Handy hint, length of string scanfed.

M

Malcolm McLean

Here is a handy hint to extract the length of input consumed by scanf().
(Returns -1 on a bad match / memory failure).

static int int_sscanf(const char *src, const char *fmt)
{
char *fmt2;
int i;
int j =0;
int answer = -1;

fmt = malloc(strlen(fmt) * 2 + 3);
if(!fmt)
return -1;
for(i=0;fmt;i++)
{
if(fmt == '%')
{
if(fmt[i+1] == '%')
{
fmt2[j++] = '%';
fmt2[j++] = '%';
i++;
}
else if(fmt[i+1] == '*')
{
fmt2[j++] = '%';
fmt2[j++] = '*';
i++;
}
else
{
fmt2[j++] = '%';
fmt2[j++] = '*';
}
}
fmt2[j++] = fmt;
}
fmt2[j++] = '%';
fmt2[j++] = 'n';
fmt2[j++] = 0;

sscanf(src, fmt2, &answer);
free(fmt2);
return answer;
}
 
P

pete

Malcolm said:
Here is a handy hint to extract the length
of input consumed by scanf().
(Returns -1 on a bad match / memory failure).

static int int_sscanf(const char *src, const char *fmt)
{
char *fmt2;
int i;
int j =0;
int answer = -1;

fmt = malloc(strlen(fmt) * 2 + 3);
if(!fmt)
return -1;
for(i=0;fmt;i++)
{
if(fmt == '%')
{
if(fmt[i+1] == '%')
{
fmt2[j++] = '%';
fmt2[j++] = '%';
i++;
}
else if(fmt[i+1] == '*')
{
fmt2[j++] = '%';
fmt2[j++] = '*';
i++;
}
else
{
fmt2[j++] = '%';
fmt2[j++] = '*';
}
}
fmt2[j++] = fmt;
}
fmt2[j++] = '%';
fmt2[j++] = 'n';
fmt2[j++] = 0;

sscanf(src, fmt2, &answer);
free(fmt2);
return answer;
}


I can't figure out how to use it.
This program crashes on the int_sscanf function call.

/* BEGIN int_sscanf.c */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static int int_sscanf(const char *src, const char *fmt);

int main(void)
{
const char src[] = "INT_MAX";
const char *fmt = "%s";
char dest[sizeof src];
int rc;

rc = sscanf(src, fmt, dest);
printf("rc is %d\n", rc);
puts(dest);
rc = int_sscanf(src, fmt);
printf("rc is %d\n", rc);
return 0;
}

static int int_sscanf(const char *src, const char *fmt)
{
char *fmt2;
int i;
int j =0;
int answer = -1;

fmt = malloc(strlen(fmt) * 2 + 3);
if(!fmt)
return -1;
for(i=0;fmt;i++)
{
if(fmt == '%')
{
if(fmt[i+1] == '%')
{
fmt2[j++] = '%';
fmt2[j++] = '%';
i++;
}
else if(fmt[i+1] == '*')
{
fmt2[j++] = '%';
fmt2[j++] = '*';
i++;
}
else
{
fmt2[j++] = '%';
fmt2[j++] = '*';
}
}
fmt2[j++] = fmt;
}
fmt2[j++] = '%';
fmt2[j++] = 'n';
fmt2[j++] = 0;

sscanf(src, fmt2, &answer);
free(fmt2);
return answer;
}

/* END int_sscanf.c */
 
B

Ben Bacarisse

Malcolm McLean said:
Here is a handy hint to extract the length of input consumed by scanf().
(Returns -1 on a bad match / memory failure).
static int int_sscanf(const char *src, const char *fmt)
{
char *fmt2;
int i;
int j =0;
int answer = -1;

fmt = malloc(strlen(fmt) * 2 + 3);
fmt2

ditto.

return -1;
for(i=0;fmt;i++)
{
if(fmt == '%')
{
if(fmt[i+1] == '%')
{
fmt2[j++] = '%';
fmt2[j++] = '%';
i++;
}
else if(fmt[i+1] == '*')
{
fmt2[j++] = '%';
fmt2[j++] = '*';
i++;
}
else
{
fmt2[j++] = '%';
fmt2[j++] = '*';
}
}
fmt2[j++] = fmt;


missing else? Goes wrong without it (i.e. with just the fixes above).
}
fmt2[j++] = '%';
fmt2[j++] = 'n';
fmt2[j++] = 0;

sscanf(src, fmt2, &answer);
free(fmt2);
return answer;
}

