Hi Dirk,
You are right, the blank should match 0 whitespace characters.
In the limited tests I have done the problem appears to be confined to %n. For example in my Windows test output this worked:
String=' 123' format=' %u%n': ui=123, strlen(string)=4, nchars=4
So there is a leading blank before the %u format specifier, and no leading whitespace in the input string. But it worked, so Windows does allow 0 whitespace characters in this case.
Note that in my original post in talking about spec I said:
epics_put(PV, "1") works fine on Linux, vxWorks, etc. but fails on Windows
In that case it is obvious that spec should be sending the index as a string. But what also fails on Windows is this:
epics_put(PV, 1) works fine on Linux, vxWorks, etc. but fails on Windows
In this case it is not obvious that spec is sending 1 as a string, but in fact it does, because it sends everything as a string.
Note that Gerry Swislow said he will change spec version 6 to do the following:
epics_put(PV, "1") will use DBF_STRING
epics_put(PV, 1) will use DBF_ENUM
That will also fix the problem. But I think we should consider fixing EPICS base as well.
One solution would be the following in dbFastLinkConv.c.
#ifdef _WIN32
#define UNSIGNED_FORMAT " %u%n"
#else
#define UNSIGNED_FORMAT " %u %n"
#endif
nargs = sscanf(from,UNSIGNED_FORMAT,&ind,&nchars);
if(nargs==1 && nchars==strlen(from) && ind<nchoices) {
*pfield = ind;
return(0);
}
This would preserve the current behavior on all platforms except _WIN32. It would allow _WIN32 to correctly parse all strings except those with trailing whitespace, which is much better than the current situation where it fails for all strings that do NOT have trailing whitespace.
Mark
-----Original Message-----
From: Dirk Zimoch [mailto:[email protected]]
Sent: Monday, September 24, 2012 8:06 AM
To: Mark Rivers
Subject: Re: Problem with using strings to access enum indices on Windows
Hi Mark,
This is interesting. The Linux man page says about this:
A sequence of white-space characters (space, tab, newline, etc;
see isspace(3)). This directive matches any amount of white
space, including none, in the input.
Quite clear.
MSDN says:
White-space characters: blank (' '); tab ('\t'); or newline ('\n'). A
white-space character causes scanf to read, but not store, all
consecutive white-space characters in the input up to the next
non-white-space character. One white-space character in the format
matches any number (including 0) and combination of white-space
characters in the input.
Clear as well. No whitespace at all is allowed. Strange that it does not
work. Is this only a problem before %n?
Dirk
Mark Rivers wrote:
> 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 Eric Norum
- Re: Problem with using strings to access enum indices on Windows J. Lewis Muir
- References:
- Problem with using strings to access enum indices on Windows Mark Rivers
- Navigate by Date:
- Prev:
Re: CAC problem between RTEMS and vxWorks Benjamin Franksen
- Next:
Re: DHCP/BOOTP configuration for EPICS with RTEMS Eric Norum
- 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:
Problem with using strings to access enum indices on Windows Mark Rivers
- Next:
Re: Problem with using strings to access enum indices on Windows Eric Norum
- 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
|