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 // FIXME: Use ConStreamWrite instead.
73 ConPuts(Stream
, szMsgBuffer
);
78 int QueryDevices(VOID
)
84 // FIXME: Dynamically allocate 'buffer' in a loop.
85 if (QueryDosDeviceW(NULL
, buffer
, ARRAYSIZE(buffer
)))
89 if (wcsstr(ptr
, L
"COM"))
91 ConResPrintf(StdOut
, IDS_QUERY_SERIAL_FOUND
, ptr
);
93 else if (wcsstr(ptr
, L
"PRN"))
95 ConResPrintf(StdOut
, IDS_QUERY_PRINTER_FOUND
, ptr
);
97 else if (wcsstr(ptr
, L
"LPT"))
99 ConResPrintf(StdOut
, IDS_QUERY_PARALLEL_FOUND
, ptr
);
101 else if (wcsstr(ptr
, L
"AUX") || wcsstr(ptr
, L
"NUL"))
103 ConResPrintf(StdOut
, IDS_QUERY_DOSDEV_FOUND
, ptr
);
107 // ConResPrintf(StdOut, IDS_QUERY_MISC_FOUND, ptr);
109 ptr
+= (wcslen(ptr
) + 1);
114 wprintf(L
"ERROR: QueryDosDeviceW(...) failed: 0x%lx\n", GetLastError());
119 int ShowParallelStatus(INT nPortNum
)
122 WCHAR szPortName
[MAX_PORTNAME_LEN
];
124 swprintf(szPortName
, L
"LPT%d", nPortNum
);
126 ConPuts(StdOut
, L
"\n");
127 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, szPortName
);
128 ConPuts(StdOut
, L
"\n");
130 if (QueryDosDeviceW(szPortName
, buffer
, ARRAYSIZE(buffer
)))
132 WCHAR
* ptr
= wcsrchr(buffer
, L
'\\');
135 if (_wcsicmp(szPortName
, ++ptr
) == 0)
136 ConResPuts(StdOut
, IDS_PRINTER_OUTPUT_NOT_REROUTED
);
138 ConResPrintf(StdOut
, IDS_PRINTER_OUTPUT_REROUTED_SERIAL
, ptr
);
144 wprintf(L
" QueryDosDeviceW(%s) returned unrecognised form %s.\n", szPortName
, buffer
);
149 wprintf(L
"ERROR: QueryDosDeviceW(%s) failed: 0x%lx\n", szPortName
, GetLastError());
155 int SetParallelState(INT nPortNum
)
157 WCHAR szPortName
[MAX_PORTNAME_LEN
];
158 WCHAR szTargetPath
[MAX_PORTNAME_LEN
];
160 swprintf(szPortName
, L
"LPT%d", nPortNum
);
161 swprintf(szTargetPath
, L
"COM%d", nPortNum
);
162 if (!DefineDosDeviceW(DDD_REMOVE_DEFINITION
, szPortName
, szTargetPath
))
164 wprintf(L
"SetParallelState(%d) - DefineDosDevice(%s) failed: 0x%lx\n", nPortNum
, szPortName
, GetLastError());
167 ShowParallelStatus(nPortNum
);
173 ParseNumber(PCWSTR argStr
, PDWORD Number
)
177 value
= swscanf(argStr
, L
"%lu%n", Number
, &skip
);
178 if (!value
) return NULL
;
186 \Device\NamedPipe\Spooler\LPT1
187 BOOL DefineDosDevice(
188 DWORD dwFlags, // options
189 LPCTSTR lpDeviceName, // device name
190 LPCTSTR lpTargetPath // path string
192 DWORD QueryDosDevice(
193 LPCTSTR lpDeviceName, // MS-DOS device name string
194 LPTSTR lpTargetPath, // query results buffer
195 DWORD ucchMax // maximum size of buffer
200 /*****************************************************************************\
201 ** C O N S O L E H E L P E R S **
202 \*****************************************************************************/
204 int ShowConsoleStatus(VOID
)
206 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
207 CONSOLE_SCREEN_BUFFER_INFO csbi
;
208 DWORD dwKbdDelay
, dwKbdSpeed
;
210 ConPuts(StdOut
, L
"\n");
211 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, L
"CON");
212 ConPuts(StdOut
, L
"\n");
214 if (GetConsoleScreenBufferInfo(hConOut
, &csbi
))
216 ConResPrintf(StdOut
, IDS_CONSOLE_STATUS_LINES
, csbi
.dwSize
.Y
);
217 ConResPrintf(StdOut
, IDS_CONSOLE_STATUS_COLS
, csbi
.dwSize
.X
);
219 if (SystemParametersInfoW(SPI_GETKEYBOARDSPEED
, 0, &dwKbdSpeed
, 0))
221 ConResPrintf(StdOut
, IDS_CONSOLE_KBD_RATE
, dwKbdSpeed
);
223 if (SystemParametersInfoW(SPI_GETKEYBOARDDELAY
, 0, &dwKbdDelay
, 0))
225 ConResPrintf(StdOut
, IDS_CONSOLE_KBD_DELAY
, dwKbdDelay
);
227 ConResPrintf(StdOut
, IDS_CONSOLE_CODEPAGE
, GetConsoleOutputCP());
231 int ShowConsoleCPStatus(VOID
)
233 ConPuts(StdOut
, L
"\n");
234 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, L
"CON");
235 ConPuts(StdOut
, L
"\n");
237 ConResPrintf(StdOut
, IDS_CONSOLE_CODEPAGE
, GetConsoleOutputCP());
244 IN PCONSOLE_SCREEN_BUFFER_INFO pcsbi
)
251 FillConsoleOutputAttribute(hConOut
, pcsbi
->wAttributes
,
252 pcsbi
->dwSize
.X
* pcsbi
->dwSize
.Y
,
254 FillConsoleOutputCharacterW(hConOut
, L
' ',
255 pcsbi
->dwSize
.X
* pcsbi
->dwSize
.Y
,
257 SetConsoleCursorPosition(hConOut
, coPos
);
261 * See, or adjust if needed, subsystems/mvdm/ntvdm/console/video.c!ResizeTextConsole()
262 * for more information.
267 IN OUT PCONSOLE_SCREEN_BUFFER_INFO pcsbi
,
275 * Use this trick to effectively resize the console buffer and window,
277 * - SetConsoleScreenBufferSize fails if the new console screen buffer size
278 * is smaller than the current console window size, and:
279 * - SetConsoleWindowInfo fails if the new console window size is larger
280 * than the current console screen buffer size.
283 /* Resize the screen buffer only if needed */
284 if (Resolution
.X
!= pcsbi
->dwSize
.X
|| Resolution
.Y
!= pcsbi
->dwSize
.Y
)
286 Width
= pcsbi
->srWindow
.Right
- pcsbi
->srWindow
.Left
+ 1;
287 Height
= pcsbi
->srWindow
.Bottom
- pcsbi
->srWindow
.Top
+ 1;
290 * If the current console window is too large for
291 * the new screen buffer, resize it first.
293 if (Width
> Resolution
.X
|| Height
> Resolution
.Y
)
296 * NOTE: This is not a problem if we move the window back to (0,0)
297 * because when we resize the screen buffer, the window will move back
298 * to where the cursor is. Or, if the screen buffer is not resized,
299 * when we readjust again the window, we will move back to a correct
300 * position. This is what we wanted after all...
302 ConRect
.Left
= ConRect
.Top
= 0;
303 ConRect
.Right
= ConRect
.Left
+ min(Width
, Resolution
.X
) - 1;
304 ConRect
.Bottom
= ConRect
.Top
+ min(Height
, Resolution
.Y
) - 1;
306 Success
= SetConsoleWindowInfo(hConOut
, TRUE
, &ConRect
);
307 if (!Success
) return FALSE
;
311 * Now resize the screen buffer.
313 * SetConsoleScreenBufferSize automatically takes into account the current
314 * cursor position when it computes starting which row it should copy text
315 * when resizing the screen buffer, and scrolls the console window such that
316 * the cursor is placed in it again. We therefore do not need to care about
317 * the cursor position and do the maths ourselves.
319 Success
= SetConsoleScreenBufferSize(hConOut
, Resolution
);
320 if (!Success
) return FALSE
;
323 * Setting a new screen buffer size can change other information,
324 * so update the console screen buffer information.
326 GetConsoleScreenBufferInfo(hConOut
, pcsbi
);
329 /* Always resize the console window within the permitted maximum size */
330 Width
= min(Resolution
.X
, pcsbi
->dwMaximumWindowSize
.X
);
331 Height
= min(Resolution
.Y
, pcsbi
->dwMaximumWindowSize
.Y
);
333 ConRect
.Right
= ConRect
.Left
+ Width
- 1;
334 ConRect
.Bottom
= max(pcsbi
->dwCursorPosition
.Y
, Height
- 1);
335 ConRect
.Top
= ConRect
.Bottom
- Height
+ 1;
337 SetConsoleWindowInfo(hConOut
, TRUE
, &ConRect
);
339 /* Update the console screen buffer information */
340 GetConsoleScreenBufferInfo(hConOut
, pcsbi
);
344 int SetConsoleStateOld(IN PCWSTR ArgStr
)
346 PCWSTR argStr
= ArgStr
;
348 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
349 CONSOLE_SCREEN_BUFFER_INFO csbi
;
353 if (!GetConsoleScreenBufferInfo(hConOut
, &csbi
))
355 // TODO: Error message?
359 Resolution
= csbi
.dwSize
;
361 /* Parse the column number (only MANDATORY argument) */
363 argStr
= ParseNumber(argStr
, &value
);
364 if (!argStr
) goto invalid_parameter
;
365 Resolution
.X
= (SHORT
)value
;
367 /* Parse the line number (OPTIONAL argument) */
368 while (*argStr
== L
' ') argStr
++;
369 if (!*argStr
) goto Quit
;
370 if (*argStr
++ != L
',') goto invalid_parameter
;
371 while (*argStr
== L
' ') argStr
++;
374 argStr
= ParseNumber(argStr
, &value
);
375 if (!argStr
) goto invalid_parameter
;
376 Resolution
.Y
= (SHORT
)value
;
378 /* This should be the end of the string */
379 while (*argStr
== L
' ') argStr
++;
380 if (*argStr
) goto invalid_parameter
;
383 ClearScreen(hConOut
, &csbi
);
384 if (!ResizeTextConsole(hConOut
, &csbi
, Resolution
))
385 wprintf(L
"The screen cannot be set to the number of lines and columns specified.\n");
390 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
394 int SetConsoleState(IN PCWSTR ArgStr
)
396 PCWSTR argStr
= ArgStr
;
397 BOOL dispMode
= FALSE
, kbdMode
= FALSE
;
399 HANDLE hConOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
400 CONSOLE_SCREEN_BUFFER_INFO csbi
;
402 DWORD dwKbdDelay
, dwKbdSpeed
;
405 if (!GetConsoleScreenBufferInfo(hConOut
, &csbi
))
407 // TODO: Error message?
410 if (!SystemParametersInfoW(SPI_GETKEYBOARDDELAY
, 0, &dwKbdDelay
, 0))
412 // TODO: Error message?
415 if (!SystemParametersInfoW(SPI_GETKEYBOARDSPEED
, 0, &dwKbdSpeed
, 0))
417 // TODO: Error message?
421 Resolution
= csbi
.dwSize
;
423 while (argStr
&& *argStr
)
425 while (*argStr
== L
' ') argStr
++;
428 if (!kbdMode
&& _wcsnicmp(argStr
, L
"COLS=", 5) == 0)
433 argStr
= ParseNumber(argStr
+5, &value
);
434 if (!argStr
) goto invalid_parameter
;
435 Resolution
.X
= (SHORT
)value
;
437 else if (!kbdMode
&& _wcsnicmp(argStr
, L
"LINES=", 6) == 0)
442 argStr
= ParseNumber(argStr
+6, &value
);
443 if (!argStr
) goto invalid_parameter
;
444 Resolution
.Y
= (SHORT
)value
;
446 else if (!dispMode
&& _wcsnicmp(argStr
, L
"RATE=", 5) == 0)
450 argStr
= ParseNumber(argStr
+5, &dwKbdSpeed
);
451 if (!argStr
) goto invalid_parameter
;
453 else if (!dispMode
&& _wcsnicmp(argStr
, L
"DELAY=", 6) == 0)
457 argStr
= ParseNumber(argStr
+6, &dwKbdDelay
);
458 if (!argStr
) goto invalid_parameter
;
463 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
470 ClearScreen(hConOut
, &csbi
);
471 if (!ResizeTextConsole(hConOut
, &csbi
, Resolution
))
472 wprintf(L
"The screen cannot be set to the number of lines and columns specified.\n");
477 * Set the new keyboard settings. If those values are greater than
478 * their allowed range, they are automatically corrected as follows:
479 * dwKbdSpeed = min(dwKbdSpeed, 31);
480 * dwKbdDelay = (dwKbdDelay % 4);
482 SystemParametersInfoW(SPI_SETKEYBOARDDELAY
, dwKbdDelay
, NULL
, 0);
483 // "Invalid keyboard delay."
484 SystemParametersInfoW(SPI_SETKEYBOARDSPEED
, dwKbdSpeed
, NULL
, SPIF_UPDATEINIFILE
| SPIF_SENDCHANGE
);
485 // "Invalid keyboard rate."
491 int SetConsoleCPState(IN PCWSTR ArgStr
)
493 PCWSTR argStr
= ArgStr
;
496 if ( (_wcsnicmp(argStr
, L
"SELECT=", 7) == 0 && (argStr
+= 7)) ||
497 (_wcsnicmp(argStr
, L
"SEL=", 4) == 0 && (argStr
+= 4)) )
499 argStr
= ParseNumber(argStr
, &CodePage
);
500 if (!argStr
) goto invalid_parameter
;
502 /* This should be the end of the string */
503 while (*argStr
== L
' ') argStr
++;
504 if (*argStr
) goto invalid_parameter
;
506 SetConsoleCP(CodePage
);
507 SetConsoleOutputCP(CodePage
);
508 // "The code page specified is not valid."
509 ShowConsoleCPStatus();
514 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
522 /*****************************************************************************\
523 ** S E R I A L P O R T H E L P E R S **
524 \*****************************************************************************/
527 SerialPortQuery(INT nPortNum
, LPDCB pDCB
, LPCOMMTIMEOUTS pCommTimeouts
, BOOL bWrite
)
531 WCHAR szPortName
[MAX_PORTNAME_LEN
];
534 ASSERT(pCommTimeouts
);
536 swprintf(szPortName
, L
"COM%d", nPortNum
);
537 hPort
= CreateFileW(szPortName
,
538 bWrite
? GENERIC_WRITE
: GENERIC_READ
,
543 NULL
); // no template
545 if (hPort
== INVALID_HANDLE_VALUE
)
547 wprintf(L
"Illegal device name - %s\n", szPortName
);
548 wprintf(L
"Last error = 0x%lx\n", GetLastError());
552 Success
= bWrite
? SetCommState(hPort
, pDCB
)
553 : GetCommState(hPort
, pDCB
);
556 wprintf(L
"Failed to %s the status for device COM%d:\n", bWrite
? L
"set" : L
"get", nPortNum
);
560 Success
= bWrite
? SetCommTimeouts(hPort
, pCommTimeouts
)
561 : GetCommTimeouts(hPort
, pCommTimeouts
);
564 wprintf(L
"Failed to %s timeout status for device COM%d:\n", bWrite
? L
"set" : L
"get", nPortNum
);
573 int ShowSerialStatus(INT nPortNum
)
575 static const LPCWSTR parity_strings
[] =
579 L
"Even", // EVENPARITY
580 L
"Mark", // MARKPARITY
581 L
"Space" // SPACEPARITY
583 static const LPCWSTR control_strings
[] = { L
"OFF", L
"ON", L
"HANDSHAKE", L
"TOGGLE" };
584 static const LPCWSTR stopbit_strings
[] = { L
"1", L
"1.5", L
"2" };
587 COMMTIMEOUTS CommTimeouts
;
588 WCHAR szPortName
[MAX_PORTNAME_LEN
];
590 if (!SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, FALSE
))
594 if (dcb
.Parity
>= ARRAYSIZE(parity_strings
))
596 wprintf(L
"ERROR: Invalid value for Parity Bits %d:\n", dcb
.Parity
);
599 if (dcb
.StopBits
>= ARRAYSIZE(stopbit_strings
))
601 wprintf(L
"ERROR: Invalid value for Stop Bits %d:\n", dcb
.StopBits
);
605 swprintf(szPortName
, L
"COM%d", nPortNum
);
607 ConPuts(StdOut
, L
"\n");
608 UnderlinedResPrintf(StdOut
, IDS_DEVICE_STATUS_HEADER
, szPortName
);
609 ConPuts(StdOut
, L
"\n");
611 ConResPrintf(StdOut
, IDS_COM_STATUS_BAUD
, dcb
.BaudRate
);
612 ConResPrintf(StdOut
, IDS_COM_STATUS_PARITY
, parity_strings
[dcb
.Parity
]);
613 ConResPrintf(StdOut
, IDS_COM_STATUS_DATA_BITS
, dcb
.ByteSize
);
614 ConResPrintf(StdOut
, IDS_COM_STATUS_STOP_BITS
, stopbit_strings
[dcb
.StopBits
]);
615 ConResPrintf(StdOut
, IDS_COM_STATUS_TIMEOUT
,
616 control_strings
[(CommTimeouts
.ReadTotalTimeoutConstant
!= 0) ||
617 (CommTimeouts
.WriteTotalTimeoutConstant
!= 0) ? 1 : 0]);
618 ConResPrintf(StdOut
, IDS_COM_STATUS_XON_XOFF
,
619 control_strings
[dcb
.fOutX
? 1 : 0]);
620 ConResPrintf(StdOut
, IDS_COM_STATUS_CTS_HANDSHAKING
,
621 control_strings
[dcb
.fOutxCtsFlow
? 1 : 0]);
622 ConResPrintf(StdOut
, IDS_COM_STATUS_DSR_HANDSHAKING
,
623 control_strings
[dcb
.fOutxDsrFlow
? 1 : 0]);
624 ConResPrintf(StdOut
, IDS_COM_STATUS_DSR_SENSITIVITY
,
625 control_strings
[dcb
.fDsrSensitivity
? 1 : 0]);
626 ConResPrintf(StdOut
, IDS_COM_STATUS_DTR_CIRCUIT
, control_strings
[dcb
.fDtrControl
]);
627 ConResPrintf(StdOut
, IDS_COM_STATUS_RTS_CIRCUIT
, control_strings
[dcb
.fRtsControl
]);
633 * Those procedures are inspired from Wine's dll/win32/kernel32/wine/comm.c
634 * Copyright 1996 Erik Bos and Marcus Meissner.
638 ParseModes(PCWSTR argStr
, PBYTE Mode
)
640 if (_wcsnicmp(argStr
, L
"OFF", 3) == 0)
645 else if (_wcsnicmp(argStr
, L
"ON", 2) == 0)
650 else if (_wcsnicmp(argStr
, L
"HS", 2) == 0)
655 else if (_wcsnicmp(argStr
, L
"TG", 2) == 0)
665 ParseBaudRate(PCWSTR argStr
, PDWORD BaudRate
)
667 argStr
= ParseNumber(argStr
, BaudRate
);
668 if (!argStr
) return NULL
;
671 * Check for Baud Rate abbreviations. This means that using
672 * those values as real baud rates is impossible using MODE.
676 /* BaudRate = 110, 150, 300, 600 */
677 case 11: case 15: case 30: case 60:
681 /* BaudRate = 1200, 2400, 4800, 9600 */
682 case 12: case 24: case 48: case 96:
695 ParseParity(PCWSTR argStr
, PBYTE Parity
)
697 switch (towupper(*argStr
++))
708 *Parity
= EVENPARITY
;
712 *Parity
= MARKPARITY
;
716 *Parity
= SPACEPARITY
;
727 ParseByteSize(PCWSTR argStr
, PBYTE ByteSize
)
731 argStr
= ParseNumber(argStr
, &value
);
732 if (!argStr
) return NULL
;
734 *ByteSize
= (BYTE
)value
;
735 if (*ByteSize
< 5 || *ByteSize
> 8)
742 ParseStopBits(PCWSTR argStr
, PBYTE StopBits
)
744 if (_wcsnicmp(argStr
, L
"1.5", 3) == 0)
747 *StopBits
= ONE5STOPBITS
;
752 *StopBits
= ONESTOPBIT
;
753 else if (*argStr
== L
'2')
754 *StopBits
= TWOSTOPBITS
;
765 * Build a DCB using the old style settings string eg: "96,n,8,1"
767 * See dll/win32/kernel32/wine/comm.c!COMM_BuildOldCommDCB()
768 * for more information.
775 PCWSTR argStr
= ArgStr
;
779 * Parse the baud rate (only MANDATORY argument)
781 argStr
= ParseBaudRate(argStr
, &pDCB
->BaudRate
);
782 if (!argStr
) return FALSE
;
786 * Now parse the rest (OPTIONAL arguments)
789 while (*argStr
== L
' ') argStr
++;
790 if (!*argStr
) goto Quit
;
791 if (*argStr
++ != L
',') return FALSE
;
792 while (*argStr
== L
' ') argStr
++;
793 if (!*argStr
) goto Quit
;
795 /* Parse the parity */
796 // Default: EVENPARITY
797 pDCB
->Parity
= EVENPARITY
;
800 argStr
= ParseParity(argStr
, &pDCB
->Parity
);
801 if (!argStr
) return FALSE
;
804 while (*argStr
== L
' ') argStr
++;
805 if (!*argStr
) goto Quit
;
806 if (*argStr
++ != L
',') return FALSE
;
807 while (*argStr
== L
' ') argStr
++;
808 if (!*argStr
) goto Quit
;
810 /* Parse the data bits */
815 argStr
= ParseByteSize(argStr
, &pDCB
->ByteSize
);
816 if (!argStr
) return FALSE
;
819 while (*argStr
== L
' ') argStr
++;
820 if (!*argStr
) goto Quit
;
821 if (*argStr
++ != L
',') return FALSE
;
822 while (*argStr
== L
' ') argStr
++;
823 if (!*argStr
) goto Quit
;
825 /* Parse the stop bits */
826 // Default: 1, or 2 for BAUD=110
827 // pDCB->StopBits = ONESTOPBIT;
831 argStr
= ParseStopBits(argStr
, &pDCB
->StopBits
);
832 if (!argStr
) return FALSE
;
835 /* The last parameter (flow control "retry") is really optional */
836 while (*argStr
== L
' ') argStr
++;
837 if (!*argStr
) goto Quit
;
838 if (*argStr
++ != L
',') return FALSE
;
839 while (*argStr
== L
' ') argStr
++;
840 if (!*argStr
) goto Quit
;
843 switch (towupper(*argStr
))
848 pDCB
->fOutxCtsFlow
= FALSE
;
849 pDCB
->fOutxDsrFlow
= FALSE
;
850 pDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
851 pDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
857 pDCB
->fOutxCtsFlow
= FALSE
;
858 pDCB
->fOutxDsrFlow
= FALSE
;
859 pDCB
->fDtrControl
= DTR_CONTROL_ENABLE
;
860 pDCB
->fRtsControl
= RTS_CONTROL_ENABLE
;
866 pDCB
->fOutxCtsFlow
= TRUE
;
867 pDCB
->fOutxDsrFlow
= TRUE
;
868 pDCB
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
869 pDCB
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
876 if (*argStr
) argStr
++;
878 /* This should be the end of the string */
879 while (*argStr
== L
' ') argStr
++;
880 if (*argStr
) return FALSE
;
882 /* If stop bits were not specified, a default is always supplied */
885 if (pDCB
->BaudRate
== 110)
886 pDCB
->StopBits
= TWOSTOPBITS
;
888 pDCB
->StopBits
= ONESTOPBIT
;
894 * Build a DCB using the new style settings string.
895 * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
897 * See dll/win32/kernel32/wine/comm.c!COMM_BuildNewCommDCB()
898 * for more information.
903 OUT LPCOMMTIMEOUTS pCommTimeouts
,
906 PCWSTR argStr
= ArgStr
;
907 BOOL baud
= FALSE
, stop
= FALSE
;
910 while (argStr
&& *argStr
)
912 while (*argStr
== L
' ') argStr
++;
915 if (_wcsnicmp(argStr
, L
"BAUD=", 5) == 0)
918 argStr
= ParseBaudRate(argStr
+5, &pDCB
->BaudRate
);
919 if (!argStr
) return FALSE
;
921 else if (_wcsnicmp(argStr
, L
"PARITY=", 7) == 0)
923 // Default: EVENPARITY
924 argStr
= ParseParity(argStr
+7, &pDCB
->Parity
);
925 if (!argStr
) return FALSE
;
927 else if (_wcsnicmp(argStr
, L
"DATA=", 5) == 0)
930 argStr
= ParseByteSize(argStr
+5, &pDCB
->ByteSize
);
931 if (!argStr
) return FALSE
;
933 else if (_wcsnicmp(argStr
, L
"STOP=", 5) == 0)
935 // Default: 1, or 2 for BAUD=110
937 argStr
= ParseStopBits(argStr
+5, &pDCB
->StopBits
);
938 if (!argStr
) return FALSE
;
940 else if (_wcsnicmp(argStr
, L
"TO=", 3) == 0) // TO=ON|OFF
942 /* Only total time-outs are get/set by Windows' MODE.COM */
943 argStr
= ParseModes(argStr
+3, &value
);
944 if (!argStr
) return FALSE
;
945 if (value
== 0) // OFF
947 pCommTimeouts
->ReadTotalTimeoutConstant
= 0;
948 pCommTimeouts
->WriteTotalTimeoutConstant
= 0;
950 else if (value
== 1) // ON
952 pCommTimeouts
->ReadTotalTimeoutConstant
= 60000;
953 pCommTimeouts
->WriteTotalTimeoutConstant
= 60000;
960 else if (_wcsnicmp(argStr
, L
"XON=", 4) == 0) // XON=ON|OFF
962 argStr
= ParseModes(argStr
+4, &value
);
963 if (!argStr
) return FALSE
;
964 if ((value
== 0) || (value
== 1))
974 else if (_wcsnicmp(argStr
, L
"ODSR=", 5) == 0) // ODSR=ON|OFF
977 argStr
= ParseModes(argStr
+5, &value
);
978 if (!argStr
) return FALSE
;
979 if ((value
== 0) || (value
== 1))
980 pDCB
->fOutxDsrFlow
= value
;
984 else if (_wcsnicmp(argStr
, L
"OCTS=", 5) == 0) // OCTS=ON|OFF
987 argStr
= ParseModes(argStr
+5, &value
);
988 if (!argStr
) return FALSE
;
989 if ((value
== 0) || (value
== 1))
990 pDCB
->fOutxCtsFlow
= value
;
994 else if (_wcsnicmp(argStr
, L
"DTR=", 4) == 0) // DTR=ON|OFF|HS
997 argStr
= ParseModes(argStr
+4, &value
);
998 if (!argStr
) return FALSE
;
999 if ((value
== 0) || (value
== 1) || (value
== 2))
1000 pDCB
->fDtrControl
= value
;
1004 else if (_wcsnicmp(argStr
, L
"RTS=", 4) == 0) // RTS=ON|OFF|HS|TG
1007 argStr
= ParseModes(argStr
+4, &value
);
1008 if (!argStr
) return FALSE
;
1009 if ((value
== 0) || (value
== 1) || (value
== 2) || (value
== 3))
1010 pDCB
->fRtsControl
= value
;
1014 else if (_wcsnicmp(argStr
, L
"IDSR=", 5) == 0) // IDSR=ON|OFF
1017 argStr
= ParseModes(argStr
+5, &value
);
1018 if (!argStr
) return FALSE
;
1019 if ((value
== 0) || (value
== 1))
1020 pDCB
->fDsrSensitivity
= value
;
1030 /* If stop bits were not specified, a default is always supplied */
1033 if (baud
&& pDCB
->BaudRate
== 110)
1034 pDCB
->StopBits
= TWOSTOPBITS
;
1036 pDCB
->StopBits
= ONESTOPBIT
;
1041 int SetSerialState(INT nPortNum
, IN PCWSTR ArgStr
)
1045 COMMTIMEOUTS CommTimeouts
;
1047 if (!SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, FALSE
))
1049 // TODO: Error message?
1054 * Check whether we should use the old or the new MODE syntax:
1055 * in the old syntax, the separators are both spaces and commas.
1057 if (wcschr(ArgStr
, L
','))
1058 Success
= BuildOldCommDCB(&dcb
, ArgStr
);
1060 Success
= BuildNewCommDCB(&dcb
, &CommTimeouts
, ArgStr
);
1064 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
1068 SerialPortQuery(nPortNum
, &dcb
, &CommTimeouts
, TRUE
);
1069 ShowSerialStatus(nPortNum
);
1075 /*****************************************************************************\
1076 ** E N T R Y P O I N T **
1077 \*****************************************************************************/
1080 FindPortNum(PCWSTR argStr
, PINT PortNum
)
1084 if (*argStr
>= L
'0' && *argStr
<= L
'9')
1086 *PortNum
= *argStr
- L
'0';
1088 if (*argStr
>= L
'0' && *argStr
<= L
'9')
1091 *PortNum
+= *argStr
- L
'0';
1102 int wmain(int argc
, WCHAR
* argv
[])
1107 PCWSTR ArgStr
, argStr
;
1111 /* Initialize the Console Standard Streams */
1112 ConInitStdStreams();
1115 * MODE.COM has a very peculiar way of parsing its arguments,
1116 * as they can be even not separated by any space. This extreme
1117 * behaviour certainly is present for backwards compatibility
1118 * with the oldest versions of the utility present on MS-DOS.
1120 * For example, such a command:
1121 * "MODE.COM COM1baud=9600parity=ndata=8stop=1xon=onto=on"
1122 * will be correctly understood as:
1123 * "MODE.COM COM1 baud=9600 parity=n data=8 stop=1 xon=on to=on"
1125 * Note also that the "/STATUS" switch is actually really "/STA".
1127 * However we will not use GetCommandLine() because we do not want
1128 * to deal with the prepended application path and try to find
1129 * where the arguments start. Our approach here will consist in
1130 * flattening the arguments vector.
1134 /* Compute space needed for the new string, and allocate it */
1135 for (arg
= 1; arg
< argc
; arg
++)
1137 ArgStrSize
+= wcslen(argv
[arg
]) + 1; // 1 for space
1139 ArgStr
= HeapAlloc(GetProcessHeap(), 0, (ArgStrSize
+ 1) * sizeof(WCHAR
));
1142 wprintf(L
"ERROR: Not enough memory\n");
1146 /* Copy the contents and NULL-terminate the string */
1148 for (arg
= 1; arg
< argc
; arg
++)
1150 wcscpy((PWSTR
)argStr
, argv
[arg
]);
1151 argStr
+= wcslen(argv
[arg
]);
1152 *(PWSTR
)argStr
++ = L
' ';
1154 *(PWSTR
)argStr
= L
'\0';
1156 /* Parse the command line */
1159 while (*argStr
== L
' ') argStr
++;
1160 if (!*argStr
) goto show_status
;
1162 if (wcsstr(argStr
, L
"/?") || wcsstr(argStr
, L
"-?"))
1164 ConResPuts(StdOut
, IDS_USAGE
);
1167 else if (_wcsnicmp(argStr
, L
"/STA", 4) == 0)
1169 // FIXME: Check if there are other "parameters" after the status,
1170 // in which case this is invalid.
1173 else if (_wcsnicmp(argStr
, L
"LPT", 3) == 0)
1175 argStr
= FindPortNum(argStr
+3, &nPortNum
);
1176 if (!argStr
|| nPortNum
== -1)
1177 goto invalid_parameter
;
1179 if (*argStr
== L
':') argStr
++;
1180 while (*argStr
== L
' ') argStr
++;
1182 ret
= ShowParallelStatus(nPortNum
);
1185 else if (_wcsnicmp(argStr
, L
"COM", 3) == 0)
1187 argStr
= FindPortNum(argStr
+3, &nPortNum
);
1188 if (!argStr
|| nPortNum
== -1)
1189 goto invalid_parameter
;
1191 if (*argStr
== L
':') argStr
++;
1192 while (*argStr
== L
' ') argStr
++;
1194 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1195 ret
= ShowSerialStatus(nPortNum
);
1197 ret
= SetSerialState(nPortNum
, argStr
);
1200 else if (_wcsnicmp(argStr
, L
"CON", 3) == 0)
1204 if (*argStr
== L
':') argStr
++;
1205 while (*argStr
== L
' ') argStr
++;
1207 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1209 ret
= ShowConsoleStatus();
1211 else if ( (_wcsnicmp(argStr
, L
"CP", 2) == 0 && (argStr
+= 2)) ||
1212 (_wcsnicmp(argStr
, L
"CODEPAGE", 8) == 0 && (argStr
+= 8)) )
1214 while (*argStr
== L
' ') argStr
++;
1216 if (!*argStr
|| _wcsnicmp(argStr
, L
"/STA", 4) == 0)
1217 ret
= ShowConsoleCPStatus();
1219 ret
= SetConsoleCPState(argStr
);
1223 ret
= SetConsoleState(argStr
);
1227 // else if (wcschr(argStr, L','))
1230 /* Old syntax: MODE [COLS],[LINES] */
1231 ret
= SetConsoleStateOld(argStr
);
1238 ShowParallelStatus(1);
1239 for (nPortNum = 0; nPortNum < MAX_COMPORT_NUM; nPortNum++)
1241 ShowSerialStatus(nPortNum + 1);
1243 ShowConsoleStatus();
1248 wprintf(L
"Invalid parameter - %s\n", ArgStr
);
1252 /* Free the string and quit */
1253 HeapFree(GetProcessHeap(), 0, (PWSTR
)ArgStr
);