Commit 8be51c92 authored by Kevin Groeneveld's avatar Kevin Groeneveld Committed by Alexandre Julliard

Add missing wReserved1 member to DCB structure definition.

Fix several bugs in BuildCommDCBAndTimeouts: - make sure LPCSTR parameter is really treated as constant - fix possible buffer overflow if passed in string is too long - if the device control string is invalid, do not modify DCB - do not clear entire DCB, only modify appropriate members - fix parsing of stop bits parameter so it works for 1 and 1.5 - populate COMMTIMEOUTS when to=xxx parameter is specified - added support for xon, odsr, octs, dtr, rts, and idsr parameters - fix several other parsing errors
parent fc7e8f5c
...@@ -156,134 +156,349 @@ static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie) ...@@ -156,134 +156,349 @@ static int COMM_WhackModem(int fd, unsigned int andy, unsigned int orrie)
} }
/*********************************************************************** /***********************************************************************
* COMM_BuildOldCommDCB (Internal) * COMM_Parse* (Internal)
* *
* Build a DCB using the old style settings string eg: "COMx:96,n,8,1" * The following COMM_Parse* functions are used by the BuildCommDCB
* We ignore the COM port index, since we can support more than 4 ports. * functions to help parse the various parts of the device control string.
*/ */
BOOL WINAPI COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb) static LPCSTR COMM_ParseStart(LPCSTR ptr)
{
/* The device control string may optionally start with "COMx" followed
by an optional ':' and spaces. */
if(!strncasecmp(ptr, "COM", 3))
{
ptr += 3;
/* Allow any com port above 0 as Win 9x does (NT only allows
values for com ports which are actually present) */
if(*ptr < '1' || *ptr > '9')
return NULL;
/* Advance pointer past port number */
while(*ptr >= '0' && *ptr <= '9') ptr++;
/* The com port number must be followed by a ':' or ' ' */
if(*ptr != ':' && *ptr != ' ')
return NULL;
/* Advance pointer to beginning of next parameter */
while(*ptr == ' ') ptr++;
if(*ptr == ':')
{
ptr++;
while(*ptr == ' ') ptr++;
}
}
/* The device control string must not start with a space. */
else if(*ptr == ' ')
return NULL;
return ptr;
}
static LPCSTR COMM_ParseNumber(LPCSTR ptr, LPDWORD lpnumber)
{ {
/* "COM1:96,n,8,1" */ if(*ptr < '0' || *ptr > '9') return NULL;
/* 012345 */ if(!sscanf(ptr, "%ld", lpnumber)) return NULL;
char *ptr, temp[256], last; while(*ptr >= '0' && *ptr <= '9') ptr++;
int rate; return ptr;
}
TRACE("(%s), ptr %p\n", device, lpdcb); static LPCSTR COMM_ParseParity(LPCSTR ptr, LPBYTE lpparity)
{
/* Contrary to what you might expect, Windows only sets the Parity
member of DCB and not fParity even when parity is specified in the
device control string */
/* Some applications call this function with "9600,n,8,1" switch(toupper(*ptr++))
* not sending the "COM1:" parameter at left of string */ {
if (!strncasecmp(device,"COM",3)) case 'E':
{ *lpparity = EVENPARITY;
if (!device[3]) return FALSE; break;
if (device[4] != ':' && device[4] != ' ') return FALSE; case 'M':
strcpy(temp,device+5); *lpparity = MARKPARITY;
} break;
else strcpy(temp,device); case 'N':
*lpparity = NOPARITY;
break;
case 'O':
*lpparity = ODDPARITY;
break;
case 'S':
*lpparity = SPACEPARITY;
break;
default:
return NULL;
}
return ptr;
}
static LPCSTR COMM_ParseByteSize(LPCSTR ptr, LPBYTE lpbytesize)
{
DWORD temp;
if(!(ptr = COMM_ParseNumber(ptr, &temp)))
return NULL;
if(temp >= 5 && temp <= 8)
{
*lpbytesize = temp;
return ptr;
}
else
return NULL;
}
static LPCSTR COMM_ParseStopBits(LPCSTR ptr, LPBYTE lpstopbits)
{
DWORD temp;
if(!strncmp("1.5", ptr, 3))
{
ptr += 3;
*lpstopbits = ONE5STOPBITS;
}
else
{
if(!(ptr = COMM_ParseNumber(ptr, &temp)))
return NULL;
last=temp[strlen(temp)-1]; if(temp == 1)
ptr = strtok(temp, ", "); *lpstopbits = ONESTOPBIT;
else if(temp == 2)
*lpstopbits = TWOSTOPBITS;
else
return NULL;
}
return ptr;
}
/* DOS/Windows only compares the first two numbers static LPCSTR COMM_ParseOnOff(LPCSTR ptr, LPDWORD lponoff)
* and assigns an appropriate baud rate. {
* You can supply 961324245, it still returns 9600 ! */ if(!strncasecmp("on", ptr, 2))
if (strlen(ptr) < 2)
{ {
WARN("Unknown baudrate string '%s' !\n", ptr); ptr += 2;
return FALSE; /* error: less than 2 chars */ *lponoff = 1;
} }
ptr[2] = '\0'; else if(!strncasecmp("off", ptr, 3))
rate = atoi(ptr); {
ptr += 3;
*lponoff = 0;
}
else
return NULL;
switch (rate) { return ptr;
}
/***********************************************************************
* COMM_BuildOldCommDCB (Internal)
*
* Build a DCB using the old style settings string eg: "96,n,8,1"
*/
static BOOL COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb)
{
char last = 0;
if(!(device = COMM_ParseNumber(device, &lpdcb->BaudRate)))
return FALSE;
switch(lpdcb->BaudRate)
{
case 11: case 11:
case 30: case 30:
case 60: case 60:
rate *= 10; lpdcb->BaudRate *= 10;
break; break;
case 12: case 12:
case 24: case 24:
case 48: case 48:
case 96: case 96:
rate *= 100; lpdcb->BaudRate *= 100;
break; break;
case 19: case 19:
rate = 19200; lpdcb->BaudRate = 19200;
break; break;
default:
WARN("Unknown baudrate indicator %d !\n", rate);
return FALSE;
} }
lpdcb->BaudRate = rate; while(*device == ' ') device++;
TRACE("baudrate (%ld)\n", lpdcb->BaudRate); if(*device++ != ',') return FALSE;
while(*device == ' ') device++;
ptr = strtok(NULL, ", "); if(!(device = COMM_ParseParity(device, &lpdcb->Parity)))
if (islower(*ptr)) return FALSE;
*ptr = toupper(*ptr);
TRACE("parity (%c)\n", *ptr); while(*device == ' ') device++;
lpdcb->fParity = TRUE; if(*device++ != ',') return FALSE;
switch (*ptr) { while(*device == ' ') device++;
case 'N':
lpdcb->Parity = NOPARITY; if(!(device = COMM_ParseByteSize(device, &lpdcb->ByteSize)))
lpdcb->fParity = FALSE; return FALSE;
break;
case 'E': while(*device == ' ') device++;
lpdcb->Parity = EVENPARITY; if(*device++ != ',') return FALSE;
while(*device == ' ') device++;
if(!(device = COMM_ParseStopBits(device, &lpdcb->StopBits)))
return FALSE;
/* The last parameter for flow control is optional. */
while(*device == ' ') device++;
if(*device == ',')
{
device++;
while(*device == ' ') device++;
if(*device) last = toupper(*device++);
while(*device == ' ') device++;
}
switch(last)
{
case 0:
lpdcb->fInX = FALSE;
lpdcb->fOutX = FALSE;
lpdcb->fOutxCtsFlow = FALSE;
lpdcb->fOutxDsrFlow = FALSE;
lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
break; break;
case 'M': case 'X':
lpdcb->Parity = MARKPARITY; lpdcb->fInX = TRUE;
lpdcb->fOutX = TRUE;
lpdcb->fOutxCtsFlow = FALSE;
lpdcb->fOutxDsrFlow = FALSE;
lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
break; break;
case 'O': case 'P':
lpdcb->Parity = ODDPARITY; lpdcb->fInX = FALSE;
lpdcb->fOutX = FALSE;
lpdcb->fOutxCtsFlow = TRUE;
lpdcb->fOutxDsrFlow = TRUE;
lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
break; break;
case 'S':
lpdcb->Parity = SPACEPARITY;
break;
default: default:
WARN("Unknown parity `%c'!\n", *ptr);
return FALSE; return FALSE;
} }
ptr = strtok(NULL, ", "); /* This should be the end of the string. */
TRACE("charsize (%c)\n", *ptr); if(*device) return FALSE;
lpdcb->ByteSize = *ptr - '0';
return TRUE;
}
ptr = strtok(NULL, ", "); /***********************************************************************
TRACE("stopbits (%c)\n", *ptr); * COMM_BuildNewCommDCB (Internal)
switch (*ptr) { *
case '1': * Build a DCB using the new style settings string.
lpdcb->StopBits = ONESTOPBIT; * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
break; */
case '2': static BOOL COMM_BuildNewCommDCB(LPCSTR device, LPDCB lpdcb, LPCOMMTIMEOUTS lptimeouts)
lpdcb->StopBits = TWOSTOPBITS; {
break; DWORD temp;
default: BOOL baud = FALSE, stop = FALSE;
WARN("Unknown # of stopbits `%c'!\n", *ptr);
return FALSE; while(*device)
{
while(*device == ' ') device++;
if(!strncasecmp("baud=", device, 5))
{
baud = TRUE;
if(!(device = COMM_ParseNumber(device + 5, &lpdcb->BaudRate)))
return FALSE;
}
else if(!strncasecmp("parity=", device, 7))
{
if(!(device = COMM_ParseParity(device + 7, &lpdcb->Parity)))
return FALSE;
}
else if(!strncasecmp("data=", device, 5))
{
if(!(device = COMM_ParseByteSize(device + 5, &lpdcb->ByteSize)))
return FALSE;
}
else if(!strncasecmp("stop=", device, 5))
{
stop = TRUE;
if(!(device = COMM_ParseStopBits(device + 5, &lpdcb->StopBits)))
return FALSE;
}
else if(!strncasecmp("to=", device, 3))
{
if(!(device = COMM_ParseOnOff(device + 3, &temp)))
return FALSE;
lptimeouts->ReadIntervalTimeout = 0;
lptimeouts->ReadTotalTimeoutMultiplier = 0;
lptimeouts->ReadTotalTimeoutConstant = 0;
lptimeouts->WriteTotalTimeoutMultiplier = 0;
lptimeouts->WriteTotalTimeoutConstant = temp ? 60000 : 0;
}
else if(!strncasecmp("xon=", device, 4))
{
if(!(device = COMM_ParseOnOff(device + 4, &temp)))
return FALSE;
lpdcb->fOutX = temp;
lpdcb->fInX = temp;
}
else if(!strncasecmp("odsr=", device, 5))
{
if(!(device = COMM_ParseOnOff(device + 5, &temp)))
return FALSE;
lpdcb->fOutxDsrFlow = temp;
}
else if(!strncasecmp("octs=", device, 5))
{
if(!(device = COMM_ParseOnOff(device + 5, &temp)))
return FALSE;
lpdcb->fOutxCtsFlow = temp;
}
else if(!strncasecmp("dtr=", device, 4))
{
if(!(device = COMM_ParseOnOff(device + 4, &temp)))
return FALSE;
lpdcb->fDtrControl = temp;
}
else if(!strncasecmp("rts=", device, 4))
{
if(!(device = COMM_ParseOnOff(device + 4, &temp)))
return FALSE;
lpdcb->fRtsControl = temp;
}
else if(!strncasecmp("idsr=", device, 5))
{
if(!(device = COMM_ParseOnOff(device + 5, &temp)))
return FALSE;
lpdcb->fDsrSensitivity = temp;
}
else
return FALSE;
/* After the above parsing, the next character (if not the end of
the string) should be a space */
if(*device && *device != ' ')
return FALSE;
} }
if (last == 'x') { /* If stop bits were not specified, a default is always supplied. */
lpdcb->fInX = TRUE; if(!stop)
lpdcb->fOutX = TRUE; {
lpdcb->fOutxCtsFlow = FALSE; if(baud && lpdcb->BaudRate == 110)
lpdcb->fOutxDsrFlow = FALSE; lpdcb->StopBits = TWOSTOPBITS;
lpdcb->fDtrControl = DTR_CONTROL_ENABLE; else
lpdcb->fRtsControl = RTS_CONTROL_ENABLE; lpdcb->StopBits = ONESTOPBIT;
} else if (last=='p') {
lpdcb->fInX = FALSE;
lpdcb->fOutX = FALSE;
lpdcb->fOutxCtsFlow = TRUE;
lpdcb->fOutxDsrFlow = FALSE;
lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
} else {
lpdcb->fInX = FALSE;
lpdcb->fOutX = FALSE;
lpdcb->fOutxCtsFlow = FALSE;
lpdcb->fOutxDsrFlow = FALSE;
lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
} }
return TRUE; return TRUE;
...@@ -321,83 +536,45 @@ BOOL WINAPI BuildCommDCBA( ...@@ -321,83 +536,45 @@ BOOL WINAPI BuildCommDCBA(
BOOL WINAPI BuildCommDCBAndTimeoutsA( BOOL WINAPI BuildCommDCBAndTimeoutsA(
LPCSTR device, /* [in] The ascii device control string. */ LPCSTR device, /* [in] The ascii device control string. */
LPDCB lpdcb, /* [out] The device control block to be updated. */ LPDCB lpdcb, /* [out] The device control block to be updated. */
LPCOMMTIMEOUTS lptimeouts) /* [in] The timeouts to use if asked to set them by the control string. */ LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
{ {
int port; DCB dcb;
char *ptr,*temp; COMMTIMEOUTS timeouts;
BOOL result;
LPCSTR ptr = device;
TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts); TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
if (!strncasecmp(device,"COM",3)) { /* Set DCBlength. (Windows NT does not do this, but 9x does) */
port=device[3]-'0'; lpdcb->DCBlength = sizeof(DCB);
if (port--==0) {
ERR("BUG! COM0 can't exist!\n");
return FALSE;
}
if ((*(device+4)!=':') && (*(device+4)!=' '))
return FALSE;
temp=(LPSTR)(device+5);
} else
temp=(LPSTR)device;
memset(lpdcb,0,sizeof (DCB)); /* Make a copy of the original data structures to work with since if
lpdcb->DCBlength = sizeof(DCB); if there is an error in the device control string the originals
if (strchr(temp,',')) { /* old style */ should not be modified (except possibly DCBlength) */
memcpy(&dcb, lpdcb, sizeof(DCB));
if(lptimeouts) memcpy(&timeouts, lptimeouts, sizeof(COMMTIMEOUTS));
return COMM_BuildOldCommDCB(device,lpdcb); ptr = COMM_ParseStart(ptr);
}
ptr=strtok(temp," "); if(ptr == NULL)
while (ptr) { result = FALSE;
DWORD flag,x; else if(strchr(ptr, ','))
result = COMM_BuildOldCommDCB(ptr, &dcb);
flag=0; else
if (!strncasecmp("baud=",ptr,5)) { result = COMM_BuildNewCommDCB(ptr, &dcb, &timeouts);
if (!sscanf(ptr+5,"%ld",&x))
WARN("Couldn't parse %s\n",ptr); if(result)
lpdcb->BaudRate = x; {
flag=1; memcpy(lpdcb, &dcb, sizeof(DCB));
} if(lptimeouts) memcpy(lptimeouts, &timeouts, sizeof(COMMTIMEOUTS));
if (!strncasecmp("stop=",ptr,5)) { return TRUE;
if (!sscanf(ptr+5,"%ld",&x))
WARN("Couldn't parse %s\n",ptr);
lpdcb->StopBits = x;
flag=1;
}
if (!strncasecmp("data=",ptr,5)) {
if (!sscanf(ptr+5,"%ld",&x))
WARN("Couldn't parse %s\n",ptr);
lpdcb->ByteSize = x;
flag=1;
}
if (!strncasecmp("parity=",ptr,7)) {
lpdcb->fParity = TRUE;
switch (ptr[7]) {
case 'N':case 'n':
lpdcb->fParity = FALSE;
lpdcb->Parity = NOPARITY;
break;
case 'E':case 'e':
lpdcb->Parity = EVENPARITY;
break;
case 'O':case 'o':
lpdcb->Parity = ODDPARITY;
break;
case 'M':case 'm':
lpdcb->Parity = MARKPARITY;
break;
case 'S':case 's':
lpdcb->Parity = SPACEPARITY;
break;
}
flag=1;
}
if (!flag)
ERR("Unhandled specifier '%s', please report.\n",ptr);
ptr=strtok(NULL," ");
} }
if (lpdcb->BaudRate==110) else
lpdcb->StopBits = 2; {
return TRUE; WARN("Invalid device control string: %s\n", device);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
} }
/************************************************************************** /**************************************************************************
...@@ -414,7 +591,7 @@ BOOL WINAPI BuildCommDCBAndTimeoutsA( ...@@ -414,7 +591,7 @@ BOOL WINAPI BuildCommDCBAndTimeoutsA(
BOOL WINAPI BuildCommDCBAndTimeoutsW( BOOL WINAPI BuildCommDCBAndTimeoutsW(
LPCWSTR devid, /* [in] The unicode device control string. */ LPCWSTR devid, /* [in] The unicode device control string. */
LPDCB lpdcb, /* [out] The device control block to be updated. */ LPDCB lpdcb, /* [out] The device control block to be updated. */
LPCOMMTIMEOUTS lptimeouts) /* [in] The timeouts to use if asked to set them by the control string. */ LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
{ {
BOOL ret = FALSE; BOOL ret = FALSE;
LPSTR devidA; LPSTR devidA;
......
...@@ -970,6 +970,7 @@ typedef struct tagDCB ...@@ -970,6 +970,7 @@ typedef struct tagDCB
char ErrorChar; char ErrorChar;
char EofChar; char EofChar;
char EvtChar; char EvtChar;
WORD wReserved1;
} DCB, *LPDCB; } DCB, *LPDCB;
typedef struct tagCOMMCONFIG { typedef struct tagCOMMCONFIG {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment