Further testing has revealed a couple more issues with sscanf (and just as I was going to do a change on the repository). All these issues apply to all the scanf type functions BTW. I just happen to be using sscanf.
First issue, short ints were not working (ie "%hd"). This was because the flag define for a star and for short were set to the same value! The following needs to change (line 86 of xscanf.c):
Code: Select all
#define FLSHORT 0x10 /* arg is short int * */
#endif
#if SCANF_LEVEL >= SCANF_STD
#define FLSTAR 0x10 /* suppress assingment (* fmt) */
#endif
#if SCANF_LEVEL >= SCANF_FLT
#define FLBRACKET 0x20 /* %[ found, now collecting the set */
#define FLNEGATE 0x40 /* negate %[ set */
to this:
Code: Select all
#define FLSHORT 0x10 /* arg is short int * */
#endif
#if SCANF_LEVEL >= SCANF_STD
#define FLSTAR 0x20 /* suppress assingment (* fmt) */
#endif
#if SCANF_LEVEL >= SCANF_FLT
#define FLBRACKET 0x40 /* %[ found, now collecting the set */
#define FLNEGATE 0x80 /* negate %[ set */
Basically I've made FLSTAR 0x20 and pushed FLBRACKET and FLNEGATE out to higher values.
Second and more serious issue, I noticed sscanf was changing my string I was passing in. This bit of code illustrates it...
Code: Select all
static char *str = "2 6";
int res = 0;
short int n1 = 0;
short int n2 = 0;
n1 = n2 = 0;
printf("str=[%s] res=%d, n1=%d n2=%d str[4]=%02x",
str, res, n1, n2, str[4]);
res = sscanf(str, "%hd%hd", &n1, &n2);
printf("str=[%s] res=%d, n1=%d n2=%d str[4]=%02x",
str, res, n1, n2, str[4]);
After the call to sscanf the null character at the end of the string had been replaced with 0xFF.
The cause of this is the way the following #define is used through out the code.
#define w_xgetc(s) xgetc(s), clen++
Firstly, I have to say this define is nasty. N-A-S-T-Y.
When the function vxscanf (all the scanf functions are wrapper functions to this function) goes to read a character from the input stream, most of the time it does something like this:
Code: Select all
if ((i = w_xgetc(&stream)) == EOF)
What ends up happening with this is that "i" gets set to the character of the input stream, but EOF gets compared with clen! If an EOF had been read then it will pass through to the main processing for bits of the string, and may get put back on the input stream due to other safe guards. But for sscanf, it replaces the null character with the EOF, or more appropriately with EOF masked to a byte ie 0xFF.
Ideally the #define should be changed, but if we leave it the following should be changed. Where the above code gets used it should be changed to:
Code: Select all
i = w_xgetc(&stream);
if (i == EOF)
and the function _s_xungetc() should change from:
Code: Select all
void _s_xungetc(int c, void ** p_str) {
*(--(*((char **)p_str))) = c;
}
to:
Code: Select all
void _s_xungetc(int c, void ** p_str) {
*(--(*((char **)p_str))) = (c == EOF ? 0 : c);
}
which then makes it do the opposite of what _s_xgetc() does.
Anyway, I'll hang off a couple more days before doing the change to the repository. Just in case I find other things :)