EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: Problem with using strings to access enum indices on Windows
From: Mark Rivers <[email protected]>
To: "'Dirk Zimoch'" <[email protected]>
Cc: "'Gerry Swislow'" <[email protected]>, EPICS tech talk <[email protected]>
Date: Mon, 24 Sep 2012 15:10:52 +0000
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  <20122013  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  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 18 Nov 2013 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·