Sync with trunk r64222.
[reactos.git] / base / applications / cmdutils / mode / mode.c
1 /*
2 * ReactOS mode console command
3 *
4 * mode.c
5 *
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
7 *
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.
12 *
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.
17 *
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.
21 */
22
23 #include <windows.h>
24 #include <stdio.h>
25
26 #define MAX_PORTNAME_LEN 20
27 #define MAX_COMPORT_NUM 10
28 #define MAX_COMPARAM_LEN 20
29
30 #define NUM_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
31 #define ASSERT(a)
32
33 const WCHAR* const usage_strings[] =
34 {
35 L"Device Status: MODE [device] [/STATUS]",
36 L"Select code page: MODE CON[:] CP SELECT=yyy",
37 L"Code page status: MODE CON[:] CP [/STATUS]",
38 L"Display mode: MODE CON[:] [COLS=c] [LINES=n]",
39 L"Typematic rate: MODE CON[:] [RATE=r DELAY=d]",
40 L"Redirect printing: MODE LPTn[:]=COMm[:]",
41 L"Serial port: MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s]\n" \
42 L" [to=on|off] [xon=on|off] [odsr=on|off]\n" \
43 L" [octs=on|off] [dtr=on|off|hs]\n" \
44 L" [rts=on|off|hs|tg] [idsr=on|off]",
45 };
46
47 const WCHAR* const parity_strings[] =
48 {
49 L"None", // default
50 L"Odd", // only symbol in this set to have a 'd' in it
51 L"Even", // ... 'v' in it
52 L"Mark", // ... 'm' in it
53 L"Space" // ... 's' and/or a 'c' in it
54 };
55
56 const WCHAR* const control_strings[] = { L"OFF", L"ON", L"HANDSHAKE", L"TOGGLE" };
57
58 const WCHAR* const stopbit_strings[] = { L"1", L"1.5", L"2" };
59
60
61 int Usage()
62 {
63 int i;
64
65 wprintf(L"\nConfigures system devices.\n\n");
66 for (i = 0; i < NUM_ELEMENTS(usage_strings); i++)
67 {
68 wprintf(L"%s\n", usage_strings[i]);
69 }
70 wprintf(L"\n");
71 return 0;
72 }
73
74 int QueryDevices()
75 {
76 WCHAR buffer[20240];
77 int len;
78 WCHAR* ptr = buffer;
79
80 *ptr = L'\0';
81 if (QueryDosDeviceW(NULL, buffer, NUM_ELEMENTS(buffer)))
82 {
83 while (*ptr != L'\0')
84 {
85 len = wcslen(ptr);
86 if (wcsstr(ptr, L"COM"))
87 {
88 wprintf(L" Found serial device - %s\n", ptr);
89 }
90 else if (wcsstr(ptr, L"PRN"))
91 {
92 wprintf(L" Found printer device - %s\n", ptr);
93 }
94 else if (wcsstr(ptr, L"LPT"))
95 {
96 wprintf(L" Found parallel device - %s\n", ptr);
97 }
98 else
99 {
100 // wprintf(L" Found other device - %s\n", ptr);
101 }
102 ptr += (len+1);
103 }
104 }
105 else
106 {
107 wprintf(L" ERROR: QueryDosDeviceW(...) failed: 0x%lx\n", GetLastError());
108 }
109 return 1;
110 }
111
112 int ShowParallelStatus(int nPortNum)
113 {
114 WCHAR buffer[250];
115 WCHAR szPortName[MAX_PORTNAME_LEN];
116
117 swprintf(szPortName, L"LPT%d", nPortNum);
118 wprintf(L"\nStatus for device LPT%d:\n", nPortNum);
119 wprintf(L"-----------------------\n");
120 if (QueryDosDeviceW(szPortName, buffer, NUM_ELEMENTS(buffer)))
121 {
122 WCHAR* ptr = wcsrchr(buffer, L'\\');
123 if (ptr != NULL)
124 {
125 if (0 == wcscmp(szPortName, ++ptr))
126 {
127 wprintf(L" Printer output is not being rerouted.\n");
128 }
129 else
130 {
131 wprintf(L" Printer output is being rerouted to serial port %s\n", ptr);
132 }
133 return 0;
134 }
135 else
136 {
137 wprintf(L" QueryDosDeviceW(%s) returned unrecognised form %s.\n", szPortName, buffer);
138 }
139 }
140 else
141 {
142 wprintf(L" ERROR: QueryDosDeviceW(%s) failed: 0x%lx\n", szPortName, GetLastError());
143 }
144 return 1;
145 }
146
147 int ShowConsoleStatus()
148 {
149 DWORD dwKbdDelay;
150 DWORD dwKbdSpeed;
151 CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
152 HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
153
154 wprintf(L"\nStatus for device CON:\n");
155 wprintf(L"-----------------------\n");
156 if (GetConsoleScreenBufferInfo(hConsoleOutput, &ConsoleScreenBufferInfo))
157 {
158 wprintf(L" Lines: %d\n", ConsoleScreenBufferInfo.dwSize.Y);
159 wprintf(L" Columns: %d\n", ConsoleScreenBufferInfo.dwSize.X);
160 }
161 if (SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &dwKbdDelay, 0))
162 {
163 wprintf(L" Keyboard delay: %ld\n", dwKbdDelay);
164 }
165 if (SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &dwKbdSpeed, 0))
166 {
167 wprintf(L" Keyboard rate: %ld\n", dwKbdSpeed);
168 }
169 wprintf(L" Code page: %d\n", GetConsoleOutputCP());
170 return 0;
171 }
172
173 static
174 BOOL SerialPortQuery(int nPortNum, LPDCB pDCB, LPCOMMTIMEOUTS pCommTimeouts, BOOL bWrite)
175 {
176 BOOL result;
177 HANDLE hPort;
178 WCHAR szPortName[MAX_PORTNAME_LEN];
179
180 ASSERT(pDCB);
181 ASSERT(pCommTimeouts);
182
183 swprintf(szPortName, L"COM%d", nPortNum);
184 hPort = CreateFileW(szPortName,
185 GENERIC_READ | GENERIC_WRITE,
186 0, // exclusive
187 NULL, // sec attr
188 OPEN_EXISTING,
189 0, // no attributes
190 NULL); // no template
191
192 if (hPort == INVALID_HANDLE_VALUE)
193 {
194 wprintf(L"Illegal device name - %s\n", szPortName);
195 wprintf(L"Last error = 0x%lx\n", GetLastError());
196 return FALSE;
197 }
198
199 result = bWrite ? SetCommState(hPort, pDCB)
200 : GetCommState(hPort, pDCB);
201 if (!result)
202 {
203 wprintf(L"Failed to %s the status for device COM%d:\n", bWrite ? L"set" : L"get", nPortNum);
204 CloseHandle(hPort);
205 return FALSE;
206 }
207
208 result = bWrite ? SetCommTimeouts(hPort, pCommTimeouts)
209 : GetCommTimeouts(hPort, pCommTimeouts);
210 if (!result)
211 {
212 wprintf(L"Failed to %s Timeout status for device COM%d:\n", bWrite ? L"set" : L"get", nPortNum);
213 CloseHandle(hPort);
214 return FALSE;
215 }
216 CloseHandle(hPort);
217 return TRUE;
218 }
219
220 int ShowSerialStatus(int nPortNum)
221 {
222 DCB dcb;
223 COMMTIMEOUTS CommTimeouts;
224
225 if (!SerialPortQuery(nPortNum, &dcb, &CommTimeouts, FALSE))
226 {
227 return 1;
228 }
229 if (dcb.Parity > NUM_ELEMENTS(parity_strings))
230 {
231 wprintf(L"ERROR: Invalid value for Parity Bits %d:\n", dcb.Parity);
232 dcb.Parity = 0;
233 }
234 if (dcb.StopBits > NUM_ELEMENTS(stopbit_strings))
235 {
236 wprintf(L"ERROR: Invalid value for Stop Bits %d:\n", dcb.StopBits);
237 dcb.StopBits = 0;
238 }
239 wprintf(L"\nStatus for device COM%d:\n", nPortNum);
240 wprintf(L"-----------------------\n");
241 wprintf(L" Baud: %ld\n", dcb.BaudRate);
242 wprintf(L" Parity: %s\n", parity_strings[dcb.Parity]);
243 wprintf(L" Data Bits: %d\n", dcb.ByteSize);
244 wprintf(L" Stop Bits: %s\n", stopbit_strings[dcb.StopBits]);
245 wprintf(L" Timeout: %s\n", CommTimeouts.ReadIntervalTimeout ? L"ON" : L"OFF");
246 wprintf(L" XON/XOFF: %s\n", dcb.fOutX ? L"ON" : L"OFF");
247 wprintf(L" CTS handshaking: %s\n", dcb.fOutxCtsFlow ? L"ON" : L"OFF");
248 wprintf(L" DSR handshaking: %s\n", dcb.fOutxDsrFlow ? L"ON" : L"OFF");
249 wprintf(L" DSR sensitivity: %s\n", dcb.fDsrSensitivity ? L"ON" : L"OFF");
250 wprintf(L" DTR circuit: %s\n", control_strings[dcb.fDtrControl]);
251 wprintf(L" RTS circuit: %s\n", control_strings[dcb.fRtsControl]);
252 return 0;
253 }
254
255 int SetParallelState(int nPortNum)
256 {
257 WCHAR szPortName[MAX_PORTNAME_LEN];
258 WCHAR szTargetPath[MAX_PORTNAME_LEN];
259
260 swprintf(szPortName, L"LPT%d", nPortNum);
261 swprintf(szTargetPath, L"COM%d", nPortNum);
262 if (!DefineDosDeviceW(DDD_REMOVE_DEFINITION, szPortName, szTargetPath))
263 {
264 wprintf(L"SetParallelState(%d) - DefineDosDevice(%s) failed: 0x%lx\n", nPortNum, szPortName, GetLastError());
265 }
266 return 0;
267 }
268
269 /*
270 \??\COM1
271 \Device\NamedPipe\Spooler\LPT1
272 BOOL DefineDosDevice(
273 DWORD dwFlags, // options
274 LPCTSTR lpDeviceName, // device name
275 LPCTSTR lpTargetPath // path string
276 );
277 DWORD QueryDosDevice(
278 LPCTSTR lpDeviceName, // MS-DOS device name string
279 LPTSTR lpTargetPath, // query results buffer
280 DWORD ucchMax // maximum size of buffer
281 );
282 */
283
284 int SetConsoleState()
285 {
286 /*
287 "Select code page: MODE CON[:] CP SELECT=yyy",
288 "Code page status: MODE CON[:] CP [/STATUS]",
289 "Display mode: MODE CON[:] [COLS=c] [LINES=n]",
290 "Typematic rate: MODE CON[:] [RATE=r DELAY=d]",
291 */
292 return 0;
293 }
294
295 static
296 int ExtractModeSerialParams(const WCHAR* param)
297 {
298 if (wcsstr(param, L"OFF"))
299 return 0;
300 else if (wcsstr(param, L"ON"))
301 return 1;
302 else if (wcsstr(param, L"HS"))
303 return 2;
304 else if (wcsstr(param, L"TG"))
305 return 3;
306
307 return -1;
308 }
309
310 int SetSerialState(int nPortNum, int args, WCHAR *argv[])
311 {
312 int arg;
313 int value;
314 DCB dcb;
315 COMMTIMEOUTS CommTimeouts;
316 WCHAR buf[MAX_COMPARAM_LEN+1];
317
318 if (SerialPortQuery(nPortNum, &dcb, &CommTimeouts, FALSE))
319 {
320 for (arg = 2; arg < args; arg++)
321 {
322 if (wcslen(argv[arg]) > MAX_COMPARAM_LEN)
323 {
324 wprintf(L"Invalid parameter (too long) - %s\n", argv[arg]);
325 return 1;
326 }
327 wcscpy(buf, argv[arg]);
328 _wcslwr(buf);
329 if (wcsstr(buf, L"baud="))
330 {
331 wscanf(buf+5, L"%lu", &dcb.BaudRate);
332 }
333 else if (wcsstr(buf, L"parity="))
334 {
335 if (wcschr(buf, L'D'))
336 dcb.Parity = 1;
337 else if (wcschr(buf, L'V'))
338 dcb.Parity = 2;
339 else if (wcschr(buf, L'M'))
340 dcb.Parity = 3;
341 else if (wcschr(buf, L'S'))
342 dcb.Parity = 4;
343 else
344 dcb.Parity = 0;
345 }
346 else if (wcsstr(buf, L"data="))
347 {
348 wscanf(buf+5, L"%lu", &dcb.ByteSize);
349 }
350 else if (wcsstr(buf, L"stop="))
351 {
352 if (wcschr(buf, L'5'))
353 dcb.StopBits = 1;
354 else if (wcschr(buf, L'2'))
355 dcb.StopBits = 2;
356 else
357 dcb.StopBits = 0;
358 }
359 else if (wcsstr(buf, L"to=")) // to=on|off
360 {
361 value = ExtractModeSerialParams(buf);
362 if (value != -1)
363 {
364 }
365 else
366 {
367 goto invalid_serial_parameter;
368 }
369 }
370 else if (wcsstr(buf, L"xon=")) // xon=on|off
371 {
372 value = ExtractModeSerialParams(buf);
373 if (value != -1)
374 {
375 dcb.fOutX = value;
376 dcb.fInX = value;
377 }
378 else
379 {
380 goto invalid_serial_parameter;
381 }
382 }
383 else if (wcsstr(buf, L"odsr=")) // odsr=on|off
384 {
385 value = ExtractModeSerialParams(buf);
386 if (value != -1)
387 {
388 dcb.fOutxDsrFlow = value;
389 }
390 else
391 {
392 goto invalid_serial_parameter;
393 }
394 }
395 else if (wcsstr(buf, L"octs=")) // octs=on|off
396 {
397 value = ExtractModeSerialParams(buf);
398 if (value != -1)
399 {
400 dcb.fOutxCtsFlow = value;
401 }
402 else
403 {
404 goto invalid_serial_parameter;
405 }
406 }
407 else if (wcsstr(buf, L"dtr=")) // dtr=on|off|hs
408 {
409 value = ExtractModeSerialParams(buf);
410 if (value != -1)
411 {
412 dcb.fDtrControl = value;
413 }
414 else
415 {
416 goto invalid_serial_parameter;
417 }
418 }
419 else if (wcsstr(buf, L"rts=")) // rts=on|off|hs|tg
420 {
421 value = ExtractModeSerialParams(buf);
422 if (value != -1)
423 {
424 dcb.fRtsControl = value;
425 }
426 else
427 {
428 goto invalid_serial_parameter;
429 }
430 }
431 else if (wcsstr(buf, L"idsr=")) // idsr=on|off
432 {
433 value = ExtractModeSerialParams(buf);
434 if (value != -1)
435 {
436 dcb.fDsrSensitivity = value;
437 }
438 else
439 {
440 goto invalid_serial_parameter;
441 }
442 }
443 else
444 {
445 invalid_serial_parameter:;
446 wprintf(L"Invalid parameter - %s\n", buf);
447 return 1;
448 }
449 }
450 SerialPortQuery(nPortNum, &dcb, &CommTimeouts, TRUE);
451 }
452 return 0;
453 }
454
455 int find_portnum(const WCHAR* cmdverb)
456 {
457 int portnum = -1;
458
459 if (cmdverb[3] >= L'0' && cmdverb[3] <= L'9')
460 {
461 portnum = cmdverb[3] - L'0';
462 if (cmdverb[4] >= L'0' && cmdverb[4] <= L'9')
463 {
464 portnum *= 10;
465 portnum += cmdverb[4] - L'0';
466 }
467 }
468 return portnum;
469 }
470
471 int wmain(int argc, WCHAR* argv[])
472 {
473 int nPortNum;
474 WCHAR param1[MAX_COMPARAM_LEN+1];
475 WCHAR param2[MAX_COMPARAM_LEN+1];
476
477 if (argc > 1)
478 {
479 if (wcslen(argv[1]) > MAX_COMPARAM_LEN)
480 {
481 wprintf(L"Invalid parameter (too long) - %s\n", argv[1]);
482 return 1;
483 }
484 wcscpy(param1, argv[1]);
485 _wcslwr(param1);
486 if (argc > 2)
487 {
488 if (wcslen(argv[2]) > MAX_COMPARAM_LEN)
489 {
490 wprintf(L"Invalid parameter (too long) - %s\n", argv[2]);
491 return 1;
492 }
493 wcscpy(param2, argv[2]);
494 _wcslwr(param2);
495 }
496 else
497 {
498 param2[0] = L'\0';
499 }
500 if (wcsstr(param1, L"/?") || wcsstr(param1, L"-?"))
501 {
502 return Usage();
503 }
504 else if (wcsstr(param1, L"/status"))
505 {
506 goto show_status;
507 }
508 else if (wcsstr(param1, L"lpt"))
509 {
510 nPortNum = find_portnum(param1);
511 if (nPortNum != -1)
512 return ShowParallelStatus(nPortNum);
513 }
514 else if (wcsstr(param1, L"con"))
515 {
516 return ShowConsoleStatus();
517 }
518 else if (wcsstr(param1, L"com"))
519 {
520 nPortNum = find_portnum(param1);
521 if (nPortNum != -1)
522 {
523 if (param2[0] == L'\0' || wcsstr(param2, L"/status"))
524 {
525 return ShowSerialStatus(nPortNum);
526 }
527 else
528 {
529 return SetSerialState(nPortNum, argc, argv);
530 }
531 }
532 }
533 wprintf(L"Invalid parameter - %s\n", param1);
534 return 1;
535 }
536 else
537 {
538 show_status:;
539
540 QueryDevices();
541 /*
542 ShowParallelStatus(1);
543 for (nPortNum = 0; nPortNum < MAX_COMPORT_NUM; nPortNum++)
544 {
545 ShowSerialStatus(nPortNum + 1);
546 }
547 ShowConsoleStatus();
548 */
549 }
550 return 0;
551 }