2 * ReactOS mode console command
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * COPYRIGHT: See COPYING in the top level directory
24 * PROJECT: ReactOS Mode Utility
25 * FILE: base/applications/cmdutils/mode/mode.c
26 * PURPOSE: Provides fast mode setup for DOS devices.
27 * PROGRAMMERS: Robert Dickenson
28 * Hermes Belusca-Maito
38 #define MAX_PORTNAME_LEN 20
39 #define MAX_COMPORT_NUM 10
43 const WCHAR
* const usage_strings
[] =
45 L
"Device Status: MODE [device] [/STATUS]",
46 L
"Select code page: MODE CON[:] CP SELECT=yyy",
47 L
"Code page status: MODE CON[:] CP [/STATUS]",
48 L
"Display mode: MODE CON[:] [COLS=c] [LINES=n]",
49 L
"Typematic rate: MODE CON[:] [RATE=r DELAY=d]",
50 L
"Redirect printing: MODE LPTn[:]=COMm[:]",
51 L
"Serial port: MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s]\n" \
52 L
" [to=on|off] [xon=on|off] [odsr=on|off]\n" \
53 L
" [octs=on|off] [dtr=on|off|hs]\n" \
54 L
" [rts=on|off|hs|tg] [idsr=on|off]",
61 wprintf(L
"\nConfigures system devices.\n\n");
62 for (i
= 0; i
< ARRAYSIZE(usage_strings
); i
++)
64 wprintf(L
"%s\n", usage_strings
[i
]);
69 int QueryDevices(VOID
)
75 // FIXME: Dynamically allocate 'buffer' in a loop.
76 if (QueryDosDeviceW(NULL
, buffer
, ARRAYSIZE(buffer
)))
80 if (wcsstr(ptr
, L
"COM"))
82 wprintf(L
" Found serial device - %s\n", ptr
);
84 else if (wcsstr(ptr
, L
"PRN"))
86 wprintf(L
" Found printer device - %s\n", ptr
);
88 else if (wcsstr(ptr
, L
"LPT"))
90 wprintf(L
" Found parallel device - %s\n", ptr
);
94 // wprintf(L" Found other device - %s\n", ptr);
96 ptr
+= (wcslen(ptr
) + 1);
101 wprintf(L
" ERROR: QueryDosDeviceW(...) failed: 0x%lx\n", GetLastError());
106 int ShowParallelStatus(INT nPortNum
)
109 WCHAR szPortName
[MAX_PORTNAME_LEN
];
111 swprintf(szPortName
, L
"LPT%d", nPortNum
);
112 wprintf(L
"\nStatus for device LPT%d:\n", nPortNum
);
113 wprintf(L
"-----------------------\n");
114 if (QueryDosDeviceW(szPortName
, buffer
, ARRAYSIZE(buffer
)))
116 WCHAR
* ptr
= wcsrchr(buffer
, L
'\\');
119 if (_wcsicmp(szPortName
, ++ptr
) == 0)
121 wprintf(L
" Printer output is not being rerouted.\n");
125 wprintf(L
" Printer output is being rerouted to serial port %s\n", ptr
);
131 wprintf(L
" QueryDosDeviceW(%s) returned unrecognised form %s.\n", szPortName
, buffer
);
136 wprintf(L
" ERROR: QueryDosDeviceW(%s) failed: 0x%lx\n", szPortName
, GetLastError());
141 int SetParallelState(INT nPortNum
)
143 WCHAR szPortName
[MAX_PORTNAME_LEN
];
144 WCHAR szTargetPath
[MAX_PORTNAME_LEN
];
146 swprintf(szPortName
, L
"LPT%d", nPortNum
);
147 swprintf(szTargetPath
, L
"COM%d", nPortNum
);
148 if (!DefineDosDeviceW(DDD_REMOVE_DEFINITION
, szPortName
, szTargetPath
))
150 wprintf(L
"SetParallelState(%d) - DefineDosDevice(%s) failed: 0x%lx\n", nPortNum
, szPortName
, GetLastError());
153 ShowParallelStatus(nPortNum
);
159 ParseNumber(PCWSTR argStr
, PDWORD Number
)
163 value
= swscanf(argStr
, L
"%lu%n", Number
, &skip
);
164 if (!value
) return NULL
;
172 \Device\NamedPipe\Spooler\LPT1
173 BOOL DefineDosDevice(
174 DWORD dwFlags, // options
175 LPCTSTR lpDeviceName, // device name
176 LPCTSTR lpTargetPath // path string
178 DWORD QueryDosDevice(
179 LPCTSTR lpDeviceName, // MS-DOS device name string
180 LPTSTR lpTargetPath, // query results buffer
181 DWORD ucchMax // maximum size of buffer
186 /*****************************************************************************\
187 ** C O N S O L E H E L P E R S **
188 \*****************************************************************************/
190 int ShowConsoleStatus(VOID
)
192 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
193 CONSOLE_SCREEN_BUFFER_INFO csbi
;
194 DWORD dwKbdDelay
, dwKbdSpeed
;
196 wprintf(L
"\nStatus for device CON:\n");
197 wprintf(L
"-----------------------\n");
198 if (GetConsoleScreenBufferInfo(hConOut
, &csbi
))
200 wprintf(L
" Lines: %d\n", csbi
.dwSize
.Y
);
201 wprintf(L
" Columns: %d\n", csbi
.dwSize
.X
);
203 if (SystemParametersInfoW(SPI_GETKEYBOARDDELAY
, 0, &dwKbdDelay
, 0))
205 wprintf(L
" Keyboard delay: %ld\n", dwKbdDelay
);
207 if (SystemParametersInfoW(SPI_GETKEYBOARDSPEED
, 0, &dwKbdSpeed
, 0))
209 wprintf(L
" Keyboard rate: %ld\n", dwKbdSpeed
);
211 wprintf(L
" Code page: %d\n", GetConsoleOutputCP());
215 int ShowConsoleCPStatus(VOID
)
217 wprintf(L
"\nStatus for device CON:\n");
218 wprintf(L
"-----------------------\n");
219 wprintf(L
" Code page: %d\n", GetConsoleOutputCP());
224 * See, or adjust if needed, subsystems/mvdm/ntvdm/console/video.c!ResizeTextConsole()
225 * for more information.
230 PCONSOLE_SCREEN_BUFFER_INFO pcsbi
, // FIXME
235 SHORT oldWidth
, oldHeight
;
238 * Use this trick to effectively resize the console buffer and window,
240 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
241 * is smaller than the current console window size, and:
242 * - SetConsoleWindowInfo fails if the new console window size is larger
243 * than the current console screen buffer size.
247 // /* Retrieve the latest console information */
248 // GetConsoleScreenBufferInfo(hConsoleOutput, &ConsoleInfo);
250 oldWidth
= pcsbi
->srWindow
.Right
- pcsbi
->srWindow
.Left
+ 1;
251 oldHeight
= pcsbi
->srWindow
.Bottom
- pcsbi
->srWindow
.Top
+ 1;
254 * If the current console window is too large to hold the full contents
255 * of the new screen buffer, resize it first.
257 if (oldWidth
> Resolution
->X
|| oldHeight
> Resolution
->Y
)
260 // NOTE: This is not a problem if we move the window back to (0,0)
261 // because when we resize the screen buffer, the window will move back
262 // to where the cursor is. Or, if the screen buffer is not resized,
263 // when we readjust again the window, we will move back to a correct
264 // position. This is what we wanted after all...
267 ConRect
.Left
= ConRect
.Top
= 0;
268 ConRect
.Right
= ConRect
.Left
+ min(oldWidth
, Resolution
->X
) - 1;
269 ConRect
.Bottom
= ConRect
.Top
+ min(oldHeight
, Resolution
->Y
) - 1;
271 Success
= SetConsoleWindowInfo(hConOut
, TRUE
, &ConRect
);
272 if (!Success
) wprintf(L
"(resize) SetConsoleWindowInfo(1) failed with error %d\n", GetLastError());
275 /* Resize the screen buffer if needed */
276 if (Resolution
->X
!= pcsbi
->dwSize
.X
|| Resolution
->Y
!= pcsbi
->dwSize
.Y
)
279 * SetConsoleScreenBufferSize automatically takes into account the current
280 * cursor position when it computes starting which row it should copy text
281 * when resizing the sceenbuffer, and scrolls the console window such that
282 * the cursor is placed in it again. We therefore do not need to care about
283 * the cursor position and do the maths ourselves.
285 Success
= SetConsoleScreenBufferSize(hConOut
, *Resolution
);
286 if (!Success
) wprintf(L
"(resize) SetConsoleScreenBufferSize failed with error %d\n", GetLastError());
289 * Setting a new screen buffer size can change other information,
290 * so update the saved console information.
292 GetConsoleScreenBufferInfo(hConOut
, pcsbi
);
296 ConRect
.Right
= ConRect
.Left
+ Resolution
->X
- 1;
297 ConRect
.Bottom
= max(pcsbi
->dwCursorPosition
.Y
, Resolution
->Y
- 1);
298 ConRect
.Top
= ConRect
.Bottom
- Resolution
->Y
+ 1;
300 SetConsoleWindowInfo(hConOut
, TRUE
, &ConRect
);
303 int SetConsoleStateOld(IN PCWSTR ArgStr
)
305 PCWSTR argStr
= ArgStr
;
307 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
308 CONSOLE_SCREEN_BUFFER_INFO csbi
;
312 if (!GetConsoleScreenBufferInfo(hConOut
, &csbi
))
314 // TODO: Error message?
318 Resolution
= csbi
.dwSize
;
320 /* Parse the column number (only MANDATORY argument) */
322 argStr
= ParseNumber(argStr
, &value
);
323 if (!argStr
) goto invalid_parameter
;
324 Resolution
.X
= (SHORT
)value
;
326 /* Parse the line number (OPTIONAL argument) */
327 while (*argStr
== L
' ') argStr
++;
328 if (!*argStr
) goto Quit
;
329 if (*argStr
++ != L
',') goto invalid_parameter
;
330 while (*argStr
== L
' ') argStr
++;
333 argStr
= ParseNumber(argStr
, &value
);
334 if (!argStr
) goto invalid_parameter
;
335 Resolution
.Y
= (SHORT
)value
;
337 /* This should be the end of the string */
338 if (*argStr
) argStr
++;
339 while (*argStr
== L
' ') argStr
++;
340 if (*argStr
) goto invalid_parameter
;
344 * See, or adjust if needed, subsystems/mvdm/ntvdm/console/video.c!ResizeTextConsole()
345 * for more information.
347 ResizeTextConsole(hConOut
, &ConsoleScreenBufferInfo
, &Resolution
);
351 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
355 int SetConsoleState(IN PCWSTR ArgStr
)
357 PCWSTR argStr
= ArgStr
;
358 BOOL dispMode
= FALSE
, kbdMode
= FALSE
;
360 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
361 CONSOLE_SCREEN_BUFFER_INFO csbi
;
363 DWORD dwKbdDelay
, dwKbdSpeed
;
366 if (!GetConsoleScreenBufferInfo(hConOut
, &csbi
))
368 // TODO: Error message?
371 if (!SystemParametersInfoW(SPI_GETKEYBOARDDELAY
, 0, &dwKbdDelay
, 0))
373 // TODO: Error message?
376 if (!SystemParametersInfoW(SPI_GETKEYBOARDSPEED
, 0, &dwKbdSpeed
, 0))
378 // TODO: Error message?
382 Resolution
= csbi
.dwSize
;
384 while (argStr
&& *argStr
)
386 while (*argStr
== L
' ') argStr
++;
389 if (!kbdMode
&& _wcsnicmp(argStr
, L
"COLS=", 5) == 0)
394 argStr
= ParseNumber(argStr
+5, &value
);
395 if (!argStr
) goto invalid_parameter
;
396 Resolution
.X
= (SHORT
)value
;
398 else if (!kbdMode
&& _wcsnicmp(argStr
, L
"LINES=", 6) == 0)
403 argStr
= ParseNumber(argStr
+6, &value
);
404 if (!argStr
) goto invalid_parameter
;
405 Resolution
.Y
= (SHORT
)value
;
407 else if (!dispMode
&& _wcsnicmp(argStr
, L
"RATE=", 5) == 0)
411 argStr
= ParseNumber(argStr
+5, &dwKbdSpeed
);
412 if (!argStr
) goto invalid_parameter
;
414 else if (!dispMode
&& _wcsnicmp(argStr
, L
"DELAY=", 6) == 0)
418 argStr
= ParseNumber(argStr
+6, &dwKbdDelay
);
419 if (!argStr
) goto invalid_parameter
;
424 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
432 * See, or adjust if needed, subsystems/mvdm/ntvdm/console/video.c!ResizeTextConsole()
433 * for more information.
435 ResizeTextConsole(hConOut
, &ConsoleScreenBufferInfo
, &Resolution
);
440 * Set the new keyboard settings. If those values are greater than
441 * their allowed range, they are automatically corrected as follows:
442 * dwKbdSpeed = min(dwKbdSpeed, 31);
443 * dwKbdDelay = (dwKbdDelay % 4);
445 SystemParametersInfoW(SPI_SETKEYBOARDDELAY
, dwKbdDelay
, NULL
, 0);
446 SystemParametersInfoW(SPI_SETKEYBOARDSPEED
, dwKbdSpeed
, NULL
, SPIF_UPDATEINIFILE
| SPIF_SENDCHANGE
);
452 int SetConsoleCPState(IN PCWSTR ArgStr
)
454 PCWSTR argStr
= ArgStr
;
457 if ( (_wcsnicmp(argStr
, L
"SELECT=", 7) == 0 && (argStr
+= 7)) ||
458 (_wcsnicmp(argStr
, L
"SEL=", 4) == 0 && (argStr
+= 4)) )
460 argStr
= ParseNumber(argStr
, &CodePage
);
461 if (!argStr
) goto invalid_parameter
;
463 SetConsoleCP(CodePage
);
464 SetConsoleOutputCP(CodePage
);
465 ShowConsoleCPStatus();
470 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
478 /*****************************************************************************\
479 ** S E R I A L P O R T H E L P E R S **
480 \*****************************************************************************/
483 SerialPortQuery(INT nPortNum
, LPDCB pDCB
, LPCOMMTIMEOUTS pCommTimeouts
, BOOL bWrite
)
487 WCHAR szPortName
[MAX_PORTNAME_LEN
];
490 ASSERT(pCommTimeouts
);
492 swprintf(szPortName
, L
"COM%d", nPortNum
);
493 hPort
= CreateFileW(szPortName
,
494 bWrite
? GENERIC_WRITE
: GENERIC_READ
,
499 NULL
); // no template
501 if (hPort
== INVALID_HANDLE_VALUE
)
503 wprintf(L
"Illegal device name - %s\n", szPortName
);
504 wprintf(L
"Last error = 0x%lx\n", GetLastError());
508 Success
= bWrite
? SetCommState(hPort
, pDCB
)
509 : GetCommState(hPort
, pDCB
);
512 wprintf(L
"Failed to %s the status for device COM%d:\n", bWrite
? L
"set" : L
"get", nPortNum
);
516 Success
= bWrite
? SetCommTimeouts(hPort
, pCommTimeouts
)
517 : GetCommTimeouts(hPort
, pCommTimeouts
);
520 wprintf(L
"Failed to %s timeout status for device COM%d:\n", bWrite
? L
"set" : L
"get", nPortNum
);
529 int ShowSerialStatus(INT nPortNum
)
531 static const LPCWSTR parity_strings
[] =
535 L
"Even", // EVENPARITY
536 L
"Mark", // MARKPARITY
537 L
"Space" // SPACEPARITY
539 static const LPCWSTR control_strings
[] = { L
"OFF", L
"ON", L
"HANDSHAKE", L
"TOGGLE" };
540 static const LPCWSTR stopbit_strings
[] = { L
"1", L
"1.5", L
"2" };
543 COMMTIMEOUTS CommTimeouts
;
545 if (!SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, FALSE
))
549 if (dcb
.Parity
>= ARRAYSIZE(parity_strings
))
551 wprintf(L
"ERROR: Invalid value for Parity Bits %d:\n", dcb
.Parity
);
554 if (dcb
.StopBits
>= ARRAYSIZE(stopbit_strings
))
556 wprintf(L
"ERROR: Invalid value for Stop Bits %d:\n", dcb
.StopBits
);
559 wprintf(L
"\nStatus for device COM%d:\n", nPortNum
);
560 wprintf(L
"-----------------------\n");
561 wprintf(L
" Baud: %ld\n", dcb
.BaudRate
);
562 wprintf(L
" Parity: %s\n", parity_strings
[dcb
.Parity
]);
563 wprintf(L
" Data Bits: %d\n", dcb
.ByteSize
);
564 wprintf(L
" Stop Bits: %s\n", stopbit_strings
[dcb
.StopBits
]);
565 wprintf(L
" Timeout: %s\n",
566 (CommTimeouts
.ReadTotalTimeoutConstant
!= 0) ||
567 (CommTimeouts
.WriteTotalTimeoutConstant
!= 0) ? L
"ON" : L
"OFF");
568 wprintf(L
" XON/XOFF: %s\n", dcb
.fOutX
? L
"ON" : L
"OFF");
569 wprintf(L
" CTS handshaking: %s\n", dcb
.fOutxCtsFlow
? L
"ON" : L
"OFF");
570 wprintf(L
" DSR handshaking: %s\n", dcb
.fOutxDsrFlow
? L
"ON" : L
"OFF");
571 wprintf(L
" DSR sensitivity: %s\n", dcb
.fDsrSensitivity
? L
"ON" : L
"OFF");
572 wprintf(L
" DTR circuit: %s\n", control_strings
[dcb
.fDtrControl
]);
573 wprintf(L
" RTS circuit: %s\n", control_strings
[dcb
.fRtsControl
]);
579 * Those procedures are inspired from Wine's dll/win32/kernel32/wine/comm.c
580 * Copyright 1996 Erik Bos and Marcus Meissner.
584 ParseModes(PCWSTR argStr
, PBYTE Mode
)
586 if (_wcsnicmp(argStr
, L
"OFF", 3) == 0)
591 else if (_wcsnicmp(argStr
, L
"ON", 2) == 0)
596 else if (_wcsnicmp(argStr
, L
"HS", 2) == 0)
601 else if (_wcsnicmp(argStr
, L
"TG", 2) == 0)
611 ParseBaudRate(PCWSTR argStr
, PDWORD BaudRate
)
613 argStr
= ParseNumber(argStr
, BaudRate
);
614 if (!argStr
) return NULL
;
617 * Check for Baud Rate abbreviations. This means that using
618 * those values as real baud rates is impossible using MODE.
622 /* BaudRate = 110, 150, 300, 600 */
623 case 11: case 15: case 30: case 60:
627 /* BaudRate = 1200, 2400, 4800, 9600 */
628 case 12: case 24: case 48: case 96:
641 ParseParity(PCWSTR argStr
, PBYTE Parity
)
643 switch (towupper(*argStr
++))
654 *Parity
= EVENPARITY
;
658 *Parity
= MARKPARITY
;
662 *Parity
= SPACEPARITY
;
673 ParseByteSize(PCWSTR argStr
, PBYTE ByteSize
)
677 argStr
= ParseNumber(argStr
, &value
);
678 if (!argStr
) return NULL
;
680 *ByteSize
= (BYTE
)value
;
681 if (*ByteSize
< 5 || *ByteSize
> 8)
688 ParseStopBits(PCWSTR argStr
, PBYTE StopBits
)
690 if (_wcsnicmp(argStr
, L
"1.5", 3) == 0)
693 *StopBits
= ONE5STOPBITS
;
698 *StopBits
= ONESTOPBIT
;
699 else if (*argStr
== L
'2')
700 *StopBits
= TWOSTOPBITS
;
711 * Build a DCB using the old style settings string eg: "96,n,8,1"
713 * See dll/win32/kernel32/wine/comm.c!COMM_BuildOldCommDCB()
714 * for more information.
721 PCWSTR argStr
= ArgStr
;
725 * Parse the baud rate (only MANDATORY argument)
727 argStr
= ParseBaudRate(argStr
, &pDCB
->BaudRate
);
728 if (!argStr
) return FALSE
;
732 * Now parse the rest (OPTIONAL arguments)
735 while (*argStr
== L
' ') argStr
++;
736 if (!*argStr
) goto Quit
;
737 if (*argStr
++ != L
',') return FALSE
;
738 while (*argStr
== L
' ') argStr
++;
739 if (!*argStr
) goto Quit
;
741 /* Parse the parity */
742 // Default: EVENPARITY
743 pDCB
->Parity
= EVENPARITY
;
746 argStr
= ParseParity(argStr
, &pDCB
->Parity
);
747 if (!argStr
) return FALSE
;
750 while (*argStr
== L
' ') argStr
++;
751 if (!*argStr
) goto Quit
;
752 if (*argStr
++ != L
',') return FALSE
;
753 while (*argStr
== L
' ') argStr
++;
754 if (!*argStr
) goto Quit
;
756 /* Parse the data bits */
761 argStr
= ParseByteSize(argStr
, &pDCB
->ByteSize
);
762 if (!argStr
) return FALSE
;
765 while (*argStr
== L
' ') argStr
++;
766 if (!*argStr
) goto Quit
;
767 if (*argStr
++ != L
',') return FALSE
;
768 while (*argStr
== L
' ') argStr
++;
769 if (!*argStr
) goto Quit
;
771 /* Parse the stop bits */
772 // Default: 1, or 2 for BAUD=110
773 // pDCB->StopBits = ONESTOPBIT;
777 argStr
= ParseStopBits(argStr
, &pDCB
->StopBits
);
778 if (!argStr
) return FALSE
;
781 /* The last parameter (flow control "retry") is really optional */
782 while (*argStr
== L
' ') argStr
++;
783 if (!*argStr
) goto Quit
;
784 if (*argStr
++ != L
',') return FALSE
;
785 while (*argStr
== L
' ') argStr
++;
786 if (!*argStr
) goto Quit
;
789 switch (towupper(*argStr
))
794 pDCB
->fOutxCtsFlow
= FALSE
;
795 pDCB
->fOutxDsrFlow
= FALSE
;
796 pDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
797 pDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
803 pDCB
->fOutxCtsFlow
= FALSE
;
804 pDCB
->fOutxDsrFlow
= FALSE
;
805 pDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
806 pDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
812 pDCB
->fOutxCtsFlow
= TRUE
;
813 pDCB
->fOutxDsrFlow
= TRUE
;
814 pDCB
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
815 pDCB
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
823 /* This should be the end of the string */
824 if (*argStr
) argStr
++;
825 while (*argStr
== L
' ') argStr
++;
826 if (*argStr
) return FALSE
;
828 /* If stop bits were not specified, a default is always supplied */
831 if (pDCB
->BaudRate
== 110)
832 pDCB
->StopBits
= TWOSTOPBITS
;
834 pDCB
->StopBits
= ONESTOPBIT
;
840 * Build a DCB using the new style settings string.
841 * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
843 * See dll/win32/kernel32/wine/comm.c!COMM_BuildNewCommDCB()
844 * for more information.
849 OUT LPCOMMTIMEOUTS pCommTimeouts
,
852 PCWSTR argStr
= ArgStr
;
853 BOOL baud
= FALSE
, stop
= FALSE
;
856 while (argStr
&& *argStr
)
858 while (*argStr
== L
' ') argStr
++;
861 if (_wcsnicmp(argStr
, L
"BAUD=", 5) == 0)
864 argStr
= ParseBaudRate(argStr
+5, &pDCB
->BaudRate
);
865 if (!argStr
) return FALSE
;
867 else if (_wcsnicmp(argStr
, L
"PARITY=", 7) == 0)
869 // Default: EVENPARITY
870 argStr
= ParseParity(argStr
+7, &pDCB
->Parity
);
871 if (!argStr
) return FALSE
;
873 else if (_wcsnicmp(argStr
, L
"DATA=", 5) == 0)
876 argStr
= ParseByteSize(argStr
+5, &pDCB
->ByteSize
);
877 if (!argStr
) return FALSE
;
879 else if (_wcsnicmp(argStr
, L
"STOP=", 5) == 0)
881 // Default: 1, or 2 for BAUD=110
883 argStr
= ParseStopBits(argStr
+5, &pDCB
->StopBits
);
884 if (!argStr
) return FALSE
;
886 else if (_wcsnicmp(argStr
, L
"TO=", 3) == 0) // TO=ON|OFF
888 /* Only total time-outs are get/set by Windows' MODE.COM */
889 argStr
= ParseModes(argStr
+3, &value
);
890 if (!argStr
) return FALSE
;
891 if (value
== 0) // OFF
893 pCommTimeouts
->ReadTotalTimeoutConstant
= 0;
894 pCommTimeouts
->WriteTotalTimeoutConstant
= 0;
896 else if (value
== 1) // ON
898 pCommTimeouts
->ReadTotalTimeoutConstant
= 60000;
899 pCommTimeouts
->WriteTotalTimeoutConstant
= 60000;
906 else if (_wcsnicmp(argStr
, L
"XON=", 4) == 0) // XON=ON|OFF
908 argStr
= ParseModes(argStr
+4, &value
);
909 if (!argStr
) return FALSE
;
910 if ((value
== 0) || (value
== 1))
920 else if (_wcsnicmp(argStr
, L
"ODSR=", 5) == 0) // ODSR=ON|OFF
923 argStr
= ParseModes(argStr
+5, &value
);
924 if (!argStr
) return FALSE
;
925 if ((value
== 0) || (value
== 1))
926 pDCB
->fOutxDsrFlow
= value
;
930 else if (_wcsnicmp(argStr
, L
"OCTS=", 5) == 0) // OCTS=ON|OFF
933 argStr
= ParseModes(argStr
+5, &value
);
934 if (!argStr
) return FALSE
;
935 if ((value
== 0) || (value
== 1))
936 pDCB
->fOutxCtsFlow
= value
;
940 else if (_wcsnicmp(argStr
, L
"DTR=", 4) == 0) // DTR=ON|OFF|HS
943 argStr
= ParseModes(argStr
+4, &value
);
944 if (!argStr
) return FALSE
;
945 if ((value
== 0) || (value
== 1) || (value
== 2))
946 pDCB
->fDtrControl
= value
;
950 else if (_wcsnicmp(argStr
, L
"RTS=", 4) == 0) // RTS=ON|OFF|HS|TG
953 argStr
= ParseModes(argStr
+4, &value
);
954 if (!argStr
) return FALSE
;
955 if ((value
== 0) || (value
== 1) || (value
== 2) || (value
== 3))
956 pDCB
->fRtsControl
= value
;
960 else if (_wcsnicmp(argStr
, L
"IDSR=", 5) == 0) // IDSR=ON|OFF
963 argStr
= ParseModes(argStr
+5, &value
);
964 if (!argStr
) return FALSE
;
965 if ((value
== 0) || (value
== 1))
966 pDCB
->fDsrSensitivity
= value
;
976 /* If stop bits were not specified, a default is always supplied */
979 if (baud
&& pDCB
->BaudRate
== 110)
980 pDCB
->StopBits
= TWOSTOPBITS
;
982 pDCB
->StopBits
= ONESTOPBIT
;
987 int SetSerialState(INT nPortNum
, IN PCWSTR ArgStr
)
991 COMMTIMEOUTS CommTimeouts
;
993 if (!SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, FALSE
))
995 // TODO: Error message?
1000 * Check whether we should use the old or the new MODE syntax:
1001 * in the old syntax, the separators are both spaces and commas.
1003 if (wcschr(ArgStr
, L
','))
1004 Success
= BuildOldCommDCB(&dcb
, ArgStr
);
1006 Success
= BuildNewCommDCB(&dcb
, &CommTimeouts
, ArgStr
);
1010 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
1014 SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, TRUE
);
1015 ShowSerialStatus(nPortNum
);
1021 /*****************************************************************************\
1022 ** E N T R Y P O I N T **
1023 \*****************************************************************************/
1026 FindPortNum(PCWSTR argStr
, PINT PortNum
)
1030 if (*argStr
>= L
'0' && *argStr
<= L
'9')
1032 *PortNum
= *argStr
- L
'0';
1034 if (*argStr
>= L
'0' && *argStr
<= L
'9')
1037 *PortNum
+= *argStr
- L
'0';
1048 int wmain(int argc
, WCHAR
* argv
[])
1053 PCWSTR ArgStr
, argStr
;
1058 * MODE.COM has a very peculiar way of parsing its arguments,
1059 * as they can be even not separated by any space. This extreme
1060 * behaviour certainly is present for backwards compatibility
1061 * with the oldest versions of the utility present on MS-DOS.
1063 * For example, such a command:
1064 * "MODE.COM COM1baud=9600parity=ndata=8stop=1xon=onto=on"
1065 * will be correctly understood as:
1066 * "MODE.COM COM1 baud=9600 parity=n data=8 stop=1 xon=on to=on"
1068 * Note also that the "/STATUS" switch is actually really "/STA".
1070 * However we will not use GetCommandLine() because we do not want
1071 * to deal with the prepended application path and try to find
1072 * where the arguments start. Our approach here will consist in
1073 * flattening the arguments vector.
1077 /* Compute space needed for the new string, and allocate it */
1078 for (arg
= 1; arg
< argc
; arg
++)
1080 ArgStrSize
+= wcslen(argv
[arg
]) + 1; // 1 for space
1082 ArgStr
= HeapAlloc(GetProcessHeap(), 0, (ArgStrSize
+ 1) * sizeof(WCHAR
));
1085 wprintf(L
"ERROR: Not enough memory\n");
1089 /* Copy the contents and NULL-terminate the string */
1091 for (arg
= 1; arg
< argc
; arg
++)
1093 wcscpy((PWSTR
)argStr
, argv
[arg
]);
1094 argStr
+= wcslen(argv
[arg
]);
1095 *(PWSTR
)argStr
++ = L
' ';
1097 *(PWSTR
)argStr
= L
'\0';
1099 /* Parse the command line */
1102 while (*argStr
== L
' ') argStr
++;
1103 if (!*argStr
) goto show_status
;
1105 if (wcsstr(argStr
, L
"/?") || wcsstr(argStr
, L
"-?"))
1110 else if (_wcsnicmp(argStr
, L
"/STA", 4) == 0)
1112 // FIXME: Check if there are other "parameters" after the status,
1113 // in which case this is invalid.
1116 else if (_wcsnicmp(argStr
, L
"LPT", 3) == 0)
1118 argStr
= FindPortNum(argStr
+3, &nPortNum
);
1119 if (!argStr
|| nPortNum
== -1)
1120 goto invalid_parameter
;
1122 if (*argStr
== L
':') argStr
++;
1123 while (*argStr
== L
' ') argStr
++;
1125 ret
= ShowParallelStatus(nPortNum
);
1128 else if (_wcsnicmp(argStr
, L
"COM", 3) == 0)
1130 argStr
= FindPortNum(argStr
+3, &nPortNum
);
1131 if (!argStr
|| nPortNum
== -1)
1132 goto invalid_parameter
;
1134 if (*argStr
== L
':') argStr
++;
1135 while (*argStr
== L
' ') argStr
++;
1137 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1138 ret
= ShowSerialStatus(nPortNum
);
1140 ret
= SetSerialState(nPortNum
, argStr
);
1143 else if (_wcsnicmp(argStr
, L
"CON", 3) == 0)
1147 if (*argStr
== L
':') argStr
++;
1148 while (*argStr
== L
' ') argStr
++;
1150 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1152 ret
= ShowConsoleStatus();
1154 else if ( (_wcsnicmp(argStr
, L
"CP", 2) == 0 && (argStr
+= 2)) ||
1155 (_wcsnicmp(argStr
, L
"CODEPAGE", 8) == 0 && (argStr
+= 8)) )
1157 while (*argStr
== L
' ') argStr
++;
1159 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1160 ret
= ShowConsoleCPStatus();
1162 ret
= SetConsoleCPState(argStr
);
1166 ret
= SetConsoleState(argStr
);
1170 // else if (wcschr(argStr, L','))
1173 /* Old syntax: MODE [COLS],[LINES] */
1174 ret
= SetConsoleStateOld(argStr
);
1181 ShowParallelStatus(1);
1182 for (nPortNum = 0; nPortNum < MAX_COMPORT_NUM; nPortNum++)
1184 ShowSerialStatus(nPortNum + 1);
1186 ShowConsoleStatus();
1191 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
1195 /* Free the string and quit */
1196 HeapFree(GetProcessHeap(), 0, (PWSTR
)ArgStr
);