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
42 #define MAX_PORTNAME_LEN 20
43 #define MAX_COMPORT_NUM 10
47 /*** For fixes, see also network/net/main.c ***/
48 // VOID PrintPadding(...)
52 IN PCON_STREAM Stream
,
59 #define MAX_BUFFER_SIZE 4096
61 WCHAR szMsgBuffer
[MAX_BUFFER_SIZE
];
64 Len
= ConResPrintfV(Stream
, uID
, args
);
67 ConPuts(Stream
, L
"\n");
68 for (i
= 0; i
< Len
; i
++)
69 szMsgBuffer
[i
] = L
'-';
70 szMsgBuffer
[Len
] = UNICODE_NULL
;
72 ConStreamWrite(Stream
, szMsgBuffer
, Len
);
75 int QueryDevices(VOID
)
78 DWORD dwLen
= MAX_PATH
;
80 /* Pre-allocate a buffer for QueryDosDeviceW() */
81 Buffer
= HeapAlloc(GetProcessHeap(), 0, dwLen
* sizeof(WCHAR
));
84 /* We failed, bail out */
85 ConPuts(StdErr
, L
"ERROR: Not enough memory\n");
91 *Buffer
= UNICODE_NULL
;
92 if (QueryDosDeviceW(NULL
, Buffer
, dwLen
))
95 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
97 /* We failed, bail out */
98 ConPrintf(StdErr
, L
"ERROR: QueryDosDeviceW(...) failed: 0x%lx\n", GetLastError());
99 HeapFree(GetProcessHeap(), 0, Buffer
);
103 /* The buffer was too small, try to re-allocate it */
105 ptr
= HeapReAlloc(GetProcessHeap(), 0, Buffer
, dwLen
* sizeof(WCHAR
));
108 /* We failed, bail out */
109 ConPuts(StdErr
, L
"ERROR: Not enough memory\n");
110 HeapFree(GetProcessHeap(), 0, Buffer
);
116 for (ptr
= Buffer
; *ptr
!= UNICODE_NULL
; ptr
+= wcslen(ptr
) + 1)
118 if (wcsstr(ptr
, L
"COM"))
120 ConResPrintf(StdOut
, IDS_QUERY_SERIAL_FOUND
, ptr
);
122 else if (wcsstr(ptr
, L
"PRN"))
124 ConResPrintf(StdOut
, IDS_QUERY_PRINTER_FOUND
, ptr
);
126 else if (wcsstr(ptr
, L
"LPT"))
128 ConResPrintf(StdOut
, IDS_QUERY_PARALLEL_FOUND
, ptr
);
130 else if (wcsstr(ptr
, L
"AUX") || wcsstr(ptr
, L
"NUL"))
132 ConResPrintf(StdOut
, IDS_QUERY_DOSDEV_FOUND
, ptr
);
136 // ConResPrintf(StdOut, IDS_QUERY_MISC_FOUND, ptr);
140 /* Free the buffer and return success */
141 HeapFree(GetProcessHeap(), 0, Buffer
);
145 int ShowParallelStatus(INT nPortNum
)
148 WCHAR szPortName
[MAX_PORTNAME_LEN
];
150 swprintf(szPortName
, L
"LPT%d", nPortNum
);
152 ConPuts(StdOut
, L
"\n");
153 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, szPortName
);
154 ConPuts(StdOut
, L
"\n");
156 if (QueryDosDeviceW(szPortName
, buffer
, ARRAYSIZE(buffer
)))
158 PWSTR ptr
= wcsrchr(buffer
, L
'\\');
161 if (_wcsicmp(szPortName
, ++ptr
) == 0)
162 ConResPuts(StdOut
, IDS_PRINTER_OUTPUT_NOT_REROUTED
);
164 ConResPrintf(StdOut
, IDS_PRINTER_OUTPUT_REROUTED_SERIAL
, ptr
);
170 ConPrintf(StdErr
, L
" QueryDosDeviceW(%s) returned unrecognised form %s.\n", szPortName
, buffer
);
175 ConPrintf(StdErr
, L
"ERROR: QueryDosDeviceW(%s) failed: 0x%lx\n", szPortName
, GetLastError());
181 int SetParallelState(INT nPortNum
)
183 WCHAR szPortName
[MAX_PORTNAME_LEN
];
184 WCHAR szTargetPath
[MAX_PORTNAME_LEN
];
186 swprintf(szPortName
, L
"LPT%d", nPortNum
);
187 swprintf(szTargetPath
, L
"COM%d", nPortNum
);
188 if (!DefineDosDeviceW(DDD_REMOVE_DEFINITION
, szPortName
, szTargetPath
))
190 ConPrintf(StdErr
, L
"SetParallelState(%d) - DefineDosDevice(%s) failed: 0x%lx\n", nPortNum
, szPortName
, GetLastError());
193 ShowParallelStatus(nPortNum
);
199 ParseNumber(PCWSTR argStr
, PDWORD Number
)
203 value
= swscanf(argStr
, L
"%lu%n", Number
, &skip
);
204 if (!value
) return NULL
;
212 \Device\NamedPipe\Spooler\LPT1
213 BOOL DefineDosDevice(
214 DWORD dwFlags, // options
215 LPCTSTR lpDeviceName, // device name
216 LPCTSTR lpTargetPath // path string
218 DWORD QueryDosDevice(
219 LPCTSTR lpDeviceName, // MS-DOS device name string
220 LPTSTR lpTargetPath, // query results buffer
221 DWORD ucchMax // maximum size of buffer
226 /*****************************************************************************\
227 ** C O N S O L E H E L P E R S **
228 \*****************************************************************************/
230 int ShowConsoleStatus(VOID
)
232 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
233 CONSOLE_SCREEN_BUFFER_INFO csbi
;
234 DWORD dwKbdDelay
, dwKbdSpeed
;
236 ConPuts(StdOut
, L
"\n");
237 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, L
"CON");
238 ConPuts(StdOut
, L
"\n");
240 if (GetConsoleScreenBufferInfo(hConOut
, &csbi
))
242 ConResPrintf(StdOut
, IDS_CONSOLE_STATUS_LINES
, csbi
.dwSize
.Y
);
243 ConResPrintf(StdOut
, IDS_CONSOLE_STATUS_COLS
, csbi
.dwSize
.X
);
245 if (SystemParametersInfoW(SPI_GETKEYBOARDSPEED
, 0, &dwKbdSpeed
, 0))
247 ConResPrintf(StdOut
, IDS_CONSOLE_KBD_RATE
, dwKbdSpeed
);
249 if (SystemParametersInfoW(SPI_GETKEYBOARDDELAY
, 0, &dwKbdDelay
, 0))
251 ConResPrintf(StdOut
, IDS_CONSOLE_KBD_DELAY
, dwKbdDelay
);
253 ConResPrintf(StdOut
, IDS_CONSOLE_CODEPAGE
, GetConsoleOutputCP());
257 int ShowConsoleCPStatus(VOID
)
259 ConPuts(StdOut
, L
"\n");
260 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, L
"CON");
261 ConPuts(StdOut
, L
"\n");
263 ConResPrintf(StdOut
, IDS_CONSOLE_CODEPAGE
, GetConsoleOutputCP());
270 IN PCONSOLE_SCREEN_BUFFER_INFO pcsbi
)
277 FillConsoleOutputAttribute(hConOut
, pcsbi
->wAttributes
,
278 pcsbi
->dwSize
.X
* pcsbi
->dwSize
.Y
,
280 FillConsoleOutputCharacterW(hConOut
, L
' ',
281 pcsbi
->dwSize
.X
* pcsbi
->dwSize
.Y
,
283 SetConsoleCursorPosition(hConOut
, coPos
);
287 * See, or adjust if needed, subsystems/mvdm/ntvdm/console/video.c!ResizeTextConsole()
288 * for more information.
293 IN OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi
,
301 * Use this trick to effectively resize the console buffer and window,
303 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
304 * is smaller than the current console window size, and:
305 * - SetConsoleWindowInfo fails if the new console window size is larger
306 * than the current console screen buffer size.
309 /* Resize the screen buffer only if needed */
310 if (Resolution
.X
!= pcsbi
->dwSize
.X
|| Resolution
.Y
!= pcsbi
->dwSize
.Y
)
312 Width
= pcsbi
->srWindow
.Right
- pcsbi
->srWindow
.Left
+ 1;
313 Height
= pcsbi
->srWindow
.Bottom
- pcsbi
->srWindow
.Top
+ 1;
316 * If the current console window is too large for
317 * the new screen buffer, resize it first.
319 if (Width
> Resolution
.X
|| Height
> Resolution
.Y
)
322 * NOTE: This is not a problem if we move the window back to (0,0)
323 * because when we resize the screen buffer, the window will move back
324 * to where the cursor is. Or, if the screen buffer is not resized,
325 * when we readjust again the window, we will move back to a correct
326 * position. This is what we wanted after all...
328 ConRect
.Left
= ConRect
.Top
= 0;
329 ConRect
.Right
= ConRect
.Left
+ min(Width
, Resolution
.X
) - 1;
330 ConRect
.Bottom
= ConRect
.Top
+ min(Height
, Resolution
.Y
) - 1;
332 Success
= SetConsoleWindowInfo(hConOut
, TRUE
, &ConRect
);
333 if (!Success
) return FALSE
;
337 * Now resize the screen buffer.
339 * SetConsoleScreenBufferSize automatically takes into account the current
340 * cursor position when it computes starting which row it should copy text
341 * when resizing the screen buffer, and scrolls the console window such that
342 * the cursor is placed in it again. We therefore do not need to care about
343 * the cursor position and do the maths ourselves.
345 Success
= SetConsoleScreenBufferSize(hConOut
, Resolution
);
346 if (!Success
) return FALSE
;
349 * Setting a new screen buffer size can change other information,
350 * so update the console screen buffer information.
352 GetConsoleScreenBufferInfo(hConOut
, pcsbi
);
355 /* Always resize the console window within the permitted maximum size */
356 Width
= min(Resolution
.X
, pcsbi
->dwMaximumWindowSize
.X
);
357 Height
= min(Resolution
.Y
, pcsbi
->dwMaximumWindowSize
.Y
);
359 ConRect
.Right
= ConRect
.Left
+ Width
- 1;
360 ConRect
.Bottom
= max(pcsbi
->dwCursorPosition
.Y
, Height
- 1);
361 ConRect
.Top
= ConRect
.Bottom
- Height
+ 1;
363 SetConsoleWindowInfo(hConOut
, TRUE
, &ConRect
);
365 /* Update the console screen buffer information */
366 GetConsoleScreenBufferInfo(hConOut
, pcsbi
);
370 int SetConsoleStateOld(IN PCWSTR ArgStr
)
372 PCWSTR argStr
= ArgStr
;
374 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
375 CONSOLE_SCREEN_BUFFER_INFO csbi
;
379 if (!GetConsoleScreenBufferInfo(hConOut
, &csbi
))
381 // TODO: Error message?
385 Resolution
= csbi
.dwSize
;
387 /* Parse the column number (only MANDATORY argument) */
389 argStr
= ParseNumber(argStr
, &value
);
390 if (!argStr
) goto invalid_parameter
;
391 Resolution
.X
= (SHORT
)value
;
393 /* Parse the line number (OPTIONAL argument) */
394 while (*argStr
== L
' ') argStr
++;
395 if (!*argStr
) goto Quit
;
396 if (*argStr
++ != L
',') goto invalid_parameter
;
397 while (*argStr
== L
' ') argStr
++;
400 argStr
= ParseNumber(argStr
, &value
);
401 if (!argStr
) goto invalid_parameter
;
402 Resolution
.Y
= (SHORT
)value
;
404 /* This should be the end of the string */
405 while (*argStr
== L
' ') argStr
++;
406 if (*argStr
) goto invalid_parameter
;
409 ClearScreen(hConOut
, &csbi
);
410 if (!ResizeTextConsole(hConOut
, &csbi
, Resolution
))
411 ConPuts(StdErr
, L
"The screen cannot be set to the number of lines and columns specified.\n");
416 ConPrintf(StdErr
, L
"Invalid parameter - %s\n", ArgStr
);
420 int SetConsoleState(IN PCWSTR ArgStr
)
422 PCWSTR argStr
= ArgStr
;
423 BOOL dispMode
= FALSE
, kbdMode
= FALSE
;
425 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
426 CONSOLE_SCREEN_BUFFER_INFO csbi
;
428 DWORD dwKbdDelay
, dwKbdSpeed
;
431 if (!GetConsoleScreenBufferInfo(hConOut
, &csbi
))
433 // TODO: Error message?
436 if (!SystemParametersInfoW(SPI_GETKEYBOARDDELAY
, 0, &dwKbdDelay
, 0))
438 // TODO: Error message?
441 if (!SystemParametersInfoW(SPI_GETKEYBOARDSPEED
, 0, &dwKbdSpeed
, 0))
443 // TODO: Error message?
447 Resolution
= csbi
.dwSize
;
449 while (argStr
&& *argStr
)
451 while (*argStr
== L
' ') argStr
++;
454 if (!kbdMode
&& _wcsnicmp(argStr
, L
"COLS=", 5) == 0)
459 argStr
= ParseNumber(argStr
+5, &value
);
460 if (!argStr
) goto invalid_parameter
;
461 Resolution
.X
= (SHORT
)value
;
463 else if (!kbdMode
&& _wcsnicmp(argStr
, L
"LINES=", 6) == 0)
468 argStr
= ParseNumber(argStr
+6, &value
);
469 if (!argStr
) goto invalid_parameter
;
470 Resolution
.Y
= (SHORT
)value
;
472 else if (!dispMode
&& _wcsnicmp(argStr
, L
"RATE=", 5) == 0)
476 argStr
= ParseNumber(argStr
+5, &dwKbdSpeed
);
477 if (!argStr
) goto invalid_parameter
;
479 else if (!dispMode
&& _wcsnicmp(argStr
, L
"DELAY=", 6) == 0)
483 argStr
= ParseNumber(argStr
+6, &dwKbdDelay
);
484 if (!argStr
) goto invalid_parameter
;
489 ConPrintf(StdErr
, L
"Invalid parameter - %s\n", ArgStr
);
496 ClearScreen(hConOut
, &csbi
);
497 if (!ResizeTextConsole(hConOut
, &csbi
, Resolution
))
498 ConPuts(StdErr
, L
"The screen cannot be set to the number of lines and columns specified.\n");
503 * Set the new keyboard settings. If those values are greater than
504 * their allowed range, they are automatically corrected as follows:
505 * dwKbdSpeed = min(dwKbdSpeed, 31);
506 * dwKbdDelay = (dwKbdDelay % 4);
508 SystemParametersInfoW(SPI_SETKEYBOARDDELAY
, dwKbdDelay
, NULL
, 0);
509 // "Invalid keyboard delay."
510 SystemParametersInfoW(SPI_SETKEYBOARDSPEED
, dwKbdSpeed
, NULL
, SPIF_UPDATEINIFILE
| SPIF_SENDCHANGE
);
511 // "Invalid keyboard rate."
517 int SetConsoleCPState(IN PCWSTR ArgStr
)
519 PCWSTR argStr
= ArgStr
;
522 if ( (_wcsnicmp(argStr
, L
"SELECT=", 7) == 0 && (argStr
+= 7)) ||
523 (_wcsnicmp(argStr
, L
"SEL=", 4) == 0 && (argStr
+= 4)) )
525 argStr
= ParseNumber(argStr
, &CodePage
);
526 if (!argStr
) goto invalid_parameter
;
528 /* This should be the end of the string */
529 while (*argStr
== L
' ') argStr
++;
530 if (*argStr
) goto invalid_parameter
;
532 SetConsoleCP(CodePage
);
533 SetConsoleOutputCP(CodePage
);
534 // "The code page specified is not valid."
535 ShowConsoleCPStatus();
540 ConPrintf(StdErr
, L
"Invalid parameter - %s\n", ArgStr
);
548 /*****************************************************************************\
549 ** S E R I A L P O R T H E L P E R S **
550 \*****************************************************************************/
553 SerialPortQuery(INT nPortNum
, LPDCB pDCB
, LPCOMMTIMEOUTS pCommTimeouts
, BOOL bWrite
)
557 WCHAR szPortName
[MAX_PORTNAME_LEN
];
560 ASSERT(pCommTimeouts
);
562 swprintf(szPortName
, L
"COM%d", nPortNum
);
563 hPort
= CreateFileW(szPortName
,
564 bWrite
? GENERIC_WRITE
: GENERIC_READ
,
569 NULL
); // no template
571 if (hPort
== INVALID_HANDLE_VALUE
)
573 ConPrintf(StdErr
, L
"Illegal device name - %s\n", szPortName
);
574 ConPrintf(StdErr
, L
"Last error = 0x%lx\n", GetLastError());
578 Success
= bWrite
? SetCommState(hPort
, pDCB
)
579 : GetCommState(hPort
, pDCB
);
582 ConPrintf(StdErr
, L
"Failed to %s the status for device COM%d:\n", bWrite
? L
"set" : L
"get", nPortNum
);
586 Success
= bWrite
? SetCommTimeouts(hPort
, pCommTimeouts
)
587 : GetCommTimeouts(hPort
, pCommTimeouts
);
590 ConPrintf(StdErr
, L
"Failed to %s timeout status for device COM%d:\n", bWrite
? L
"set" : L
"get", nPortNum
);
599 int ShowSerialStatus(INT nPortNum
)
601 static const LPCWSTR parity_strings
[] =
605 L
"Even", // EVENPARITY
606 L
"Mark", // MARKPARITY
607 L
"Space" // SPACEPARITY
609 static const LPCWSTR control_strings
[] = { L
"OFF", L
"ON", L
"HANDSHAKE", L
"TOGGLE" };
610 static const LPCWSTR stopbit_strings
[] = { L
"1", L
"1.5", L
"2" };
613 COMMTIMEOUTS CommTimeouts
;
614 WCHAR szPortName
[MAX_PORTNAME_LEN
];
616 if (!SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, FALSE
))
620 if (dcb
.Parity
>= ARRAYSIZE(parity_strings
))
622 ConPrintf(StdErr
, L
"ERROR: Invalid value for Parity Bits %d:\n", dcb
.Parity
);
625 if (dcb
.StopBits
>= ARRAYSIZE(stopbit_strings
))
627 ConPrintf(StdErr
, L
"ERROR: Invalid value for Stop Bits %d:\n", dcb
.StopBits
);
631 swprintf(szPortName
, L
"COM%d", nPortNum
);
633 ConPuts(StdOut
, L
"\n");
634 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, szPortName
);
635 ConPuts(StdOut
, L
"\n");
637 ConResPrintf(StdOut
, IDS_COM_STATUS_BAUD
, dcb
.BaudRate
);
638 ConResPrintf(StdOut
, IDS_COM_STATUS_PARITY
, parity_strings
[dcb
.Parity
]);
639 ConResPrintf(StdOut
, IDS_COM_STATUS_DATA_BITS
, dcb
.ByteSize
);
640 ConResPrintf(StdOut
, IDS_COM_STATUS_STOP_BITS
, stopbit_strings
[dcb
.StopBits
]);
641 ConResPrintf(StdOut
, IDS_COM_STATUS_TIMEOUT
,
642 control_strings
[(CommTimeouts
.ReadTotalTimeoutConstant
!= 0) ||
643 (CommTimeouts
.WriteTotalTimeoutConstant
!= 0) ? 1 : 0]);
644 ConResPrintf(StdOut
, IDS_COM_STATUS_XON_XOFF
,
645 control_strings
[dcb
.fOutX
? 1 : 0]);
646 ConResPrintf(StdOut
, IDS_COM_STATUS_CTS_HANDSHAKING
,
647 control_strings
[dcb
.fOutxCtsFlow
? 1 : 0]);
648 ConResPrintf(StdOut
, IDS_COM_STATUS_DSR_HANDSHAKING
,
649 control_strings
[dcb
.fOutxDsrFlow
? 1 : 0]);
650 ConResPrintf(StdOut
, IDS_COM_STATUS_DSR_SENSITIVITY
,
651 control_strings
[dcb
.fDsrSensitivity
? 1 : 0]);
652 ConResPrintf(StdOut
, IDS_COM_STATUS_DTR_CIRCUIT
, control_strings
[dcb
.fDtrControl
]);
653 ConResPrintf(StdOut
, IDS_COM_STATUS_RTS_CIRCUIT
, control_strings
[dcb
.fRtsControl
]);
659 * Those procedures are inspired from Wine's dll/win32/kernel32/wine/comm.c
660 * Copyright 1996 Erik Bos and Marcus Meissner.
664 ParseModes(PCWSTR argStr
, PBYTE Mode
)
666 if (_wcsnicmp(argStr
, L
"OFF", 3) == 0)
671 else if (_wcsnicmp(argStr
, L
"ON", 2) == 0)
676 else if (_wcsnicmp(argStr
, L
"HS", 2) == 0)
681 else if (_wcsnicmp(argStr
, L
"TG", 2) == 0)
691 ParseBaudRate(PCWSTR argStr
, PDWORD BaudRate
)
693 argStr
= ParseNumber(argStr
, BaudRate
);
694 if (!argStr
) return NULL
;
697 * Check for Baud Rate abbreviations. This means that using
698 * those values as real baud rates is impossible using MODE.
702 /* BaudRate = 110, 150, 300, 600 */
703 case 11: case 15: case 30: case 60:
707 /* BaudRate = 1200, 2400, 4800, 9600 */
708 case 12: case 24: case 48: case 96:
721 ParseParity(PCWSTR argStr
, PBYTE Parity
)
723 switch (towupper(*argStr
++))
734 *Parity
= EVENPARITY
;
738 *Parity
= MARKPARITY
;
742 *Parity
= SPACEPARITY
;
753 ParseByteSize(PCWSTR argStr
, PBYTE ByteSize
)
757 argStr
= ParseNumber(argStr
, &value
);
758 if (!argStr
) return NULL
;
760 *ByteSize
= (BYTE
)value
;
761 if (*ByteSize
< 5 || *ByteSize
> 8)
768 ParseStopBits(PCWSTR argStr
, PBYTE StopBits
)
770 if (_wcsnicmp(argStr
, L
"1.5", 3) == 0)
773 *StopBits
= ONE5STOPBITS
;
778 *StopBits
= ONESTOPBIT
;
779 else if (*argStr
== L
'2')
780 *StopBits
= TWOSTOPBITS
;
791 * Build a DCB using the old style settings string eg: "96,n,8,1"
793 * See dll/win32/kernel32/wine/comm.c!COMM_BuildOldCommDCB()
794 * for more information.
801 PCWSTR argStr
= ArgStr
;
805 * Parse the baud rate (only MANDATORY argument)
807 argStr
= ParseBaudRate(argStr
, &pDCB
->BaudRate
);
808 if (!argStr
) return FALSE
;
812 * Now parse the rest (OPTIONAL arguments)
815 while (*argStr
== L
' ') argStr
++;
816 if (!*argStr
) goto Quit
;
817 if (*argStr
++ != L
',') return FALSE
;
818 while (*argStr
== L
' ') argStr
++;
819 if (!*argStr
) goto Quit
;
821 /* Parse the parity */
822 // Default: EVENPARITY
823 pDCB
->Parity
= EVENPARITY
;
826 argStr
= ParseParity(argStr
, &pDCB
->Parity
);
827 if (!argStr
) return FALSE
;
830 while (*argStr
== L
' ') argStr
++;
831 if (!*argStr
) goto Quit
;
832 if (*argStr
++ != L
',') return FALSE
;
833 while (*argStr
== L
' ') argStr
++;
834 if (!*argStr
) goto Quit
;
836 /* Parse the data bits */
841 argStr
= ParseByteSize(argStr
, &pDCB
->ByteSize
);
842 if (!argStr
) return FALSE
;
845 while (*argStr
== L
' ') argStr
++;
846 if (!*argStr
) goto Quit
;
847 if (*argStr
++ != L
',') return FALSE
;
848 while (*argStr
== L
' ') argStr
++;
849 if (!*argStr
) goto Quit
;
851 /* Parse the stop bits */
852 // Default: 1, or 2 for BAUD=110
853 // pDCB->StopBits = ONESTOPBIT;
857 argStr
= ParseStopBits(argStr
, &pDCB
->StopBits
);
858 if (!argStr
) return FALSE
;
861 /* The last parameter (flow control "retry") is really optional */
862 while (*argStr
== L
' ') argStr
++;
863 if (!*argStr
) goto Quit
;
864 if (*argStr
++ != L
',') return FALSE
;
865 while (*argStr
== L
' ') argStr
++;
866 if (!*argStr
) goto Quit
;
869 switch (towupper(*argStr
))
874 pDCB
->fOutxCtsFlow
= FALSE
;
875 pDCB
->fOutxDsrFlow
= FALSE
;
876 pDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
877 pDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
883 pDCB
->fOutxCtsFlow
= FALSE
;
884 pDCB
->fOutxDsrFlow
= FALSE
;
885 pDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
886 pDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
892 pDCB
->fOutxCtsFlow
= TRUE
;
893 pDCB
->fOutxDsrFlow
= TRUE
;
894 pDCB
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
895 pDCB
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
902 if (*argStr
) argStr
++;
904 /* This should be the end of the string */
905 while (*argStr
== L
' ') argStr
++;
906 if (*argStr
) return FALSE
;
908 /* If stop bits were not specified, a default is always supplied */
911 if (pDCB
->BaudRate
== 110)
912 pDCB
->StopBits
= TWOSTOPBITS
;
914 pDCB
->StopBits
= ONESTOPBIT
;
920 * Build a DCB using the new style settings string.
921 * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
923 * See dll/win32/kernel32/wine/comm.c!COMM_BuildNewCommDCB()
924 * for more information.
929 OUT LPCOMMTIMEOUTS pCommTimeouts
,
932 PCWSTR argStr
= ArgStr
;
933 BOOL baud
= FALSE
, stop
= FALSE
;
936 while (argStr
&& *argStr
)
938 while (*argStr
== L
' ') argStr
++;
941 if (_wcsnicmp(argStr
, L
"BAUD=", 5) == 0)
944 argStr
= ParseBaudRate(argStr
+5, &pDCB
->BaudRate
);
945 if (!argStr
) return FALSE
;
947 else if (_wcsnicmp(argStr
, L
"PARITY=", 7) == 0)
949 // Default: EVENPARITY
950 argStr
= ParseParity(argStr
+7, &pDCB
->Parity
);
951 if (!argStr
) return FALSE
;
953 else if (_wcsnicmp(argStr
, L
"DATA=", 5) == 0)
956 argStr
= ParseByteSize(argStr
+5, &pDCB
->ByteSize
);
957 if (!argStr
) return FALSE
;
959 else if (_wcsnicmp(argStr
, L
"STOP=", 5) == 0)
961 // Default: 1, or 2 for BAUD=110
963 argStr
= ParseStopBits(argStr
+5, &pDCB
->StopBits
);
964 if (!argStr
) return FALSE
;
966 else if (_wcsnicmp(argStr
, L
"TO=", 3) == 0) // TO=ON|OFF
968 /* Only total time-outs are get/set by Windows' MODE.COM */
969 argStr
= ParseModes(argStr
+3, &value
);
970 if (!argStr
) return FALSE
;
971 if (value
== 0) // OFF
973 pCommTimeouts
->ReadTotalTimeoutConstant
= 0;
974 pCommTimeouts
->WriteTotalTimeoutConstant
= 0;
976 else if (value
== 1) // ON
978 pCommTimeouts
->ReadTotalTimeoutConstant
= 60000;
979 pCommTimeouts
->WriteTotalTimeoutConstant
= 60000;
986 else if (_wcsnicmp(argStr
, L
"XON=", 4) == 0) // XON=ON|OFF
988 argStr
= ParseModes(argStr
+4, &value
);
989 if (!argStr
) return FALSE
;
990 if ((value
== 0) || (value
== 1))
1000 else if (_wcsnicmp(argStr
, L
"ODSR=", 5) == 0) // ODSR=ON|OFF
1003 argStr
= ParseModes(argStr
+5, &value
);
1004 if (!argStr
) return FALSE
;
1005 if ((value
== 0) || (value
== 1))
1006 pDCB
->fOutxDsrFlow
= value
;
1010 else if (_wcsnicmp(argStr
, L
"OCTS=", 5) == 0) // OCTS=ON|OFF
1013 argStr
= ParseModes(argStr
+5, &value
);
1014 if (!argStr
) return FALSE
;
1015 if ((value
== 0) || (value
== 1))
1016 pDCB
->fOutxCtsFlow
= value
;
1020 else if (_wcsnicmp(argStr
, L
"DTR=", 4) == 0) // DTR=ON|OFF|HS
1023 argStr
= ParseModes(argStr
+4, &value
);
1024 if (!argStr
) return FALSE
;
1025 if ((value
== 0) || (value
== 1) || (value
== 2))
1026 pDCB
->fDtrControl
= value
;
1030 else if (_wcsnicmp(argStr
, L
"RTS=", 4) == 0) // RTS=ON|OFF|HS|TG
1033 argStr
= ParseModes(argStr
+4, &value
);
1034 if (!argStr
) return FALSE
;
1035 if ((value
== 0) || (value
== 1) || (value
== 2) || (value
== 3))
1036 pDCB
->fRtsControl
= value
;
1040 else if (_wcsnicmp(argStr
, L
"IDSR=", 5) == 0) // IDSR=ON|OFF
1043 argStr
= ParseModes(argStr
+5, &value
);
1044 if (!argStr
) return FALSE
;
1045 if ((value
== 0) || (value
== 1))
1046 pDCB
->fDsrSensitivity
= value
;
1056 /* If stop bits were not specified, a default is always supplied */
1059 if (baud
&& pDCB
->BaudRate
== 110)
1060 pDCB
->StopBits
= TWOSTOPBITS
;
1062 pDCB
->StopBits
= ONESTOPBIT
;
1067 int SetSerialState(INT nPortNum
, IN PCWSTR ArgStr
)
1071 COMMTIMEOUTS CommTimeouts
;
1073 if (!SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, FALSE
))
1075 // TODO: Error message?
1080 * Check whether we should use the old or the new MODE syntax:
1081 * in the old syntax, the separators are both spaces and commas.
1083 if (wcschr(ArgStr
, L
','))
1084 Success
= BuildOldCommDCB(&dcb
, ArgStr
);
1086 Success
= BuildNewCommDCB(&dcb
, &CommTimeouts
, ArgStr
);
1090 ConPrintf(StdErr
, L
"Invalid parameter - %s\n", ArgStr
);
1094 SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, TRUE
);
1095 ShowSerialStatus(nPortNum
);
1101 /*****************************************************************************\
1102 ** E N T R Y P O I N T **
1103 \*****************************************************************************/
1106 FindPortNum(PCWSTR argStr
, PINT PortNum
)
1110 if (*argStr
>= L
'0' && *argStr
<= L
'9')
1112 *PortNum
= *argStr
- L
'0';
1114 if (*argStr
>= L
'0' && *argStr
<= L
'9')
1117 *PortNum
+= *argStr
- L
'0';
1128 int wmain(int argc
, WCHAR
* argv
[])
1133 PCWSTR ArgStr
, argStr
;
1137 /* Initialize the Console Standard Streams */
1138 ConInitStdStreams();
1141 * MODE.COM has a very peculiar way of parsing its arguments,
1142 * as they can be even not separated by any space. This extreme
1143 * behaviour certainly is present for backwards compatibility
1144 * with the oldest versions of the utility present on MS-DOS.
1146 * For example, such a command:
1147 * "MODE.COM COM1baud=9600parity=ndata=8stop=1xon=onto=on"
1148 * will be correctly understood as:
1149 * "MODE.COM COM1 baud=9600 parity=n data=8 stop=1 xon=on to=on"
1151 * Note also that the "/STATUS" switch is actually really "/STA".
1153 * However we will not use GetCommandLine() because we do not want
1154 * to deal with the prepended application path and try to find
1155 * where the arguments start. Our approach here will consist in
1156 * flattening the arguments vector.
1160 /* Compute the space needed for the new string, and allocate it */
1161 for (arg
= 1; arg
< argc
; arg
++)
1163 ArgStrSize
+= wcslen(argv
[arg
]) + 1; // 1 for space
1165 ArgStr
= HeapAlloc(GetProcessHeap(), 0, (ArgStrSize
+ 1) * sizeof(WCHAR
));
1168 ConPuts(StdErr
, L
"ERROR: Not enough memory\n");
1172 /* Copy the contents and NULL-terminate the string */
1174 for (arg
= 1; arg
< argc
; arg
++)
1176 wcscpy((PWSTR
)argStr
, argv
[arg
]);
1177 argStr
+= wcslen(argv
[arg
]);
1178 *(PWSTR
)argStr
++ = L
' ';
1180 *(PWSTR
)argStr
= L
'\0';
1182 /* Parse the command line */
1185 while (*argStr
== L
' ') argStr
++;
1186 if (!*argStr
) goto show_status
;
1188 if (wcsstr(argStr
, L
"/?") || wcsstr(argStr
, L
"-?"))
1190 ConResPuts(StdOut
, IDS_USAGE
);
1193 else if (_wcsnicmp(argStr
, L
"/STA", 4) == 0)
1195 /* Skip this parameter */
1196 while (*argStr
!= L
' ') argStr
++;
1197 /* Skip any delimiter */
1198 while (*argStr
== L
' ') argStr
++;
1200 /* The presence of any other parameter is invalid */
1202 goto invalid_parameter
;
1206 else if (_wcsnicmp(argStr
, L
"LPT", 3) == 0)
1208 argStr
= FindPortNum(argStr
+3, &nPortNum
);
1209 if (!argStr
|| nPortNum
== -1)
1210 goto invalid_parameter
;
1212 if (*argStr
== L
':') argStr
++;
1213 while (*argStr
== L
' ') argStr
++;
1215 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1216 ret
= ShowParallelStatus(nPortNum
);
1218 ConPuts(StdErr
, L
"ERROR: LPT port redirection is not implemented!\n");
1219 // TODO: Implement setting LPT port redirection using SetParallelState().
1222 else if (_wcsnicmp(argStr
, L
"COM", 3) == 0)
1224 argStr
= FindPortNum(argStr
+3, &nPortNum
);
1225 if (!argStr
|| nPortNum
== -1)
1226 goto invalid_parameter
;
1228 if (*argStr
== L
':') argStr
++;
1229 while (*argStr
== L
' ') argStr
++;
1231 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1232 ret
= ShowSerialStatus(nPortNum
);
1234 ret
= SetSerialState(nPortNum
, argStr
);
1237 else if (_wcsnicmp(argStr
, L
"CON", 3) == 0)
1241 if (*argStr
== L
':') argStr
++;
1242 while (*argStr
== L
' ') argStr
++;
1244 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1246 ret
= ShowConsoleStatus();
1248 else if ( (_wcsnicmp(argStr
, L
"CP", 2) == 0 && (argStr
+= 2)) ||
1249 (_wcsnicmp(argStr
, L
"CODEPAGE", 8) == 0 && (argStr
+= 8)) )
1251 while (*argStr
== L
' ') argStr
++;
1253 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1254 ret
= ShowConsoleCPStatus();
1256 ret
= SetConsoleCPState(argStr
);
1260 ret
= SetConsoleState(argStr
);
1264 // else if (wcschr(argStr, L','))
1267 /* Old syntax: MODE [COLS],[LINES] */
1268 ret
= SetConsoleStateOld(argStr
);
1275 ShowParallelStatus(1);
1276 for (nPortNum = 0; nPortNum < MAX_COMPORT_NUM; nPortNum++)
1278 ShowSerialStatus(nPortNum + 1);
1280 ShowConsoleStatus();
1285 ConPrintf(StdErr
, L
"Invalid parameter - %s\n", ArgStr
);
1289 /* Free the string and quit */
1290 HeapFree(GetProcessHeap(), 0, (PWSTR
)ArgStr
);