Revert r42536 for build server diagnosis
[reactos.git] / reactos / dll / win32 / kernel32 / misc / commdcb.c
1 /*
2 Copyright (c) 2008 KJK::Hyperion
3
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 DEALINGS IN THE SOFTWARE.
21 */
22
23 /* Parses a mode string for a serial port, in the same syntax as the mode.com command */
24
25 #if defined(__REACTOS__) && defined(_KERNEL32_)
26 #include <k32.h>
27
28 #define DCB_BuildCommDCBA BuildCommDCBA
29 #define DCB_BuildCommDCBAndTimeoutsA BuildCommDCBAndTimeoutsA
30 #define DCB_BuildCommDCBW BuildCommDCBW
31 #define DCB_BuildCommDCBAndTimeoutsW BuildCommDCBAndTimeoutsW
32 #else
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36
37 #define WIN32_LEAN_AND_MEAN
38 #include <windows.h>
39 #endif
40
41 static
42 void DCB_SkipSpace(const char ** ppTail)
43 {
44 while(**ppTail && isspace(**ppTail))
45 ++ *ppTail;
46 }
47
48 static
49 size_t DCB_SkipNonSpace(const char ** ppTail)
50 {
51 const char * pOriginal = *ppTail;
52
53 while(**ppTail && !isspace(**ppTail))
54 ++ *ppTail;
55
56 return *ppTail - pOriginal;
57 }
58
59 static
60 BOOL DCB_SetBaudRate(unsigned long baudRate, LPDCB lpDCB)
61 {
62 switch(baudRate)
63 {
64 case 11: lpDCB->BaudRate = 110; break;
65 case 15: lpDCB->BaudRate = 150; break;
66 case 30: lpDCB->BaudRate = 300; break;
67 case 60: lpDCB->BaudRate = 600; break;
68 case 12: lpDCB->BaudRate = 1200; break;
69 case 24: lpDCB->BaudRate = 2400; break;
70 case 48: lpDCB->BaudRate = 4800; break;
71 case 96: lpDCB->BaudRate = 9600; break;
72 case 19: lpDCB->BaudRate = 19200; break;
73 default: lpDCB->BaudRate = baudRate; break;
74 }
75
76 return TRUE;
77 }
78
79 static
80 BYTE DCB_SetParity(char parity, LPDCB lpDCB)
81 {
82 switch(parity)
83 {
84 case 'N':
85 case 'n':
86 lpDCB->Parity = 0;
87 break;
88
89 case 'O':
90 case 'o':
91 lpDCB->Parity = 1;
92 break;
93
94 case 'E':
95 case 'e':
96 lpDCB->Parity = 2;
97 break;
98
99 case 'M':
100 case 'm':
101 lpDCB->Parity = 3;
102 break;
103
104 case 'S':
105 case 's':
106 lpDCB->Parity = 4;
107 break;
108
109 default:
110 return FALSE;
111 }
112
113 return TRUE;
114 }
115
116 static
117 BYTE DCB_SetDataBits(unsigned long dataBits, LPDCB lpDCB)
118 {
119 BOOL bRet;
120
121 bRet = dataBits >= 5 && dataBits <= 8;
122
123 if(!bRet)
124 return bRet;
125
126 lpDCB->ByteSize = (BYTE)dataBits;
127 return bRet;
128 }
129
130 static
131 BOOL DCB_ParseOldSeparator(const char ** ppTail)
132 {
133 BOOL bRet;
134
135 bRet = **ppTail == 0;
136
137 if(bRet)
138 return bRet;
139
140 bRet = **ppTail == ',';
141
142 if(bRet)
143 {
144 ++ *ppTail;
145 return bRet;
146 }
147
148 return bRet;
149 }
150
151 static
152 unsigned long DCB_ParseOldNumber(const char ** ppTail, unsigned long nDefault)
153 {
154 char * pNumTail;
155 unsigned long number;
156
157 DCB_SkipSpace(ppTail);
158
159 if(!isdigit(**ppTail))
160 return nDefault;
161
162 number = strtoul(*ppTail, &pNumTail, 10);
163 *ppTail = pNumTail;
164
165 DCB_SkipSpace(ppTail);
166 return number;
167 }
168
169 static
170 char DCB_ParseOldCharacter(const char ** ppTail, char cDefault)
171 {
172 char character;
173
174 DCB_SkipSpace(ppTail);
175
176 if(**ppTail == 0 || **ppTail == ',')
177 return cDefault;
178
179 character = **ppTail;
180 ++ *ppTail;
181
182 DCB_SkipSpace(ppTail);
183 return character;
184 }
185
186 static
187 const char * DCB_ParseOldString(const char ** ppTail, const char * pDefault, size_t * pLength)
188 {
189 const char * string;
190
191 DCB_SkipSpace(ppTail);
192
193 if(**ppTail == 0 || **ppTail == ',')
194 return pDefault;
195
196 string = *ppTail;
197
198 *pLength = 0;
199
200 while(**ppTail != 0 && **ppTail != ',' && !isspace(**ppTail))
201 {
202 ++ *ppTail;
203 ++ *pLength;
204 }
205
206 DCB_SkipSpace(ppTail);
207 return string;
208 }
209
210 static
211 BOOL
212 DCB_ParseOldMode(const char * pTail, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
213 {
214 BOOL bRet;
215
216 unsigned long baudRate;
217 char parity;
218 unsigned long dataBits;
219 size_t stopBitsLength;
220 const char * stopBits;
221 char retry;
222
223 /* Baud rate */
224 baudRate = DCB_ParseOldNumber(&pTail, 0);
225 bRet = DCB_ParseOldSeparator(&pTail);
226 bRet = bRet && DCB_SetBaudRate(baudRate, lpDCB);
227
228 if(!bRet)
229 return bRet;
230
231 /* Parity */
232 parity = DCB_ParseOldCharacter(&pTail, 'E');
233 bRet = DCB_ParseOldSeparator(&pTail);
234 bRet = bRet && DCB_SetParity(parity, lpDCB);
235
236 if(!bRet)
237 return bRet;
238
239 /* Data bits */
240 dataBits = DCB_ParseOldNumber(&pTail, 7);
241 bRet = DCB_ParseOldSeparator(&pTail);
242 bRet = bRet && DCB_SetDataBits(dataBits, lpDCB);
243
244 if(!bRet)
245 return bRet;
246
247 /* Stop bits */
248 stopBitsLength = 1;
249 stopBits = DCB_ParseOldString(&pTail, baudRate == 110 ? "2" : "1", &stopBitsLength);
250 bRet = DCB_ParseOldSeparator(&pTail);
251
252 if(!bRet)
253 return bRet;
254
255 if(strncmp(stopBits, "1", stopBitsLength) == 0)
256 lpDCB->StopBits = 0;
257 else if(strncmp(stopBits, "1.5", stopBitsLength) == 0)
258 lpDCB->StopBits = 1;
259 else if(strncmp(stopBits, "2", stopBitsLength) == 0)
260 lpDCB->StopBits = 2;
261 else
262 return FALSE;
263
264 /* Retry */
265 retry = DCB_ParseOldCharacter(&pTail, 0);
266 bRet = *pTail == 0;
267
268 if(!bRet)
269 return bRet;
270
271 switch(retry)
272 {
273 case 0:
274 lpDCB->fInX = FALSE;
275 lpDCB->fOutX = FALSE;
276 lpDCB->fOutxCtsFlow = FALSE;
277 lpDCB->fOutxDsrFlow = FALSE;
278 lpDCB->fDtrControl = DTR_CONTROL_ENABLE;
279 lpDCB->fRtsControl = RTS_CONTROL_ENABLE;
280 break;
281
282 case 'p':
283 case 'P':
284 lpDCB->fInX = FALSE;
285 lpDCB->fOutX = FALSE;
286 lpDCB->fOutxCtsFlow = TRUE;
287 lpDCB->fOutxDsrFlow = TRUE;
288 lpDCB->fDtrControl = DTR_CONTROL_HANDSHAKE;
289 lpDCB->fRtsControl = RTS_CONTROL_HANDSHAKE;
290 break;
291
292 case 'x':
293 case 'X':
294 lpDCB->fInX = TRUE;
295 lpDCB->fOutX = TRUE;
296 lpDCB->fOutxCtsFlow = FALSE;
297 lpDCB->fOutxDsrFlow = FALSE;
298 lpDCB->fDtrControl = DTR_CONTROL_ENABLE;
299 lpDCB->fRtsControl = RTS_CONTROL_ENABLE;
300 break;
301
302 default:
303 return FALSE;
304 }
305
306 return bRet;
307 }
308
309 static
310 BOOL DCB_ParseNewNumber(const char * pString, size_t cchString, unsigned long * pNumber)
311 {
312 BOOL bRet;
313 char * pStringEnd;
314 unsigned long number;
315
316 bRet = cchString > 0;
317
318 if(!bRet)
319 return bRet;
320
321 number = strtoul(pString, &pStringEnd, 10);
322
323 bRet = pStringEnd - pString == cchString;
324
325 if(!bRet)
326 return bRet;
327
328 *pNumber = number;
329 return bRet;
330 }
331
332 static
333 BOOL DCB_ParseNewBoolean(const char * pString, size_t cchString, BOOL * pBoolean)
334 {
335 BOOL bRet;
336
337 bRet = _strnicmp(pString, "on", cchString) == 0;
338
339 if(bRet)
340 {
341 *pBoolean = bRet;
342 return bRet;
343 }
344
345 bRet = _strnicmp(pString, "off", cchString) == 0;
346
347 if(bRet)
348 {
349 *pBoolean = !bRet;
350 return bRet;
351 }
352
353 return bRet;
354 }
355
356 static
357 BOOL
358 DCB_ParseNewMode(const char * pTail, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
359 {
360 BOOL bRet;
361 BOOL stopBitsSet = FALSE;
362
363 lpDCB->StopBits = 0;
364
365 while(*pTail)
366 {
367 const char * pArg;
368 size_t cchArg;
369 size_t cchArgName;
370 size_t cchArgValue;
371 const char * pArgName;
372 const char * pArgValue;
373 unsigned long nArgValue;
374 BOOL fArgValue;
375
376 pArg = pTail;
377 cchArg = DCB_SkipNonSpace(&pTail);
378 DCB_SkipSpace(&pTail);
379
380 for(cchArgName = 0; cchArgName < cchArg; ++ cchArgName)
381 {
382 if(pArg[cchArgName] == '=')
383 break;
384 }
385
386 bRet = cchArgName < cchArg;
387
388 if(!bRet)
389 return bRet;
390
391 cchArgValue = cchArg - cchArgName - 1;
392 pArgName = pArg;
393 pArgValue = pArg + cchArgName + 1;
394
395 if(_strnicmp(pArgName, "baud", cchArgName) == 0)
396 {
397 bRet = DCB_ParseNewNumber(pArgValue, cchArgValue, &nArgValue);
398 bRet = bRet && DCB_SetBaudRate(nArgValue, lpDCB);
399
400 if(bRet)
401 {
402 if(lpDCB->BaudRate == 110 && !stopBitsSet)
403 lpDCB->StopBits = 2;
404 else
405 lpDCB->StopBits = 0;
406 }
407 }
408 else if(_strnicmp(pArgName, "parity", cchArgName) == 0)
409 {
410 bRet = cchArgValue == 1;
411 bRet = bRet && DCB_SetParity(pArgValue[0], lpDCB);
412 }
413 else if(_strnicmp(pArgName, "data", cchArgName) == 0)
414 {
415 bRet = DCB_ParseNewNumber(pArgValue, cchArgValue, &nArgValue);
416 bRet = bRet && DCB_SetDataBits(nArgValue, lpDCB);
417 }
418 else if(_strnicmp(pArgName, "stop", cchArgName) == 0)
419 {
420 stopBitsSet = TRUE;
421
422 if(strncmp(pArgValue, "1", cchArgValue) == 0)
423 lpDCB->StopBits = 0;
424 else if(strncmp(pArgValue, "1.5", cchArgValue) == 0)
425 lpDCB->StopBits = 1;
426 else if(strncmp(pArgValue, "2", cchArgValue) == 0)
427 lpDCB->StopBits = 2;
428 else
429 bRet = FALSE;
430 }
431 else if(_strnicmp(pArgName, "to", cchArgName) == 0)
432 {
433 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
434
435 if(bRet)
436 {
437 if(lpCommTimeouts)
438 {
439 memset(lpCommTimeouts, 0, sizeof(*lpCommTimeouts));
440
441 if(fArgValue)
442 lpCommTimeouts->WriteTotalTimeoutConstant = 60000;
443 }
444 }
445 }
446 else if(_strnicmp(pArgName, "xon", cchArgName) == 0)
447 {
448 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
449
450 if(bRet)
451 {
452 lpDCB->fInX = !!fArgValue;
453 lpDCB->fOutX = !!fArgValue;
454 }
455 }
456 else if(_strnicmp(pArgName, "odsr", cchArgName) == 0)
457 {
458 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
459
460 if(bRet)
461 lpDCB->fOutxDsrFlow = !!fArgValue;
462 }
463 else if(_strnicmp(pArgName, "octs", cchArgName) == 0)
464 {
465 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
466
467 if(bRet)
468 lpDCB->fOutxCtsFlow = !!fArgValue;
469 }
470 else if(_strnicmp(pArgName, "dtr", cchArgName) == 0)
471 {
472 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
473
474 if(bRet)
475 {
476 if(fArgValue)
477 lpDCB->fDtrControl = DTR_CONTROL_ENABLE;
478 else
479 lpDCB->fDtrControl = DTR_CONTROL_DISABLE;
480 }
481 else
482 {
483 bRet = _strnicmp(pArgValue, "hs", cchArgValue) == 0;
484
485 if(bRet)
486 lpDCB->fDtrControl = DTR_CONTROL_HANDSHAKE;
487 }
488 }
489 else if(_strnicmp(pArgName, "rts", cchArgName) == 0)
490 {
491 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
492
493 if(bRet)
494 {
495 if(fArgValue)
496 lpDCB->fRtsControl = RTS_CONTROL_ENABLE;
497 else
498 lpDCB->fRtsControl = RTS_CONTROL_DISABLE;
499 }
500 else
501 {
502 bRet = _strnicmp(pArgValue, "hs", cchArgValue) == 0;
503
504 if(bRet)
505 lpDCB->fRtsControl = RTS_CONTROL_HANDSHAKE;
506 else
507 {
508 bRet = _strnicmp(pArgValue, "tg", cchArgValue) == 0;
509
510 if(bRet)
511 lpDCB->fRtsControl = RTS_CONTROL_TOGGLE;
512 }
513 }
514 }
515 else if(_strnicmp(pArgName, "idsr", cchArgName) == 0)
516 {
517 bRet = DCB_ParseNewBoolean(pArgValue, cchArgValue, &fArgValue);
518
519 if(bRet)
520 lpDCB->fDsrSensitivity = !!fArgValue;
521 }
522 else
523 bRet = FALSE;
524
525 if(!bRet)
526 return bRet;
527 }
528
529 return TRUE;
530 }
531
532 static
533 BOOL
534 DCB_ValidPort(unsigned long nPort)
535 {
536 BOOL bRet;
537 DWORD dwErr;
538 WCHAR szPort[3 + 10 + 1];
539
540 dwErr = GetLastError();
541
542 _snwprintf(szPort, sizeof(szPort) / sizeof(szPort[0]), L"COM%lu", nPort);
543
544 bRet = QueryDosDeviceW(szPort, NULL, 0) == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER;
545
546 if(!bRet)
547 dwErr = ERROR_INVALID_PARAMETER;
548
549 SetLastError(dwErr);
550 return bRet;
551 }
552
553 /*
554 * @implemented
555 */
556 BOOL
557 WINAPI
558 DCB_BuildCommDCBAndTimeoutsA(LPCSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
559 {
560 BOOL bRet;
561 LPCSTR pTail = lpDef;
562 DCB DCBCopy;
563
564 if(_strnicmp(pTail, "COM", 3) == 0)
565 {
566 char * pNumTail;
567 unsigned long nPort;
568
569 pTail += 3;
570
571 if(!isdigit(*pTail))
572 return FALSE;
573
574 nPort = strtoul(pTail, &pNumTail, 10);
575 pTail = pNumTail;
576
577 bRet = DCB_ValidPort(nPort);
578
579 if(!bRet)
580 return bRet;
581
582 DCB_SkipSpace(&pTail);
583
584 if(*pTail == ':')
585 ++ pTail;
586
587 DCB_SkipSpace(&pTail);
588 }
589
590 DCBCopy = *lpDCB;
591
592 if(isdigit(*pTail))
593 bRet = DCB_ParseOldMode(pTail, &DCBCopy, lpCommTimeouts);
594 else
595 bRet = DCB_ParseNewMode(pTail, &DCBCopy, lpCommTimeouts);
596
597 if(!bRet)
598 SetLastError(ERROR_INVALID_PARAMETER);
599 else
600 *lpDCB = DCBCopy;
601
602 return bRet;
603 }
604
605 /*
606 * @implemented
607 */
608 BOOL
609 WINAPI
610 DCB_BuildCommDCBA(LPCSTR lpDef, LPDCB lpDCB)
611 {
612 return DCB_BuildCommDCBAndTimeoutsA(lpDef, lpDCB, NULL);
613 }
614
615 /*
616 * @implemented
617 */
618 BOOL
619 WINAPI
620 DCB_BuildCommDCBAndTimeoutsW(LPCWSTR lpDef, LPDCB lpDCB, LPCOMMTIMEOUTS lpCommTimeouts)
621 {
622 BOOL bRet;
623 HANDLE hHeap;
624 BOOL bInvalidChars;
625 LPSTR pszAscii;
626 int cchAscii;
627 DWORD dwErr;
628
629 dwErr = ERROR_INVALID_PARAMETER;
630 cchAscii = WideCharToMultiByte(20127, 0, lpDef, -1, NULL, 0, NULL, NULL);
631
632 bRet = cchAscii > 0;
633
634 if(bRet)
635 {
636 hHeap = GetProcessHeap();
637 pszAscii = HeapAlloc(hHeap, 0, cchAscii);
638
639 bRet = pszAscii != NULL;
640
641 if(bRet)
642 {
643 bInvalidChars = FALSE;
644 cchAscii = WideCharToMultiByte(20127, 0, lpDef, -1, pszAscii, cchAscii, NULL, &bInvalidChars);
645
646 bRet = cchAscii > 0 && !bInvalidChars;
647
648 if(bRet)
649 bRet = DCB_BuildCommDCBAndTimeoutsA(pszAscii, lpDCB, lpCommTimeouts);
650
651 HeapFree(hHeap, 0, pszAscii);
652 }
653 else
654 dwErr = ERROR_OUTOFMEMORY;
655 }
656
657 if(!bRet)
658 SetLastError(dwErr);
659
660 return bRet;
661 }
662
663 /*
664 * @implemented
665 */
666 BOOL
667 WINAPI
668 DCB_BuildCommDCBW(LPCWSTR lpDef, LPDCB lpDCB)
669 {
670 return DCB_BuildCommDCBAndTimeoutsW(lpDef, lpDCB, NULL);
671 }
672
673 /* EOF */