4 Virtual Floppy Drive for Windows
5 Driver control program (console version)
7 Copyright (C) 2003-2008 Ken Kato
11 #pragma message(__FILE__": Compiled as C++ for testing purpose.")
14 #define WIN32_LEAN_AND_MEAN
15 #define _CRTDBG_MAP_ALLOC
22 #ifndef INVALID_FILE_ATTRIBUTES
23 #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
24 #endif // INVALID_FILE_ATTRIBUTES
32 // current driver state
34 static DWORD driver_state
= VFD_NOT_INSTALLED
;
39 static const char *help_progname
= "VFD.EXE ";
42 // command functions return value
50 #define OPERATION_ASK 0 // ask user on error
51 #define OPERATION_QUIT 1 // quits on error
52 #define OPERATION_FORCE 2 // force on error
55 // invalid target number
57 #define TARGET_NONE (ULONG)-1
60 // command processing functions
62 typedef int (*cmdfnc
)(const char **args
);
64 static int Install(const char **args
);
65 static int Remove(const char **args
);
66 static int Config(const char **args
);
67 static int Start(const char **args
);
68 static int Stop(const char **args
);
69 static int Shell(const char **args
);
70 static int Open(const char **args
);
71 static int Close(const char **args
);
72 static int Save(const char **args
);
73 static int Protect(const char **args
);
74 static int Format(const char **args
);
75 static int Link(const char **args
);
76 static int Unlink(const char **args
);
77 static int Status(const char **args
);
78 static int Help(const char **args
);
79 static int Version(const char **args
);
85 char *cmd
; // command string
86 int max_args
; // maximum allowed number of argc
87 cmdfnc func
; // command processing function
88 DWORD hint
; // command hint message id
91 {"INSTALL", 2, Install
, MSG_HINT_INSTALL
},
92 {"REMOVE", 1, Remove
, MSG_HINT_REMOVE
},
93 {"CONFIG", 1, Config
, MSG_HINT_CONFIG
},
94 {"START", 0, Start
, MSG_HINT_START
},
95 {"STOP", 1, Stop
, MSG_HINT_STOP
},
96 {"SHELL", 1, Shell
, MSG_HINT_SHELL
},
97 {"OPEN", 6, Open
, MSG_HINT_OPEN
},
98 {"CLOSE", 2, Close
, MSG_HINT_CLOSE
},
99 {"SAVE", 3, Save
, MSG_HINT_SAVE
, },
100 {"PROTECT", 2, Protect
, MSG_HINT_PROTECT
},
101 {"FORMAT", 2, Format
, MSG_HINT_FORMAT
},
102 {"LINK", 3, Link
, MSG_HINT_LINK
},
103 {"ULINK", 1, Unlink
, MSG_HINT_ULINK
},
104 {"STATUS", 0, Status
, MSG_HINT_STATUS
},
105 {"HELP", 1, Help
, MSG_HELP_HELP
},
106 {"?", 1, Help
, MSG_HELP_HELP
},
107 {"VERSION", 0, Version
, MSG_HINT_VERSION
},
112 // Help message table
114 static const struct {
115 char *keyword
; // help keyword
116 DWORD help
; // help message id
119 {"GENERAL", MSG_HELP_GENERAL
},
120 {"CONSOLE", MSG_HELP_CONSOLE
},
121 {"INSTALL", MSG_HELP_INSTALL
},
122 {"REMOVE", MSG_HELP_REMOVE
},
123 {"CONFIG", MSG_HELP_CONFIG
},
124 {"START", MSG_HELP_START
},
125 {"STOP", MSG_HELP_STOP
},
126 {"SHELL", MSG_HELP_SHELL
},
127 {"OPEN", MSG_HELP_OPEN
},
128 {"CLOSE", MSG_HELP_CLOSE
},
129 {"SAVE", MSG_HELP_SAVE
},
130 {"PROTECT", MSG_HELP_PROTECT
},
131 {"FORMAT", MSG_HELP_FORMAT
},
132 {"LINK", MSG_HELP_LINK
},
133 {"ULINK", MSG_HELP_ULINK
},
134 {"STATUS", MSG_HELP_STATUS
},
135 {"HELP", MSG_HELP_HELP
},
136 {"VERSION", MSG_HINT_VERSION
},
143 static int InteractiveConsole();
144 static int ProcessCommandLine(int argc
, const char **args
);
145 static int ParseCommand(const char *cmd
);
146 static int ParseHelpTopic(const char *topic
);
147 static int CheckDriver();
148 static int InputChar(ULONG msg
, PCSTR ans
);
149 static void PrintImageInfo(HANDLE hDevice
);
150 static void PrintDriveLetter(HANDLE hDevice
, ULONG nDrive
);
151 static void PrintMessage(UINT msg
, ...);
152 static BOOL
ConsolePager(char *pBuffer
, BOOL bReset
);
153 static const char *SystemError(DWORD err
);
154 static void ConvertPathCase(char *src
, char *dst
);
159 #define IS_WINDOWS_NT() ((GetVersion() & 0xff) < 5)
164 int main(int argc
, const char **argv
)
168 // output vfd.exe command reference text
170 if (*(argv
+ 1) && !_stricmp(*(argv
+ 1), "doc")) {
174 printf("\r\n VFD.EXE Command Reference\r\n");
176 while (HelpMsg
[idx
].keyword
) {
177 int len
= strlen(HelpMsg
[idx
].keyword
);
181 "====================\r\n"
183 "====================\r\n"
185 (20 + len
) / 2, HelpMsg
[idx
].keyword
);
188 FORMAT_MESSAGE_FROM_HMODULE
|
189 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
190 FORMAT_MESSAGE_ARGUMENT_ARRAY
,
191 NULL
, HelpMsg
[idx
].help
, 0,
192 (LPTSTR
)&buf
, 0, (va_list *)&help_progname
);
205 // Reports memory leaks at process termination
207 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG
) | _CRTDBG_LEAK_CHECK_DF
);
209 // Check the operating system version
211 if (!VfdIsValidPlatform()) {
212 PrintMessage(MSG_WRONG_PLATFORM
);
217 // If no parameter is given, enter the interactive mode
219 return InteractiveConsole();
222 // Perform a single operation
224 return ProcessCommandLine(argc
- 1, argv
+ 1);
229 // VFD interactive console
231 int InteractiveConsole()
233 char input
[1024]; // user input buffer
235 int argc
; // number of args in the user input
236 char *args
[10]; // args to pass to command functions
238 char sepa
; // argument separator
239 char *p
; // work pointer
241 // Disable the system default Ctrl+C handler
243 SetConsoleCtrlHandler(NULL
, TRUE
);
245 // Set the console title
247 SetConsoleTitle(VFD_PRODUCT_DESC
);
249 // print version information and the console hint text
253 PrintMessage(MSG_CONSOLE_HINT
);
255 // set interactive flag to exclude "VFD.EXE" from help text
259 // process user input
271 p
= fgets(input
, sizeof(input
), stdin
);
275 // most likely <ctrl+c>
281 // skip leading blank characters
283 while (*p
== ' ' || *p
== '\t' || *p
== '\n') {
294 // handle external commands
296 if (!_strnicmp(p
, "dir", 3) ||
297 !_strnicmp(p
, "attrib", 6)) {
299 // special cases - frequently used commands
300 // pass these to system() even without '.'
306 else if (*p
== '.') {
315 // split the input line into parameters (10 parameters max)
318 ZeroMemory(args
, sizeof(args
));
321 // top of a parameter
325 // is the parameter quoted?
327 if (*p
== '\"' || *p
== '\'') {
334 // search the end of the parameter
336 while (*p
&& *p
!= '\n') {
338 if (*p
== '\t' || *p
== ' ') {
339 break; // tail of a non-quoted parameter
344 sepa
= ' '; // close quote
350 // terminate the parameter
356 // skip trailing blank characters
358 while (*p
== ' ' || *p
== '\t' || *p
== '\n') {
364 // end of the input line - no more args
369 while (argc
< sizeof(args
) / sizeof(args
[0]));
371 // check the first parameter for special commands
373 if (!_stricmp(args
[0], "exit") ||
374 !_stricmp(args
[0], "quit") ||
375 !_stricmp(args
[0], "bye")) {
381 else if (!_stricmp(args
[0], "cd") ||
382 !_stricmp(args
[0], "chdir")) {
384 // internal change directory command
390 // ignore the /d option (of the standard cd command)
392 if (_stricmp(args
[1], "/d")) {
401 if (*p
== '\"' || *p
== '\'') {
403 // the parameter is quoted -- remove quotations
407 while (*p
&& *p
!= *args
[i
]) {
411 args
[i
]++; // skip a leading quote
412 *p
= '\0'; // remove a trailing quote
416 // the parameter is not quoted
417 // -- concatenate params to allow spaces in unquoted path
419 while (i
< argc
- 1) {
420 *(args
[i
] + strlen(args
[i
])) = ' ';
425 // Match the case of the path to the name on the disk
427 ConvertPathCase(p
, path
);
429 if (!SetCurrentDirectory(path
)) {
430 DWORD ret
= GetLastError();
432 if (ret
== ERROR_FILE_NOT_FOUND
) {
433 ret
= ERROR_PATH_NOT_FOUND
;
436 printf("%s", SystemError(ret
));
440 if (!GetCurrentDirectory(sizeof(input
), input
)) {
441 printf("%s", SystemError(GetLastError()));
444 printf("%s\n", input
);
448 else if (isalpha(*args
[0]) &&
449 *(args
[0] + 1) == ':' &&
450 *(args
[0] + 2) == '\0') {
452 // internal change drive command
454 *args
[0] = (char)toupper(*args
[0]);
455 *(args
[0] + 2) = '\\';
456 *(args
[0] + 3) = '\0';
458 if (!SetCurrentDirectory(args
[0])) {
459 printf("%s", SystemError(GetLastError()));
464 // perform the requested VFD command
466 ProcessCommandLine(argc
, (const char **)args
);
476 // process a single command
478 int ProcessCommandLine(int argc
, const char **args
)
484 // Decide a command to perform
486 cmd
= ParseCommand(*args
);
490 // no matching command
496 (!strcmp(*args
, "/?") ||
497 !_stricmp(*args
, "/h"))) {
499 // print a short hint for the command
501 PrintMessage(Commands
[cmd
].hint
);
505 if (--argc
> Commands
[cmd
].max_args
) {
507 // too many parameters for the command
509 PrintMessage(MSG_TOO_MANY_ARGS
);
510 PrintMessage(Commands
[cmd
].hint
);
514 // Get the current driver state
516 ret
= VfdGetDriverState(&driver_state
);
518 if (ret
!= ERROR_SUCCESS
) {
519 PrintMessage(MSG_GET_STAT_NG
);
520 printf("%s", SystemError(ret
));
524 // Perform the requested operation
526 return (*Commands
[cmd
].func
)(args
);
530 // Install the Virtual Floppy Driver
531 // Command Line Parameters:
532 // (optional) driver file path - default to executive's dir
533 // (optional) auto start switch - default to demand start
535 int Install(const char **args
)
537 const char *install_path
= NULL
;
538 DWORD start_type
= SERVICE_DEMAND_START
;
542 // process parameters
544 while (args
&& *args
) {
546 if (!_stricmp(*args
, "/a") ||
547 !_stricmp(*args
, "/auto")) {
549 if (start_type
!= SERVICE_DEMAND_START
) {
550 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
554 if (IS_WINDOWS_NT()) {
556 // On Windows NT, SYSTEM start drivers must be placed
557 // under the winnt\system32 directory. Since I don't
558 // care to handle driver file copying, I use the AUTO
559 // start method for Windows NT.
561 start_type = SERVICE_AUTO_START;
565 // On Windows XP, the VFD driver must be running when
566 // the shell starts -- otherwise the shell doesn't
567 // recognize the VFD drives. Since Windows XP allows
568 // SYSTEM start drivers to be placed in any local
569 // directories, I use the SYSTEM start method here.
571 // This is not an issue when the driver is started
572 // manually because in that case VFD.EXE and VFDWIN.EXE
573 // notify the shell of the VFD drives.
575 // On Windows 2000 both SYSTEM and AUTO work fine.
577 start_type = SERVICE_SYSTEM_START;
580 // On second thought -- Win2K / XP mount manager assigns
581 // arbitrary drive letters to all drives it finds during
582 // the system start up. There is no way to prevent it
583 // until the driver is fully PnP compatible, so I'd settle
584 // for AUTO start for the time being.
586 start_type
= SERVICE_AUTO_START
;
588 else if (**args
== '/') {
589 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
590 PrintMessage(MSG_HINT_INSTALL
, help_progname
);
595 PrintMessage(MSG_DUPLICATE_ARGS
, "path");
599 install_path
= *args
;
605 // already installed?
607 if (driver_state
!= VFD_NOT_INSTALLED
) {
608 PrintMessage(MSG_DRIVER_EXISTS
);
612 // install the driver
614 ret
= VfdInstallDriver(
618 if (ret
!= ERROR_SUCCESS
) {
619 PrintMessage(MSG_INSTALL_NG
);
620 printf("%s", SystemError(ret
));
624 // Get the latest driver state
626 ret
= VfdGetDriverState(&driver_state
);
628 if (ret
!= ERROR_SUCCESS
) {
629 PrintMessage(MSG_GET_STAT_NG
);
630 printf("%s", SystemError(ret
));
634 // operation successfull
636 PrintMessage(MSG_INSTALL_OK
);
642 // Remove Virtual Floppy Driver from system
643 // Command Line Parameters:
644 // [/F | /FORCE | /Q | /QUIT]
645 // /F forces remove operation if the driver cannot be stopped
646 // /Q quits remove operation if the driver cannot be stopped
648 int Remove(const char **args
)
650 int mode
= OPERATION_ASK
;
651 const char *stop_params
[] = { NULL
, NULL
};
657 while (args
&& *args
) {
659 if (!_stricmp(*args
, "/f") ||
660 !_stricmp(*args
, "/force")) {
662 if (mode
!= OPERATION_ASK
) {
663 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
667 mode
= OPERATION_FORCE
;
668 stop_params
[0] = *args
;
670 else if (!_stricmp(*args
, "/q") ||
671 !_stricmp(*args
, "/quit")) {
673 if (mode
!= OPERATION_ASK
) {
674 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
678 mode
= OPERATION_QUIT
;
679 stop_params
[0] = *args
;
682 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
683 PrintMessage(MSG_HINT_REMOVE
, help_progname
);
690 // ensure the driver is installed
692 if (driver_state
== VFD_NOT_INSTALLED
) {
693 PrintMessage(MSG_NOT_INSTALLED
);
697 // ensure the driver is stopped
699 if (driver_state
== SERVICE_RUNNING
) {
701 // Try to stop with the same command line option (/F or /Q)
703 while (Stop(stop_params
) != VFD_OK
) {
707 if (mode
== OPERATION_FORCE
) {
708 PrintMessage(MSG_REMOVE_FORCE
);
711 else if (mode
== OPERATION_QUIT
) {
712 PrintMessage(MSG_REMOVE_QUIT
);
718 PrintMessage(MSG_REMOVE_WARN
);
720 c
= InputChar(MSG_RETRY_FORCE_CANCEL
, "rfc");
722 if (c
== 'f') { // force
725 else if (c
== 'c') { // cancel
734 ret
= VfdRemoveDriver();
736 if (ret
!= ERROR_SUCCESS
) {
737 PrintMessage(MSG_REMOVE_NG
);
738 printf("%s", SystemError(ret
));
742 // Wait for the driver to be actually removed for 3 secs Max.
744 for (idx
= 0; idx
< 10; idx
++) {
746 ret
= VfdGetDriverState(&driver_state
);
748 if (ret
!= ERROR_SUCCESS
) {
749 PrintMessage(MSG_GET_STAT_NG
);
750 printf("%s", SystemError(ret
));
754 if (driver_state
== VFD_NOT_INSTALLED
) {
761 if (driver_state
!= VFD_NOT_INSTALLED
) {
762 PrintMessage(MSG_REMOVE_PENDING
);
766 // operation successful
768 PrintMessage(MSG_REMOVE_OK
);
774 // Configure the Virtual Floppy Driver
775 // Command Line Parameters:
778 int Config(const char **args
)
780 DWORD start_type
= SERVICE_DISABLED
;
783 while (args
&& *args
) {
784 if (!_stricmp(*args
, "/a") ||
785 !_stricmp(*args
, "/auto")) {
787 if (start_type
!= SERVICE_DISABLED
) {
788 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
792 start_type
= SERVICE_AUTO_START
;
794 else if (!_stricmp(*args
, "/m") ||
795 !_stricmp(*args
, "/manual")) {
797 if (start_type
!= SERVICE_DISABLED
) {
798 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
802 start_type
= SERVICE_DEMAND_START
;
805 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
806 PrintMessage(MSG_HINT_CONFIG
, help_progname
);
813 if (start_type
== SERVICE_DISABLED
) {
814 // no parameter is specified
815 PrintMessage(MSG_HINT_CONFIG
, help_progname
);
819 // ensure that the driver is installed
821 if (driver_state
== VFD_NOT_INSTALLED
) {
822 PrintMessage(MSG_NOT_INSTALLED
);
826 // ensure that the driver is up to date
828 if (CheckDriver() != VFD_OK
) {
832 // configure the driver
834 ret
= VfdConfigDriver(start_type
);
836 if (ret
!= ERROR_SUCCESS
) {
837 PrintMessage(MSG_CONFIG_NG
);
838 printf("%s", SystemError(ret
));
842 // operation successfull
844 PrintMessage(MSG_CONFIG_OK
);
850 // Start the Virtual Floppy Driver
851 // Command Line Parameters: None
853 int Start(const char **args
)
857 UNREFERENCED_PARAMETER(args
);
859 // ensure that the driver is installed
861 if (driver_state
== VFD_NOT_INSTALLED
&&
862 Install(NULL
) != VFD_OK
) {
866 // ensure that the driver is up to date
868 if (CheckDriver() != VFD_OK
) {
872 // ensure that the driver is not running
874 if (driver_state
== SERVICE_RUNNING
) {
875 PrintMessage(MSG_ALREADY_RUNNING
);
881 ret
= VfdStartDriver(&driver_state
);
883 if (ret
!= ERROR_SUCCESS
) {
884 PrintMessage(MSG_START_NG
);
885 printf("%s", SystemError(ret
));
889 // operation successfull
891 PrintMessage(MSG_START_OK
);
897 // Stop the Virtual Floppy Driver
898 // Command Line Parameters:
899 // /FORCE | /F Forces the operation on error
900 // /QUIT | /Q Quits the operation on error
902 int Stop(const char **args
)
904 int mode
= OPERATION_ASK
;
905 const char *close_params
[] = { "*", NULL
, NULL
};
908 while (args
&& *args
) {
909 if (!_stricmp(*args
, "/f") ||
910 !_stricmp(*args
, "/force")) {
912 if (mode
!= OPERATION_ASK
) {
913 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
917 mode
= OPERATION_FORCE
;
919 // parameter to pass to the Close() function
920 close_params
[1] = *args
;
922 else if (!_stricmp(*args
, "/q") ||
923 !_stricmp(*args
, "/quit")) {
925 if (mode
!= OPERATION_ASK
) {
926 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
930 mode
= OPERATION_QUIT
;
932 // parameter to pass to the Close() function
933 close_params
[1] = *args
;
936 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
937 PrintMessage(MSG_HINT_STOP
, help_progname
);
944 // ensure that the driver is installed
946 if (driver_state
== VFD_NOT_INSTALLED
) {
947 PrintMessage(MSG_NOT_INSTALLED
);
951 // ensure that the driver is running
953 if (driver_state
== SERVICE_STOPPED
) {
954 PrintMessage(MSG_NOT_STARTED
);
958 // ensure that all drives are empty
960 if (driver_state
== SERVICE_RUNNING
) {
962 // Try to close drives with the same operation mode (/F or /Q)
964 while (Close(close_params
) != VFD_OK
) {
968 if (mode
== OPERATION_FORCE
) {
969 PrintMessage(MSG_STOP_FORCE
);
972 else if (mode
== OPERATION_QUIT
) {
973 PrintMessage(MSG_STOP_QUIT
);
979 PrintMessage(MSG_STOP_WARN
);
981 c
= InputChar(MSG_RETRY_FORCE_CANCEL
, "rfc");
983 if (c
== 'f') { // force
986 else if (c
== 'c') { // cancel
995 ret
= VfdStopDriver(&driver_state
);
997 if (ret
!= ERROR_SUCCESS
) {
998 PrintMessage(MSG_STOP_NG
);
999 printf("%s", SystemError(ret
));
1003 if (driver_state
!= SERVICE_STOPPED
) {
1004 PrintMessage(MSG_STOP_PENDING
);
1008 // operation successful
1010 PrintMessage(MSG_STOP_OK
);
1016 // Enable / Disable the shell extension
1017 // Command Line Parameters:
1018 // (optional) /ON or /OFF
1020 int Shell(const char **args
)
1024 ret
= VfdCheckHandlers();
1026 if (ret
!= ERROR_SUCCESS
&&
1027 ret
!= ERROR_PATH_NOT_FOUND
&&
1028 ret
!= ERROR_FILE_NOT_FOUND
) {
1029 PrintMessage(MSG_GET_SHELLEXT_NG
);
1030 printf("%s", SystemError(ret
));
1034 if (args
&& *args
) {
1035 if (_stricmp(*args
, "/on") == 0) {
1036 if (ret
!= ERROR_SUCCESS
) {
1037 ret
= VfdRegisterHandlers();
1039 if (ret
!= ERROR_SUCCESS
) {
1040 PrintMessage(MSG_SET_SHELLEXT_NG
);
1041 printf("%s", SystemError(ret
));
1046 else if (_stricmp(*args
, "/off") == 0) {
1047 if (ret
== ERROR_SUCCESS
) {
1048 ret
= VfdUnregisterHandlers();
1050 if (ret
!= ERROR_SUCCESS
) {
1051 PrintMessage(MSG_SET_SHELLEXT_NG
);
1052 printf("%s", SystemError(ret
));
1058 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
1059 PrintMessage(MSG_HINT_SHELL
, help_progname
);
1063 ret
= VfdCheckHandlers();
1066 if (ret
== ERROR_PATH_NOT_FOUND
||
1067 ret
== ERROR_FILE_NOT_FOUND
) {
1068 PrintMessage(MSG_SHELLEXT_DISABLED
);
1070 else if (ret
== ERROR_SUCCESS
) {
1071 PrintMessage(MSG_SHELLEXT_ENABLED
);
1074 PrintMessage(MSG_GET_SHELLEXT_NG
);
1075 printf("%s", SystemError(ret
));
1083 // Open an image file to a Virtual Floppy Drive
1084 // Command Line Parameters:
1085 // [drive:] [file] [/NEW] [/RAM] [/P | /W]
1086 // [/size] [/media] [/F | /FORCE | /Q | /QUIT]
1088 int Open(const char **args
)
1090 int mode
= OPERATION_ASK
;
1091 BOOL create
= FALSE
;
1092 ULONG target
= TARGET_NONE
;
1093 PCSTR file_name
= NULL
;
1094 VFD_DISKTYPE disk_type
= VFD_DISKTYPE_FILE
;
1095 CHAR protect
= '\0';
1096 VFD_MEDIA media_type
= VFD_MEDIA_NONE
;
1097 BOOL five_inch
= FALSE
;
1098 VFD_FLAGS media_flags
= 0;
1103 // process parameters
1105 while (args
&& *args
) {
1107 if (!_stricmp(*args
, "/f") ||
1108 !_stricmp(*args
, "/force")) {
1110 if (mode
!= OPERATION_ASK
) {
1111 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1115 mode
= OPERATION_FORCE
;
1117 else if (!_stricmp(*args
, "/q") ||
1118 !_stricmp(*args
, "/quit")) {
1120 if (mode
!= OPERATION_ASK
) {
1121 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1125 mode
= OPERATION_QUIT
;
1128 else if (!_stricmp(*args
, "/new")) {
1131 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1138 // Disk type options
1140 else if (_stricmp(*args
, "/ram") == 0) {
1142 if (disk_type
!= VFD_DISKTYPE_FILE
) {
1143 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1147 disk_type
= VFD_DISKTYPE_RAM
;
1151 else if (_stricmp(*args
, "/p") == 0 ||
1152 _stricmp(*args
, "/w") == 0) {
1155 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1159 protect
= (CHAR
)toupper(*(*args
+ 1));
1162 // media size options
1164 else if (strcmp(*args
, "/160") == 0) {
1166 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1170 media_type
= VFD_MEDIA_F5_160
;
1172 else if (strcmp(*args
, "/180") == 0) {
1174 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1178 media_type
= VFD_MEDIA_F5_180
;
1180 else if (strcmp(*args
, "/320") == 0) {
1182 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1186 media_type
= VFD_MEDIA_F5_320
;
1188 else if (strcmp(*args
, "/360") == 0) {
1190 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1194 media_type
= VFD_MEDIA_F5_360
;
1196 else if (strcmp(*args
, "/640") == 0) {
1198 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1202 media_type
= VFD_MEDIA_F3_640
;
1204 else if (strcmp(*args
, "/720") == 0) {
1206 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1210 media_type
= VFD_MEDIA_F3_720
;
1212 else if (strcmp(*args
, "/820") == 0) {
1214 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1218 media_type
= VFD_MEDIA_F3_820
;
1220 else if (strcmp(*args
, "/120") == 0 ||
1221 strcmp(*args
, "/1.20") == 0) {
1223 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1227 media_type
= VFD_MEDIA_F3_1P2
;
1229 else if (strcmp(*args
, "/144") == 0 ||
1230 strcmp(*args
, "/1.44") == 0) {
1232 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1236 media_type
= VFD_MEDIA_F3_1P4
;
1238 else if (strcmp(*args
, "/168") == 0 ||
1239 strcmp(*args
, "/1.68") == 0) {
1241 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1245 media_type
= VFD_MEDIA_F3_1P6
;
1247 else if (strcmp(*args
, "/172") == 0 ||
1248 strcmp(*args
, "/1.72") == 0) {
1250 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1254 media_type
= VFD_MEDIA_F3_1P7
;
1256 else if (strcmp(*args
, "/288") == 0 ||
1257 strcmp(*args
, "/2.88") == 0) {
1259 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1263 media_type
= VFD_MEDIA_F3_2P8
;
1268 else if (strcmp(*args
, "/5") == 0 ||
1269 strcmp(*args
, "/525") == 0 ||
1270 strcmp(*args
, "/5.25") == 0) {
1273 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1282 else if (isalnum(**args
) &&
1283 *(*args
+ 1) == ':' &&
1284 *(*args
+ 2) == '\0') {
1286 if (target
!= TARGET_NONE
) {
1287 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1291 target
= toupper(**args
);
1296 else if (**args
!= '/') {
1298 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1305 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
1306 PrintMessage(MSG_HINT_OPEN
, help_progname
);
1313 if (target
== TARGET_NONE
) {
1316 PrintMessage(MSG_TARGET_NOTICE
, target
);
1319 // check target file
1323 VFD_FILETYPE file_type
;
1325 BOOL overwrite
= FALSE
;
1327 ret
= VfdCheckImageFile(
1328 file_name
, &file_attr
, &file_type
, &image_size
);
1330 if (ret
== ERROR_FILE_NOT_FOUND
) {
1332 // the target file does not exist
1334 if (!create
) { // create option not specified
1336 if (mode
== OPERATION_FORCE
) {
1337 PrintMessage(MSG_CREATE_NOTICE
);
1340 printf("%s", SystemError(ret
));
1342 if (mode
== OPERATION_QUIT
||
1343 InputChar(MSG_CREATE_CONFIRM
, "yn") == 'n') {
1351 else if (ret
== ERROR_SUCCESS
) {
1353 // the target file exists
1355 if (create
) { // create option is specified
1357 if (mode
== OPERATION_FORCE
) {
1358 PrintMessage(MSG_OVERWRITE_NOTICE
);
1361 printf("%s", SystemError(ERROR_FILE_EXISTS
));
1363 if (mode
== OPERATION_QUIT
||
1364 InputChar(MSG_OVERWRITE_CONFIRM
, "yn") == 'n') {
1373 PrintMessage(MSG_OPEN_NG
, file_name
);
1374 printf("%s", SystemError(ret
));
1379 // create or overwrite the target file
1384 if (media_type
== VFD_MEDIA_NONE
) {
1386 if (mode
== OPERATION_FORCE
) {
1387 PrintMessage(MSG_CREATE144_NOTICE
);
1390 PrintMessage(MSG_FILE_MEDIA_UNKNOWN
);
1392 if (mode
== OPERATION_QUIT
||
1393 InputChar(MSG_CREATE144_CONFIRM
, "yn") == 'n') {
1398 media_type
= VFD_MEDIA_F3_1P4
;
1401 ret
= VfdCreateImageFile(
1402 file_name
, media_type
, VFD_FILETYPE_RAW
, overwrite
);
1404 if (ret
!= ERROR_SUCCESS
) {
1405 PrintMessage(MSG_CREATE_NG
, file_name
);
1406 printf("%s", SystemError(ret
));
1410 PrintMessage(MSG_FILE_CREATED
);
1412 ret
= VfdCheckImageFile(
1413 file_name
, &file_attr
, &file_type
, &image_size
);
1415 if (ret
!= ERROR_SUCCESS
) {
1416 PrintMessage(MSG_OPEN_NG
, file_name
);
1417 printf("%s", SystemError(ret
));
1423 // use the existing target file
1424 // check image size and the media type
1427 VFD_MEDIA def_media
; // default media for image size
1428 ULONG media_size
; // specified media size
1430 media_size
= VfdGetMediaSize(media_type
);
1432 if (media_size
> image_size
) {
1434 // specified media is too large for the image
1436 PrintMessage(MSG_IMAGE_TOO_SMALL
);
1440 def_media
= VfdLookupMedia(image_size
);
1442 if (def_media
== VFD_MEDIA_NONE
) {
1444 // image is too small for the smallest media
1446 PrintMessage(MSG_IMAGE_TOO_SMALL
);
1450 if (media_type
== VFD_MEDIA_NONE
) {
1452 // media type is not specified
1454 ULONG def_size
= VfdGetMediaSize(def_media
);
1456 if (def_size
!= image_size
) {
1458 // image size does not match the largest media size
1460 PrintMessage(MSG_NO_MATCHING_MEDIA
, image_size
);
1462 if (mode
== OPERATION_FORCE
) {
1463 PrintMessage(MSG_MEDIATYPE_NOTICE
,
1464 VfdMediaTypeName(def_media
), def_size
);
1466 else if (mode
== OPERATION_QUIT
) {
1470 PrintMessage(MSG_MEDIATYPE_SUGGEST
,
1471 VfdMediaTypeName(def_media
), def_size
);
1473 if (InputChar(MSG_MEDIATYPE_CONFIRM
, "yn") == 'n') {
1479 media_type
= def_media
;
1483 // check file attributes against the disk type
1485 if (file_type
== VFD_FILETYPE_ZIP
||
1486 (file_attr
& (FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_COMPRESSED
| FILE_ATTRIBUTE_ENCRYPTED
))) {
1488 if (disk_type
!= VFD_DISKTYPE_RAM
) {
1490 if (mode
== OPERATION_FORCE
) {
1491 PrintMessage(MSG_RAM_MODE_NOTICE
);
1494 PrintMessage(MSG_RAM_MODE_ONLY
);
1496 if (mode
== OPERATION_QUIT
||
1497 InputChar(MSG_RAM_MODE_CONFIRM
, "yn") == 'n') {
1502 disk_type
= VFD_DISKTYPE_RAM
;
1506 if (disk_type
!= VFD_DISKTYPE_FILE
) {
1508 PrintMessage(MSG_DEFAULT_PROTECT
);
1517 disk_type
= VFD_DISKTYPE_RAM
;
1519 if (media_type
== VFD_MEDIA_NONE
) {
1521 if (mode
== OPERATION_FORCE
) {
1522 PrintMessage(MSG_CREATE144_NOTICE
);
1525 PrintMessage(MSG_RAM_MEDIA_UNKNOWN
);
1527 if (mode
== OPERATION_QUIT
||
1528 InputChar(MSG_CREATE144_CONFIRM
, "yn") == 'n') {
1533 media_type
= VFD_MEDIA_F3_1P4
;
1537 if (protect
== 'P') {
1538 media_flags
|= VFD_FLAG_WRITE_PROTECTED
;
1542 VfdGetMediaSize(media_type
) ==
1543 VfdGetMediaSize((VFD_MEDIA
)(media_type
+ 1))) {
1544 media_type
= (VFD_MEDIA
)(media_type
+ 1);
1547 // ensure that the driver is installed
1549 if (driver_state
== VFD_NOT_INSTALLED
&&
1550 Install(NULL
) != VFD_OK
) {
1554 // ensure that the driver is up to date
1556 if (CheckDriver() != VFD_OK
) {
1560 // ensure that the driver is running
1562 if (driver_state
!= SERVICE_RUNNING
&&
1563 Start(NULL
) != VFD_OK
) {
1567 // Open the target device
1569 hDevice
= VfdOpenDevice(target
);
1571 if (hDevice
== INVALID_HANDLE_VALUE
) {
1572 ret
= GetLastError();
1573 PrintMessage(MSG_ACCESS_NG
, target
);
1574 printf("%s", SystemError(ret
));
1578 // Ensure that the drive is empty
1580 ret
= VfdGetMediaState(hDevice
);
1582 if (ret
!= ERROR_NOT_READY
) {
1583 if (ret
== ERROR_SUCCESS
||
1584 ret
== ERROR_WRITE_PROTECT
) {
1585 PrintMessage(MSG_DRIVE_BUSY
);
1588 PrintMessage(MSG_GET_MEDIA_NG
);
1589 printf("%s", SystemError(ret
));
1592 CloseHandle(hDevice
);
1596 // Open the image file
1598 ret
= VfdOpenImage(hDevice
, file_name
,
1599 disk_type
, media_type
, media_flags
);
1601 if (ret
!= ERROR_SUCCESS
) {
1602 PrintMessage(MSG_OPEN_NG
, file_name
? file_name
: "<RAM>");
1603 printf("%s", SystemError(ret
));
1605 CloseHandle(hDevice
);
1609 // assign a drive letter if the drive has none
1611 VfdGetGlobalLink(hDevice
, &letter
);
1613 if (!isalpha(letter
)) {
1614 VfdGetLocalLink(hDevice
, &letter
);
1617 if (!isalpha(letter
)) {
1618 VfdSetLocalLink(hDevice
, VfdChooseLetter());
1621 // Get the actually opened image information.
1623 PrintImageInfo(hDevice
);
1625 CloseHandle(hDevice
);
1631 // Close the current virtual floppy image
1632 // Command Line Parameters:
1633 // drive number or drive letter
1634 // /F | /FORCE | /Q | /QUIT
1636 int Close(const char **args
)
1638 ULONG mode
= OPERATION_ASK
;
1640 ULONG target_min
= TARGET_NONE
;
1641 ULONG target_max
= TARGET_NONE
;
1644 VFD_MEDIA media_type
;
1645 VFD_FLAGS media_flags
;
1651 while (args
&& *args
) {
1653 if (!_stricmp(*args
, "/f") ||
1654 !_stricmp(*args
, "/force")) {
1656 if (mode
!= OPERATION_ASK
) {
1657 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1661 mode
= OPERATION_FORCE
;
1663 else if (!_stricmp(*args
, "/q") ||
1664 !_stricmp(*args
, "/quit")) {
1666 if (mode
!= OPERATION_ASK
) {
1667 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1671 mode
= OPERATION_QUIT
;
1673 else if ((isalnum(**args
) || **args
== '*') &&
1674 (*(*args
+ 1) == ':' || *(*args
+ 1) == '\0')) {
1676 if (target_min
!= TARGET_NONE
) {
1677 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1681 if (**args
== '*') {
1683 target_max
= '0' + VFD_MAXIMUM_DEVICES
;
1686 target_min
= toupper(**args
);
1687 target_max
= target_min
+ 1;
1691 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
1692 PrintMessage(MSG_HINT_CLOSE
, help_progname
);
1699 if (target_min
== TARGET_NONE
) {
1700 // default target = drive 0
1703 PrintMessage(MSG_TARGET_NOTICE
, target_min
);
1706 // ensure that the driver is installed
1708 if (driver_state
== VFD_NOT_INSTALLED
) {
1709 PrintMessage(MSG_NOT_INSTALLED
);
1713 // ensure that the driver is running
1715 if (driver_state
!= SERVICE_RUNNING
) {
1716 PrintMessage(MSG_NOT_STARTED
);
1720 // Close the drive(s)
1722 while (target_min
< target_max
) {
1724 // open the target device
1726 hDevice
= VfdOpenDevice(target_min
);
1728 if (hDevice
== INVALID_HANDLE_VALUE
) {
1729 ret
= GetLastError();
1731 PrintMessage(MSG_ACCESS_NG
, target_min
);
1732 printf("%s", SystemError(ret
));
1734 if (mode
!= OPERATION_FORCE
) {
1742 // get the current image information
1744 ret
= VfdGetImageInfo(hDevice
, NULL
, NULL
,
1745 &media_type
, &media_flags
, NULL
, NULL
);
1747 if (ret
!= ERROR_SUCCESS
) {
1748 PrintMessage(MSG_ACCESS_NG
, target_min
);
1749 printf("%s", SystemError(ret
));
1751 CloseHandle(hDevice
);
1753 if (mode
!= OPERATION_FORCE
) {
1761 if (media_type
== VFD_MEDIA_NONE
) {
1765 CloseHandle(hDevice
);
1770 if (media_flags
& VFD_FLAG_DATA_MODIFIED
) {
1772 // RAM disk data is modified
1774 PrintMessage(MSG_MEDIA_MODIFIED
, target_min
);
1776 if (mode
== OPERATION_FORCE
) {
1777 PrintMessage(MSG_CLOSE_FORCE
);
1779 else if (mode
== OPERATION_QUIT
) {
1780 PrintMessage(MSG_CLOSE_QUIT
);
1781 CloseHandle(hDevice
);
1785 if (InputChar(MSG_CLOSE_CONFIRM
, "yn") == 'n') {
1786 CloseHandle(hDevice
);
1793 ret
= VfdCloseImage(
1794 hDevice
, (mode
== OPERATION_FORCE
));
1796 if (ret
== ERROR_ACCESS_DENIED
) {
1798 PrintMessage(MSG_LOCK_NG
, target_min
);
1800 if (mode
== OPERATION_QUIT
) {
1801 CloseHandle(hDevice
);
1804 else if (mode
== OPERATION_ASK
) {
1808 if (IS_WINDOWS_NT()) {
1809 c
= InputChar(MSG_RETRY_CANCEL
, "rc");
1812 c
= InputChar(MSG_RETRY_FORCE_CANCEL
, "rfc");
1815 if (c
== 'f') { // force
1816 ret
= VfdCloseImage(hDevice
, TRUE
);
1818 else if (c
== 'c') { // cancel
1819 CloseHandle(hDevice
);
1828 CloseHandle(hDevice
);
1830 if (ret
== ERROR_SUCCESS
) {
1831 PrintMessage(MSG_CLOSE_OK
, target_min
);
1833 else if (ret
!= ERROR_NOT_READY
) {
1834 PrintMessage(MSG_CLOSE_NG
, target_min
);
1835 printf("%s", SystemError(ret
));
1837 if (mode
!= OPERATION_FORCE
) {
1849 // Save the current image into a file
1851 int Save(const char **args
)
1853 int mode
= OPERATION_ASK
;
1854 ULONG target
= TARGET_NONE
;
1855 CHAR file_name
[MAX_PATH
] = {0};
1856 BOOL overwrite
= FALSE
;
1857 BOOL truncate
= FALSE
;
1860 CHAR current
[MAX_PATH
] = {0};
1861 VFD_MEDIA media_type
;
1862 VFD_FLAGS media_flags
;
1863 VFD_FILETYPE file_type
;
1870 while (args
&& *args
) {
1872 if (!_stricmp(*args
, "/f") ||
1873 !_stricmp(*args
, "/force")) {
1875 if (mode
!= OPERATION_ASK
) {
1876 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1880 mode
= OPERATION_FORCE
;
1882 else if (!_stricmp(*args
, "/q") ||
1883 !_stricmp(*args
, "/quit")) {
1885 if (mode
!= OPERATION_ASK
) {
1886 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1890 mode
= OPERATION_QUIT
;
1892 else if (!_stricmp(*args
, "/o") ||
1893 !_stricmp(*args
, "/over")) {
1895 if (truncate
|| overwrite
) {
1896 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1902 else if (!_stricmp(*args
, "/t") ||
1903 !_stricmp(*args
, "/trunc")) {
1905 if (truncate
|| overwrite
) {
1906 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1912 else if (isalnum(**args
) &&
1913 *(*args
+ 1) == ':' &&
1914 *(*args
+ 2) == '\0') {
1916 if (target
!= TARGET_NONE
) {
1917 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
1921 target
= toupper(**args
);
1923 else if (**args
== '/') {
1924 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
1925 PrintMessage(MSG_HINT_SAVE
, help_progname
);
1929 strcpy(file_name
, *args
);
1935 if (target
== TARGET_NONE
) {
1937 PrintMessage(MSG_TARGET_NOTICE
, target
);
1940 // ensure that the driver is installed
1942 if (driver_state
== VFD_NOT_INSTALLED
) {
1943 PrintMessage(MSG_NOT_INSTALLED
);
1947 // ensure that the driver is up to date
1949 if (CheckDriver() != VFD_OK
) {
1953 // ensure that the driver is running
1955 if (driver_state
!= SERVICE_RUNNING
) {
1956 PrintMessage(MSG_NOT_STARTED
);
1960 // Open the target device
1962 hDevice
= VfdOpenDevice(target
);
1964 if (hDevice
== INVALID_HANDLE_VALUE
) {
1965 ret
= GetLastError();
1966 PrintMessage(MSG_ACCESS_NG
, target
);
1967 printf("%s", SystemError(ret
));
1971 // Get the current image info
1973 ret
= VfdGetImageInfo(hDevice
, current
, NULL
,
1974 &media_type
, &media_flags
, NULL
, NULL
);
1976 if (ret
!= ERROR_SUCCESS
) {
1977 printf("%s", SystemError(ret
));
1978 CloseHandle(hDevice
);
1982 if (media_type
== VFD_MEDIA_NONE
) {
1983 printf("%s", SystemError(ERROR_NOT_READY
));
1984 CloseHandle(hDevice
);
1988 if (file_name
[0] == '\0') {
1990 if (current
[0] == '\0') {
1992 PrintMessage(MSG_TARGET_REQUIRED
);
1993 CloseHandle(hDevice
);
1998 strcpy(file_name
, current
);
2001 if (!_stricmp(file_name
, current
)) {
2003 // target is the current image file
2005 if (!(media_flags
& VFD_FLAG_DATA_MODIFIED
)) {
2007 // FILE disk (always up to date) or RAM disk is not modified
2009 PrintMessage(MSG_TARGET_UP_TO_DATE
);
2010 CloseHandle(hDevice
);
2018 // check target file
2020 ret
= VfdCheckImageFile(file_name
,
2021 &file_attr
, &file_type
, &image_size
);
2023 if (ret
== ERROR_SUCCESS
) {
2025 if (!overwrite
&& !truncate
) {
2027 if (mode
== OPERATION_FORCE
) {
2028 PrintMessage(MSG_OVERWRITE_NOTICE
);
2031 else if (mode
== OPERATION_QUIT
) {
2032 printf("%s", SystemError(ERROR_FILE_EXISTS
));
2033 CloseHandle(hDevice
);
2040 printf("%s", SystemError(ERROR_FILE_EXISTS
));
2042 c
= InputChar(MSG_OVERWRITE_PROMPT
, "otc");
2047 else if (c
== 't') {
2051 CloseHandle(hDevice
);
2057 else if (ret
!= ERROR_FILE_NOT_FOUND
) {
2059 printf("%s", SystemError(ret
));
2060 CloseHandle(hDevice
);
2065 if (file_type
== VFD_FILETYPE_ZIP
) {
2067 // Cannot update a zip file
2069 PrintMessage(MSG_TARGET_IS_ZIP
);
2070 CloseHandle(hDevice
);
2076 ret
= VfdDismountVolume(
2077 hDevice
, (mode
== OPERATION_FORCE
));
2079 if (ret
== ERROR_ACCESS_DENIED
) {
2081 PrintMessage(MSG_LOCK_NG
, target
);
2083 if (mode
== OPERATION_FORCE
) {
2084 PrintMessage(MSG_SAVE_FORCE
);
2086 else if (mode
== OPERATION_QUIT
) {
2087 PrintMessage(MSG_SAVE_QUIT
);
2088 CloseHandle(hDevice
);
2092 int c
= InputChar(MSG_RETRY_FORCE_CANCEL
, "rfc");
2094 if (c
== 'r') { // retry
2097 else if (c
== 'f') { // force
2098 VfdDismountVolume(hDevice
, TRUE
);
2101 CloseHandle(hDevice
);
2106 else if (ret
!= ERROR_SUCCESS
) {
2107 printf("%s", SystemError(ret
));
2108 CloseHandle(hDevice
);
2112 ret
= VfdSaveImage(hDevice
, file_name
,
2113 (overwrite
|| truncate
), truncate
);
2115 CloseHandle(hDevice
);
2117 if (ret
!= ERROR_SUCCESS
) {
2118 PrintMessage(MSG_SAVE_NG
, target
, file_name
);
2119 printf("%s", SystemError(ret
));
2124 PrintMessage(MSG_SAVE_OK
, target
, file_name
);
2130 // Enable/disable virtual media write protection
2132 int Protect(const char **args
)
2134 #define PROTECT_NONE 0
2135 #define PROTECT_ON 1
2136 #define PROTECT_OFF 2
2137 ULONG protect
= PROTECT_NONE
;
2138 ULONG target
= TARGET_NONE
;
2144 while (args
&& *args
) {
2146 // Disk type options
2148 if (_stricmp(*args
, "/on") == 0) {
2151 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2155 protect
= PROTECT_ON
;
2157 else if (_stricmp(*args
, "/off") == 0) {
2160 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2164 protect
= PROTECT_OFF
;
2166 else if (isalnum(**args
)) {
2168 if (target
!= TARGET_NONE
) {
2169 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2173 target
= toupper(**args
);
2176 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
2177 PrintMessage(MSG_HINT_PROTECT
, help_progname
);
2184 if (target
== TARGET_NONE
) {
2186 PrintMessage(MSG_TARGET_NOTICE
, target
);
2189 // ensure that the driver is installed
2191 if (driver_state
== VFD_NOT_INSTALLED
) {
2192 PrintMessage(MSG_NOT_INSTALLED
);
2196 // ensure that the driver is up to date
2198 if (CheckDriver() != VFD_OK
) {
2202 // ensure that the driver is running
2204 if (driver_state
!= SERVICE_RUNNING
) {
2205 PrintMessage(MSG_NOT_STARTED
);
2209 // open the target drive
2211 hDevice
= VfdOpenDevice(target
);
2213 if (hDevice
== INVALID_HANDLE_VALUE
) {
2214 ret
= GetLastError();
2215 PrintMessage(MSG_ACCESS_NG
, target
);
2216 printf("%s", SystemError(ret
));
2221 // change protect state
2223 ret
= VfdWriteProtect(
2224 hDevice
, (protect
== PROTECT_ON
));
2226 if (ret
!= ERROR_SUCCESS
) {
2227 PrintMessage(MSG_PROTECT_NG
, target
);
2228 printf("%s", SystemError(ret
));
2230 CloseHandle(hDevice
);
2235 // get the current protect state
2237 ret
= VfdGetMediaState(hDevice
);
2239 CloseHandle(hDevice
);
2241 if (ret
== ERROR_SUCCESS
) {
2242 PrintMessage(MSG_MEDIA_WRITABLE
);
2244 else if (ret
== ERROR_WRITE_PROTECT
) {
2245 PrintMessage(MSG_MEDIA_PROTECTED
);
2248 PrintMessage(MSG_GET_MEDIA_NG
);
2249 printf("%s", SystemError(ret
));
2257 // Format the virtual media with FAT12
2259 int Format(const char **args
)
2261 int mode
= OPERATION_ASK
;
2262 ULONG target
= TARGET_NONE
;
2268 while (args
&& *args
) {
2270 if (!_stricmp(*args
, "/f") ||
2271 !_stricmp(*args
, "/force")) {
2273 if (mode
!= OPERATION_ASK
) {
2274 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2278 mode
= OPERATION_FORCE
;
2280 else if (!_stricmp(*args
, "/q") ||
2281 !_stricmp(*args
, "/quit")) {
2283 if (mode
!= OPERATION_ASK
) {
2284 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2288 mode
= OPERATION_QUIT
;
2290 else if (isalnum(**args
)) {
2291 if (target
!= TARGET_NONE
) {
2292 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2296 target
= toupper(**args
);
2299 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
2300 PrintMessage(MSG_HINT_FORMAT
, help_progname
);
2307 if (target
== TARGET_NONE
) {
2309 PrintMessage(MSG_TARGET_NOTICE
, target
);
2312 // ensure that the driver is installed
2314 if (driver_state
== VFD_NOT_INSTALLED
) {
2315 PrintMessage(MSG_NOT_INSTALLED
);
2319 // ensure that the driver is up to date
2321 if (CheckDriver() != VFD_OK
) {
2325 // ensure that the driver is running
2327 if (driver_state
!= SERVICE_RUNNING
) {
2328 PrintMessage(MSG_NOT_STARTED
);
2334 hDevice
= VfdOpenDevice(target
);
2336 if (hDevice
== INVALID_HANDLE_VALUE
) {
2337 ret
= GetLastError();
2338 PrintMessage(MSG_ACCESS_NG
, target
);
2339 printf("%s", SystemError(ret
));
2343 // check if the media is writable
2345 ret
= VfdGetMediaState(hDevice
);
2347 if (ret
!= ERROR_SUCCESS
) {
2348 PrintMessage(MSG_FORMAT_NG
, target
);
2349 printf("%s", SystemError(ret
));
2351 CloseHandle(hDevice
);
2358 ret
= VfdDismountVolume(
2359 hDevice
, (mode
== OPERATION_FORCE
));
2361 if (ret
== ERROR_ACCESS_DENIED
) {
2363 PrintMessage(MSG_LOCK_NG
, target
);
2365 if (mode
== OPERATION_FORCE
) {
2366 PrintMessage(MSG_FORMAT_FORCE
);
2368 else if (mode
== OPERATION_QUIT
) {
2369 PrintMessage(MSG_FORMAT_QUIT
);
2370 CloseHandle(hDevice
);
2374 int c
= InputChar(MSG_RETRY_FORCE_CANCEL
, "rfc");
2376 if (c
== 'r') { // retry
2379 else if (c
== 'f') { // force
2380 VfdDismountVolume(hDevice
, TRUE
);
2383 CloseHandle(hDevice
);
2388 else if (ret
!= ERROR_SUCCESS
) {
2389 PrintMessage(MSG_LOCK_NG
, target
);
2390 CloseHandle(hDevice
);
2394 ret
= VfdFormatMedia(hDevice
);
2396 CloseHandle(hDevice
);
2398 if (ret
!= ERROR_SUCCESS
) {
2399 PrintMessage(MSG_FORMAT_NG
, target
);
2400 printf("%s", SystemError(ret
));
2404 // successful operation
2406 PrintMessage(MSG_FORMAT_OK
);
2412 // Assign a drive letter to a Virtual Floppy Drive
2414 int Link(const char **args
)
2416 ULONG target_min
= TARGET_NONE
;
2417 ULONG target_max
= TARGET_NONE
;
2418 PCSTR letters
= NULL
;
2423 while (args
&& *args
) {
2424 if (!_stricmp(*args
, "/g")) {
2427 else if (!_stricmp(*args
, "/l")) {
2430 else if (isdigit(**args
) || **args
== '*') {
2431 if (target_min
!= TARGET_NONE
) {
2432 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2436 if (**args
== '*') {
2438 target_max
= '0' + VFD_MAXIMUM_DEVICES
;
2441 target_min
= **args
;
2442 target_max
= target_min
+ 1;
2445 else if (isalpha(**args
)) {
2447 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2453 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
2454 PrintMessage(MSG_HINT_LINK
, help_progname
);
2461 if (target_min
== TARGET_NONE
) {
2465 PrintMessage(MSG_TARGET_NOTICE
, target_min
);
2468 // ensure that the driver is installed
2470 if (driver_state
== VFD_NOT_INSTALLED
) {
2471 PrintMessage(MSG_NOT_INSTALLED
);
2475 // ensure that the driver is up to date
2477 if (CheckDriver() != VFD_OK
) {
2481 // ensure that the driver is running
2483 if (driver_state
!= SERVICE_RUNNING
) {
2484 PrintMessage(MSG_NOT_STARTED
);
2488 while (target_min
< target_max
) {
2492 hDevice
= VfdOpenDevice(target_min
);
2494 if (hDevice
== INVALID_HANDLE_VALUE
) {
2495 ret
= GetLastError();
2496 PrintMessage(MSG_ACCESS_NG
, target_min
);
2497 printf("%s", SystemError(ret
));
2502 ret
= VfdGetDeviceNumber(hDevice
, &number
);
2504 if (ret
!= ERROR_SUCCESS
) {
2505 PrintMessage(MSG_ACCESS_NG
, target_min
);
2506 printf("%s", SystemError(ret
));
2507 CloseHandle(hDevice
);
2512 if (letters
&& isalpha(*letters
)) {
2513 letter
= (CHAR
)toupper(*(letters
++));
2516 letter
= VfdChooseLetter();
2521 ret
= VfdSetGlobalLink(hDevice
, letter
);
2524 ret
= VfdSetLocalLink(hDevice
, letter
);
2527 if (ret
!= ERROR_SUCCESS
) {
2528 PrintMessage(MSG_LINK_NG
, number
, letter
);
2529 printf("%s", SystemError(ret
));
2533 PrintMessage(MSG_LINK_FULL
);
2536 PrintDriveLetter(hDevice
, number
);
2538 CloseHandle(hDevice
);
2547 // Remove a drive letter from a Virtual Floppy Drive
2549 int Unlink(const char **args
)
2551 ULONG target_min
= TARGET_NONE
;
2552 ULONG target_max
= TARGET_NONE
;
2556 while (args
&& *args
) {
2557 if ((isalnum(**args
) || **args
== '*') &&
2558 (*(*args
+ 1) == ':' || *(*args
+ 1) == '\0')) {
2560 if (target_min
!= TARGET_NONE
) {
2561 PrintMessage(MSG_DUPLICATE_ARGS
, *args
);
2565 if (**args
== '*') {
2567 target_max
= '0' + VFD_MAXIMUM_DEVICES
;
2570 target_min
= **args
;
2571 target_max
= target_min
+ 1;
2575 PrintMessage(MSG_UNKNOWN_OPTION
, *args
);
2576 PrintMessage(MSG_HINT_ULINK
, help_progname
);
2583 if (target_min
== TARGET_NONE
) {
2587 PrintMessage(MSG_TARGET_NOTICE
, target_min
);
2590 // ensure that the driver is installed
2592 if (driver_state
== VFD_NOT_INSTALLED
) {
2593 PrintMessage(MSG_NOT_INSTALLED
);
2597 // ensure that the driver is up to date
2599 if (CheckDriver() != VFD_OK
) {
2603 // ensure that the driver is running
2605 if (driver_state
!= SERVICE_RUNNING
) {
2606 PrintMessage(MSG_NOT_STARTED
);
2610 while (target_min
< target_max
) {
2613 hDevice
= VfdOpenDevice(target_min
);
2615 if (hDevice
== INVALID_HANDLE_VALUE
) {
2616 ret
= GetLastError();
2617 PrintMessage(MSG_ACCESS_NG
, target_min
);
2618 printf("%s", SystemError(ret
));
2623 ret
= VfdGetDeviceNumber(hDevice
, &number
);
2625 if (ret
!= ERROR_SUCCESS
) {
2626 PrintMessage(MSG_ACCESS_NG
, target_min
);
2627 printf("%s", SystemError(ret
));
2628 CloseHandle(hDevice
);
2633 VfdSetGlobalLink(hDevice
, 0);
2634 VfdSetLocalLink(hDevice
, 0);
2636 PrintDriveLetter(hDevice
, number
);
2638 CloseHandle(hDevice
);
2647 // Print current driver state
2648 // Command Line Parameters: None
2650 int Status(const char **args
)
2653 TCHAR path
[MAX_PATH
];
2659 UNREFERENCED_PARAMETER(args
);
2661 if (driver_state
== VFD_NOT_INSTALLED
) {
2662 PrintMessage(MSG_NOT_INSTALLED
);
2666 // get current driver config
2668 ret
= VfdGetDriverConfig(path
, &start_type
);
2670 if (ret
!= ERROR_SUCCESS
) {
2671 PrintMessage(MSG_GET_CONFIG_NG
);
2672 printf("%s", SystemError(ret
));
2676 // print driver file path
2678 PrintMessage(MSG_DRIVER_FILE
, path
);
2680 // print driver version
2683 if (driver_state
== SERVICE_RUNNING
) {
2685 hDevice
= VfdOpenDevice(0);
2687 if (hDevice
!= INVALID_HANDLE_VALUE
) {
2688 ret
= VfdGetDriverVersion(hDevice
, &version
);
2690 CloseHandle(hDevice
);
2696 ret
= VfdCheckDriverFile(path
, &version
);
2699 if (ret
== ERROR_SUCCESS
) {
2700 PrintMessage(MSG_DRIVER_VERSION
,
2701 HIWORD(version
) & 0x7fff,
2703 (version
& 0x80000000) ? "(debug)" : "");
2706 PrintMessage(MSG_GET_VERSION_NG
);
2707 printf("%s", SystemError(ret
));
2711 // print driver start type
2713 PrintMessage(MSG_START_TYPE
);
2715 switch (start_type
) {
2716 case SERVICE_AUTO_START
:
2717 PrintMessage(MSG_START_AUTO
);
2720 case SERVICE_BOOT_START
:
2721 PrintMessage(MSG_START_BOOT
);
2724 case SERVICE_DEMAND_START
:
2725 PrintMessage(MSG_START_DEMAND
);
2728 case SERVICE_DISABLED
:
2729 PrintMessage(MSG_START_DISABLED
);
2732 case SERVICE_SYSTEM_START
:
2733 PrintMessage(MSG_START_SYSTEM
);
2737 PrintMessage(MSG_UNKNOWN_LONG
, start_type
);
2741 // print current driver state
2743 PrintMessage(MSG_DRIVER_STATUS
);
2745 switch (driver_state
) {
2746 case SERVICE_STOPPED
:
2747 PrintMessage(MSG_STATUS_STOPPED
);
2750 case SERVICE_START_PENDING
:
2751 PrintMessage(MSG_STATUS_START_P
);
2754 case SERVICE_STOP_PENDING
:
2755 PrintMessage(MSG_STATUS_STOP_P
);
2758 case SERVICE_RUNNING
:
2759 PrintMessage(MSG_STATUS_RUNNING
);
2762 case SERVICE_CONTINUE_PENDING
:
2763 PrintMessage(MSG_STATUS_CONT_P
);
2766 case SERVICE_PAUSE_PENDING
:
2767 PrintMessage(MSG_STATUS_PAUSE_P
);
2770 case SERVICE_PAUSED
:
2771 PrintMessage(MSG_STATUS_PAUSED
);
2775 PrintMessage(MSG_UNKNOWN_LONG
, driver_state
);
2780 // print shell extension status
2784 if (VfdCheckHandlers() == ERROR_SUCCESS
) {
2785 PrintMessage(MSG_SHELLEXT_ENABLED
);
2788 PrintMessage(MSG_SHELLEXT_DISABLED
);
2791 // if driver is not running, no more info
2793 if (driver_state
!= SERVICE_RUNNING
) {
2797 // print image information
2799 for (target
= 0; target
< VFD_MAXIMUM_DEVICES
; target
++) {
2800 HANDLE hDevice
= VfdOpenDevice(target
);
2802 if (hDevice
== INVALID_HANDLE_VALUE
) {
2803 ret
= GetLastError();
2804 PrintMessage(MSG_ACCESS_NG
, target
+ '0');
2805 printf("%s", SystemError(ret
));
2809 PrintImageInfo(hDevice
);
2811 CloseHandle(hDevice
);
2820 int Help(const char **args
)
2822 DWORD msg
= MSG_HELP_GENERAL
;
2825 if (args
&& *args
) {
2826 int cmd
= ParseHelpTopic(*args
);
2829 msg
= MSG_HELP_HELP
;
2832 msg
= HelpMsg
[cmd
].help
;
2837 FORMAT_MESSAGE_FROM_HMODULE
|
2838 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
2839 FORMAT_MESSAGE_ARGUMENT_ARRAY
,
2840 NULL
, msg
, 0, (LPTSTR
)&buf
, 0,
2841 (va_list *)&help_progname
);
2844 printf("%s", SystemError(GetLastError()));
2848 ConsolePager(buf
, TRUE
);
2855 // Print version information
2857 int Version(const char **args
)
2859 UNREFERENCED_PARAMETER(args
);
2861 printf(VFD_PRODUCT_DESC
"\n" VFD_COPYRIGHT_STR
"\n"
2862 "http://chitchat.at.infoseek.co.jp/vmware/vfd.html\n");
2868 // Parse command parameter
2870 int ParseCommand(const char *cmd
)
2872 #define CMD_MATCH_NONE -1
2873 #define CMD_MATCH_MULTI -2
2879 // skip a leading '/'
2889 return CMD_MATCH_NONE
;
2895 match
= CMD_MATCH_NONE
;
2897 while (Commands
[idx
].cmd
) {
2899 if (strlen(Commands
[idx
].cmd
) >= len
&&
2900 !_strnicmp(cmd
, Commands
[idx
].cmd
, len
)) {
2902 if (match
== CMD_MATCH_NONE
) { // first match
2905 else { // multiple matches
2906 if (match
!= CMD_MATCH_MULTI
) { // first time
2907 PrintMessage(MSG_AMBIGUOUS_COMMAND
, cmd
);
2908 printf("> %s ", Commands
[match
].cmd
);
2909 match
= CMD_MATCH_MULTI
;
2912 printf("%s ", Commands
[idx
].cmd
);
2919 if (match
== CMD_MATCH_NONE
) { // match not found
2920 PrintMessage(MSG_UNKNOWN_COMMAND
, cmd
);
2922 else if (match
== CMD_MATCH_MULTI
) { // multiple matches
2929 int ParseHelpTopic(const char *topic
)
2935 if (*topic
== '\0') {
2939 return CMD_MATCH_NONE
;
2943 len
= strlen(topic
);
2945 match
= CMD_MATCH_NONE
;
2947 while (HelpMsg
[idx
].keyword
) {
2949 if (strlen(HelpMsg
[idx
].keyword
) >= len
&&
2950 !_strnicmp(topic
, HelpMsg
[idx
].keyword
, len
)) {
2952 if (match
== CMD_MATCH_NONE
) { // first match
2955 else { // multiple matches
2956 if (match
!= CMD_MATCH_MULTI
) { // first time
2957 PrintMessage(MSG_AMBIGUOUS_COMMAND
, topic
);
2958 printf("> %s ", HelpMsg
[match
].keyword
);
2959 match
= CMD_MATCH_MULTI
;
2962 printf("%s ", HelpMsg
[idx
].keyword
);
2969 if (match
== CMD_MATCH_NONE
) { // match not found
2970 PrintMessage(MSG_UNKNOWN_COMMAND
, topic
);
2972 else if (match
== CMD_MATCH_MULTI
) { // multiple matches
2980 // Check driver version and update if necessary
2984 char path
[MAX_PATH
];
2987 // check installed driver file version
2989 if (VfdGetDriverConfig(path
, &start
) == ERROR_SUCCESS
&&
2990 VfdCheckDriverFile(path
, NULL
) == ERROR_SUCCESS
) {
2994 if (driver_state
!= SERVICE_RUNNING
) {
2998 // check running driver version
3000 hDevice
= VfdOpenDevice(0);
3002 if (hDevice
!= INVALID_HANDLE_VALUE
) {
3003 CloseHandle(hDevice
);
3008 PrintMessage(MSG_WRONG_DRIVER
);
3013 // Print a prompt message and accept the reply input
3015 int InputChar(ULONG msg
, PCSTR ans
)
3025 hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
3027 FlushConsoleInputBuffer(hStdIn
);
3030 ReadConsoleInput(hStdIn
, &input
, sizeof(input
), &result
);
3032 if (input
.EventType
== KEY_EVENT
&&
3033 input
.Event
.KeyEvent
.bKeyDown
) {
3035 reply
= tolower(input
.Event
.KeyEvent
.uChar
.AsciiChar
);
3037 if (strchr(ans
, reply
)) {
3043 printf("%c\n", reply
);
3049 // Print image information on a Virtual Floppy Drive
3051 void PrintImageInfo(
3054 ULONG device_number
;
3055 CHAR file_name
[MAX_PATH
];
3056 CHAR file_desc
[MAX_PATH
];
3057 VFD_DISKTYPE disk_type
;
3058 VFD_MEDIA media_type
;
3059 VFD_FLAGS media_flags
;
3060 VFD_FILETYPE file_type
;
3066 // get current device number
3068 ret
= VfdGetDeviceNumber(hDevice
, &device_number
);
3070 if (ret
!= ERROR_SUCCESS
) {
3071 PrintMessage(MSG_GET_LINK_NG
);
3072 printf("%s", SystemError(ret
));
3073 device_number
= (ULONG
)-1;
3076 // get current drive letters
3078 PrintDriveLetter(hDevice
, device_number
);
3080 // image file information
3082 ret
= VfdGetImageInfo(hDevice
, file_name
, &disk_type
,
3083 &media_type
, &media_flags
, &file_type
, &image_size
);
3085 if (ret
!= ERROR_SUCCESS
) {
3086 PrintMessage(MSG_GET_FILE_NG
);
3087 printf("%s", SystemError(ret
));
3091 // print image file information
3092 if (media_type
== VFD_MEDIA_NONE
) {
3093 PrintMessage(MSG_IMAGE_NONE
);
3098 PrintMessage(MSG_IMAGE_NAME
, file_name
);
3100 VfdMakeFileDesc(file_desc
, sizeof(file_desc
),
3101 file_type
, image_size
, GetFileAttributes(file_name
));
3104 PrintMessage(MSG_IMAGE_NAME
, "<RAM>");
3106 VfdMakeFileDesc(file_desc
, sizeof(file_desc
),
3107 VFD_FILETYPE_NONE
, image_size
, 0);
3110 PrintMessage(MSG_FILE_DESC
, file_desc
);
3112 if (disk_type
== VFD_DISKTYPE_FILE
) {
3113 PrintMessage(MSG_DISKTYPE_FILE
);
3116 if (media_flags
& VFD_FLAG_DATA_MODIFIED
) {
3117 PrintMessage(MSG_DISKTYPE_RAM_DIRTY
);
3120 PrintMessage(MSG_DISKTYPE_RAM_CLEAN
);
3124 // print other file info
3126 PrintMessage(MSG_MEDIA_TYPE
, VfdMediaTypeName(media_type
));
3128 if (media_flags
& VFD_FLAG_WRITE_PROTECTED
) {
3129 PrintMessage(MSG_MEDIA_PROTECTED
);
3132 PrintMessage(MSG_MEDIA_WRITABLE
);
3137 // Print drive letters on a virtual floppy drive
3139 void PrintDriveLetter(
3145 PrintMessage(MSG_DRIVE_LETTER
, nDrive
);
3147 VfdGetGlobalLink(hDevice
, &letter
);
3149 if (isalpha(letter
)) {
3150 PrintMessage(MSG_PERSISTENT
, toupper(letter
));
3153 while (VfdGetLocalLink(hDevice
, &letter
) == ERROR_SUCCESS
&&
3155 PrintMessage(MSG_EPHEMERAL
, toupper(letter
));
3162 // Prints a text on screen a page a time
3164 BOOL
ConsolePager(char *pBuffer
, BOOL bReset
)
3166 static int rows
= 0;
3173 // prepare the console input and output handles
3175 hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
3176 hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
3179 CONSOLE_SCREEN_BUFFER_INFO info
;
3188 // Get the current console screen information
3190 GetConsoleScreenBufferInfo(hStdOut
, &info
);
3192 if (bReset
|| rows
<= 0) {
3193 rows
= info
.srWindow
.Bottom
- info
.srWindow
.Top
- 1;
3196 cols
= info
.dwSize
.X
;
3198 // console window is too small for paging
3201 // print all text and exit
3202 printf("%s", pBuffer
);
3207 // find the tail of the text to be printed this time
3213 if (*(cur
++) == '\n' || (cols
--) == 0) {
3214 // reached the end of a line
3216 // reached the end of a page
3217 // insert a terminating NULL char
3223 cols
= info
.dwSize
.X
;
3227 // print the current page
3228 printf("%s", pBuffer
);
3230 // end of the whole text?
3236 // prompt for the next page
3239 // prepare the prompt text
3241 if (prompt_len
== 0) {
3243 prompt_len
= FormatMessage(
3244 FORMAT_MESSAGE_FROM_HMODULE
|
3245 FORMAT_MESSAGE_IGNORE_INSERTS
,
3246 NULL
, MSG_PAGER_PROMPT
, 0,
3247 prompt
, sizeof(prompt
), NULL
);
3249 if (prompt_len
== 0) {
3250 strcpy(prompt
, "Press any key to continue...");
3251 prompt_len
= strlen(prompt
);
3255 // get the current console input mode
3257 GetConsoleMode(hStdIn
, &mode
);
3259 // change the mode to receive Ctrl+C as a regular input
3261 SetConsoleMode(hStdIn
, (mode
& ~ENABLE_PROCESSED_INPUT
));
3263 // get the current cursor position
3265 GetConsoleScreenBufferInfo(hStdOut
, &info
);
3267 // print the prompt text
3269 WriteConsoleOutputCharacter(hStdOut
, prompt
,
3270 prompt_len
, info
.dwCursorPosition
, &result
);
3272 // reverse the text color
3274 FillConsoleOutputAttribute(hStdOut
,
3275 (WORD
)(info
.wAttributes
| COMMON_LVB_REVERSE_VIDEO
),
3276 prompt_len
, info
.dwCursorPosition
, &result
);
3278 // move cursor to the end of the prompt text
3280 info
.dwCursorPosition
.X
=
3281 (short)(info
.dwCursorPosition
.X
+ prompt_len
);
3283 SetConsoleCursorPosition(hStdOut
, info
.dwCursorPosition
);
3285 // wait for a key press event
3287 FlushConsoleInputBuffer(hStdIn
);
3290 ReadConsoleInput(hStdIn
, &input
, sizeof(input
), &result
);
3292 while (input
.EventType
!= KEY_EVENT
||
3293 !input
.Event
.KeyEvent
.bKeyDown
||
3294 !input
.Event
.KeyEvent
.uChar
.AsciiChar
);
3296 // restore the original cursor position
3298 info
.dwCursorPosition
.X
=
3299 (short)(info
.dwCursorPosition
.X
- prompt_len
);
3301 SetConsoleCursorPosition(hStdOut
, info
.dwCursorPosition
);
3303 // delete the prompt text
3305 FillConsoleOutputCharacter(hStdOut
, ' ',
3306 prompt_len
, info
.dwCursorPosition
, &result
);
3308 // restore the text attribute to norml
3310 FillConsoleOutputAttribute(hStdOut
, info
.wAttributes
,
3311 prompt_len
, info
.dwCursorPosition
, &result
);
3313 // restore the original console mode
3315 SetConsoleMode(hStdIn
, mode
);
3317 // check if the input was 'q', <esc> or <Ctrl+C> ?
3319 if (input
.Event
.KeyEvent
.uChar
.AsciiChar
== VK_CANCEL
||
3320 input
.Event
.KeyEvent
.uChar
.AsciiChar
== VK_ESCAPE
||
3321 tolower(input
.Event
.KeyEvent
.uChar
.AsciiChar
) == 'q') {
3323 // cancelled by the user
3328 // process the next page
3338 // Format and print a message text
3340 void PrintMessage(UINT msg
, ...)
3345 va_start(list
, msg
);
3348 FORMAT_MESSAGE_FROM_HMODULE
|
3349 FORMAT_MESSAGE_ALLOCATE_BUFFER
,
3350 NULL
, msg
, 0, (LPTSTR
)&buf
, 0, &list
)) {
3355 printf("Unknown Message ID %u\n", msg
);
3366 // Return a system error message text
3368 const char *SystemError(DWORD err
)
3370 static char msg
[256];
3373 FORMAT_MESSAGE_FROM_SYSTEM
|
3374 FORMAT_MESSAGE_IGNORE_INSERTS
,
3375 NULL
, err
, 0, msg
, sizeof(msg
), NULL
)) {
3377 sprintf(msg
, "Unknown system error %lu (0x%08x)\n", err
, err
);
3379 sprintf(msg
, "Unknown system error %lu (0x%08lx)\n", err
, err
);
3387 // Convert a path to match the case of names on the disk
3389 void ConvertPathCase(char *src
, char *dst
)
3392 WIN32_FIND_DATA find
;
3401 if (*(src
+ strlen(src
) - 1) == '\"') {
3402 *(src
+ strlen(src
) - 1) = '\0';
3406 // handle drive / remote server name
3408 if (isalpha(*src
) && *(src
+ 1) == ':') {
3412 *(p
++) = (char)toupper(*src
);
3417 else if (*src
== '\\' || *src
== '/') {
3419 // absolute path or remote name
3421 if ((*(src
+ 1) == '\\' || *(src
+ 1) == '/') &&
3422 *(src
+ 2) && *(src
+ 2) != '\\' && *(src
+ 2) != '/') {
3430 while (*src
&& *src
!= '\\' && *src
!= '/') {
3441 // skip redundant '\'
3443 while (*src
== '\\' || *src
== '/') {
3453 // separate the next part
3455 while (*q
&& *q
!= '\\' && *q
!= '/') {
3459 if ((q
- src
) == 2 && !strncmp(src
, "..", 2)) {
3460 // parent dir - copy as it is
3468 else if ((q
- src
) > 1 || *src
!= '.') {
3469 // path name other than "."
3474 strncpy(p
, src
, (q
- src
));
3475 *(p
+ (q
- src
)) = '\0';
3477 hFind
= FindFirstFile(dst
, &find
);
3479 if (hFind
== INVALID_HANDLE_VALUE
) {
3486 strcpy(p
, find
.cFileName
);
3490 // skip trailing '\'s
3492 while (*q
== '\\' || *q
== '/') {