Experimental Physics and Industrial Control System
Folks,
There is a problem writing a number as a string (such a "1") to an EPICS enum when the EPICS PV is hosted on a Windows IOC built with the Microsoft compiler (win32-x86, windows-x64, etc). This problem came to my attention because the popular beamline control software program "spec" does all channel access puts using DBF_STRING.
For example if there is bo record with states 0="Off" and 1="On" then this is what we observe in spec:
epics_put(PV, "On") works fine
epics_put(PV, "1") works fine on Linux, vxWorks, etc. but fails on Windows
When one does epics_put(PV, "1") here is what is supposed to happen:
1) The EPICS IOC first sees if the string matches one of the enum string fields. If it does it selects that enum choice.
2) If the string does not match an enum string, it tries to convert the string to a number, and checks to see if the number is one of the allowed numbers for that enum. If it does it selects that enum choice.
In step 2) it does the attempted conversion from a string to a number using this code in dbFastLinkConv.c.
nargs = sscanf(from," %u %n",&ind,&nchars);
if(nargs==1 && nchars==strlen(from) && ind<nchoices) {
*pfield = ind;
return(0);
}
So it uses the %n format string to figure out if sscanf has consumed the entire "from" string. This ensures, for example, that the string "1abc" is not interpreted as "1".
The problem is that the " %u %n" format string does not work on Windows.
When I spoke to Andrew Johnson he said he thought this was because Windows does not implement the %n format specifier.
I have done some more investigation, and found that this is not the case. The problem is the leading space before the %n specifier. On Windows when sscanf hits the blank space in the format specifier, but does not find a blank space in the input string, it stops parsing the input string. So it never reaches the %n format specifier. The GNU run-time library behaves differently, it processes %n even if there is no space in the input. I think it is questionable as to which is the "correct" behavior.
To investigate this I wrote the following little test program. It tests all combinations of 4 input strings with 4 format strings. The input strings differ in having no blanks, leading blank, trailing blank, and both leading and trailing blank. The format strings differ in having no blanks, leading blank, blank between %u and %n, and both leading and between. The program prints the results of the %u and %n conversions.
****************************************
#include <stdio.h>
#include <string.h>
#define NUM_STRINGS 4
#define NUM_FORMATS 4
int main(int argc, char *argv[])
{
static const char *testStrings[NUM_STRINGS] = {"123", " 123", "123 ", " 123 "};
static const char *testFormats[NUM_FORMATS] = {" %u %n", " %u%n", "%u %n", "%u%n"};
unsigned ui;
int i, j, nchars;
for (i=0; i<NUM_STRINGS; i++) {
for (j=0; j<NUM_FORMATS; j++) {
ui = 0;
nchars = 0;
sscanf(testStrings[i], testFormats[j], &ui, &nchars);
printf("String='%s' format='%s': ui=%u, strlen(string)=%d, nchars=%d\n",
testStrings[i], testFormats[j], ui, strlen(testStrings[i]), nchars);
}
}
return 0;
}
****************************************
Here are the results on Linux:
corvette:dxp/dxpApp/src>../../bin/linux-x86/test_sscanf
String='123' format=' %u %n': ui=123, strlen(string)=3, nchars=3
String='123' format=' %u%n': ui=123, strlen(string)=3, nchars=3
String='123' format='%u %n': ui=123, strlen(string)=3, nchars=3
String='123' format='%u%n': ui=123, strlen(string)=3, nchars=3
String=' 123' format=' %u %n': ui=123, strlen(string)=4, nchars=4
String=' 123' format=' %u%n': ui=123, strlen(string)=4, nchars=4
String=' 123' format='%u %n': ui=123, strlen(string)=4, nchars=4
String=' 123' format='%u%n': ui=123, strlen(string)=4, nchars=4
String='123 ' format=' %u %n': ui=123, strlen(string)=4, nchars=4
String='123 ' format=' %u%n': ui=123, strlen(string)=4, nchars=3
String='123 ' format='%u %n': ui=123, strlen(string)=4, nchars=4
String='123 ' format='%u%n': ui=123, strlen(string)=4, nchars=3
String=' 123 ' format=' %u %n': ui=123, strlen(string)=5, nchars=5
String=' 123 ' format=' %u%n': ui=123, strlen(string)=5, nchars=4
String=' 123 ' format='%u %n': ui=123, strlen(string)=5, nchars=5
String=' 123 ' format='%u%n': ui=123, strlen(string)=5, nchars=4
Here are the results on Windows:
J:\epics\devel\dxp\dxpApp\src>..\..\bin\win32-x86\test_sscanf.exe
String='123' format=' %u %n': ui=123, strlen(string)=3, nchars=0
String='123' format=' %u%n': ui=123, strlen(string)=3, nchars=3
String='123' format='%u %n': ui=123, strlen(string)=3, nchars=0
String='123' format='%u%n': ui=123, strlen(string)=3, nchars=3
String=' 123' format=' %u %n': ui=123, strlen(string)=4, nchars=0
String=' 123' format=' %u%n': ui=123, strlen(string)=4, nchars=4
String=' 123' format='%u %n': ui=123, strlen(string)=4, nchars=0
String=' 123' format='%u%n': ui=123, strlen(string)=4, nchars=4
String='123 ' format=' %u %n': ui=123, strlen(string)=4, nchars=4
String='123 ' format=' %u%n': ui=123, strlen(string)=4, nchars=3
String='123 ' format='%u %n': ui=123, strlen(string)=4, nchars=4
String='123 ' format='%u%n': ui=123, strlen(string)=4, nchars=3
String=' 123 ' format=' %u %n': ui=123, strlen(string)=5, nchars=5
String=' 123 ' format=' %u%n': ui=123, strlen(string)=5, nchars=4
String=' 123 ' format='%u %n': ui=123, strlen(string)=5, nchars=5
String=' 123 ' format='%u%n': ui=123, strlen(string)=5, nchars=4
So Windows does not set nchars with the %n specifier if there is a blank before %n in the format string but no blank after the number in the input string.
My question: Is it necessary to allow the string to contain a trailing blank? That is the only case where " %u %n" produces a different result from "%u%n". If we changed these format strings to %u%n then they would also work on Windows.
Mark
- Replies:
- Re: Problem with using strings to access enum indices on Windows Andrew Johnson
- Navigate by Date:
- Prev:
FW: BPM Screens Southern, Tim
- Next:
Re: CAC problem between RTEMS and vxWorks Benjamin Franksen
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Bug on autosave for the ULONG type array Kim, Kukhee
- Next:
RE: Problem with using strings to access enum indices on Windows Mark Rivers
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
<2012>
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024