Then you need to fix cases like "%[%]".

I was going to add that training % might be a problem, but I am not
sure (on reading the standard) if it is legal. It seems not.
 
M

Malcolm McLean

Ben Bacarisse said:
Then you need to fix cases like "%[%]".

I was going to add that training % might be a problem, but I am not
sure (on reading the standard) if it is legal. It seems not.

The square brackets are fiddly. I think this fixes them up, plus the other
problems caused by an old edit being posted.

int int_sscanf(const char *src, char *fmt)
{
char *fmt2;
int i;
int j =0;
int answer = -1;
int inbrackets = 0;
char *temp;

fmt2 = malloc(strlen(fmt) * 2 + 3);
if(!fmt2)
return -1;
for(i=0;fmt;i++)
{
if(fmt == '%' && !inbrackets)
{
temp = &fmt[i+1];
while(isdigit((unsigned char) *temp) || *temp == '*')
temp++;
if(*temp == '[')
inbrackets = 1;
if(fmt[i+1] == '%')
{
fmt2[j++] = '%';
fmt2[j++] = '%';
i++;
}
else if(fmt[i+1] == '*')
{
fmt2[j++] = '%';
fmt2[j++] = '*';
i++;
}
else
{
fmt2[j++] = '%';
fmt2[j++] = '*';
}
}
else if(fmt == ']')
{
if( inbrackets && fmt[i-1] != '[' && !(fmt[i-1] == '^' && fmt[i-2] ==
'[') )
inbrackets = 0;
fmt2[j++] = ']';
}
else
fmt2[j++] = fmt;
}
fmt2[j++] = '%';
fmt2[j++] = 'n';
fmt2[j++] = 0;

sscanf(src, fmt2, &answer);
free(fmt2);
return answer;
}
 
B

Ben Bacarisse

Malcolm McLean said:
Ben Bacarisse said:
Then you need to fix cases like "%[%]".

I was going to add that training % might be a problem, but I am not
sure (on reading the standard) if it is legal. It seems not.

The square brackets are fiddly. I think this fixes them up, plus the
other problems caused by an old edit being posted.

Provided you are limiting the function to C90 formats. I presume you
are, since your code also breaks %n (by adding a *). In C99 %*n is
undefined behaviour but I think is fine in C90 (though I can't afford
the documents I need to argue definitively about this!).
 
B

Ben Bacarisse

Malcolm McLean said:
Ben Bacarisse said:
Then you need to fix cases like "%[%]".

I was going to add that training % might be a problem, but I am not
sure (on reading the standard) if it is legal. It seems not.

The square brackets are fiddly. I think this fixes them up, plus the
other problems caused by an old edit being posted.

int int_sscanf(const char *src, char *fmt)

The old fmt parameter was const char *, which seems the right choice.
 
M

Malcolm McLean

Ben Bacarisse said:
Malcolm McLean said:
Ben Bacarisse said:
Then you need to fix cases like "%[%]".

I was going to add that training % might be a problem, but I am not
sure (on reading the standard) if it is legal. It seems not.

The square brackets are fiddly. I think this fixes them up, plus the
other problems caused by an old edit being posted.

Provided you are limiting the function to C90 formats. I presume you
are, since your code also breaks %n (by adding a *). In C99 %*n is
undefined behaviour but I think is fine in C90 (though I can't afford
the documents I need to argue definitively about this!).
Who thought up that evil little rule?
It seems to have no purpose other than to break my function.

The original plan was to modify fmt in place, which I quickly abandoned.
However I forgot to change the constness.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,436
Messages
2,571,696
Members
48,796
Latest member
Greg L.
Top