Custom Scanf Routine

T

Tarique

Barry said:
....snip..


Sorry but you fixed only half the problem.

The Best i've come so far :I've re-designed the error handling (looks
sane to me! ) and now process signed "Longs" and "Ints" separately !

/*
* File: main.c
* Author: Tarique
*
* Created on July 4, 2008, 11:07 PM
*/

#include <stdio.h >
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdarg.h>
#include <errno.h >
/*
*
*/
struct ErrorCode {
int code ;
/*Pack any other info if required later on */
};

/*Provide Error Code to Differentiate between Errors*/
enum Ecodes {
E_OK = 0, /*Input Ok */
E_IO = 1, /*Input Stream Error */
E_EOF = 2, /*End of File Envountered */
E_TOOLONG = 3, /*Input Exceeds Buffer Length */
E_SHORTBUFF = 4, /*Destination Buffer is Short */
E_RANGE = 5, /*Number Exceeds Range */
E_BADINPUT = 6, /*Invalid Input Obtained */
E_DEFAULT = 7 /*All Unhandled Errors if Any */
};

/*
*If there is garbage in the input stream,pull off everything from the
*input stream to clear it for further use.
*/

int flushln(FILE *f) {
int ch;
while(('\n' != (ch = getc( f ))) && (EOF != ch))
;
return ch;
}

/*Takes a destination buffer and its size as arg (With Error Code) ;
*copies the user entered string into the destination buffer if input
* is successful and the caller's buffer is long enough to hold it.
*
*On Error ,clears the error and sets the appropriate error code which
*can be suitably utilized if necessary.
*/

void input( char* buff,
size_t buff_len,
struct ErrorCode* error ) {

#define BUFFSIZE 100 + 2

char buffer[ BUFFSIZE ];
char* p = buffer + BUFFSIZE - 1;
*p = !0;

if( fgets( buffer, BUFFSIZE, stdin ) == NULL ) {
if( ferror( stdin ) ) {
fprintf( stderr, "Input Stream Error \n" );
error->code = E_IO;
clearerr( stdin );
return ;
}
else if( feof( stdin ) ) {
fprintf( stderr, "EOF Encountered \n" );
error->code = E_EOF;
clearerr( stdin );
return ;
}
}

else {
if( !(*p || (*--p) == '\n') ) {
fprintf( stderr, "Too Long Input\n" );
error->code = E_TOOLONG;
flushln( stdin );
return ;
}
}

if( buff_len >= strlen(buffer) ) {
strcpy( buff, buffer );
error->code = E_OK;
return ;
}

else {
fprintf( stderr, "Too Long Input-b \n" );
error->code = E_SHORTBUFF;
return ;
}
}

/*
* If a string is successfully obtained from the input function,
*it is parsed using strtol. If no parsing error occurs, a long
*If there is any error zero is returned.
*/

long getLong(int isint,
struct ErrorCode* error ) {

char intbuff[21] = {0} ;
char* end_ptr = NULL;
long int lval = 0;
errno = 0;

printf("Enter :");
input( intbuff, 20, error );

if ( error->code == E_IO ) return 0;
else if( error->code == E_EOF ) return 0;
else if( error->code == E_TOOLONG ) return 0;
else if( error->code == E_SHORTBUFF ) return 0;

errno = 0;
lval = strtol( intbuff, &end_ptr, 10 );
if( ERANGE == errno ) {
fprintf(stderr,"Out of Range \n");
error->code = E_RANGE;
return 0;
}
else if (!((*end_ptr == '\n') || (*end_ptr == '\0') || (*end_ptr ==
' '))) {
error->code = E_BADINPUT;
fprintf( stderr, "Not a Valid Integer\n" );
return 0;
}


if(!isint) { /*Process long */
return lval;
}

else { /*Process Int*/
if ( lval > INT_MAX ) {
error->code = E_RANGE;
fprintf( stderr, "Number too Large \n" );
return 0;
}
else if ( lval < INT_MIN ) {
error->code = E_RANGE;
fprintf( stderr, "Number too Small \n" );
return 0;
}
else
return lval;
}
}

/*Minimal Scanf routine only for signed
*'ints' and 'longs' as of now
*/

int myscanf( const char* format, ... ) {

va_list ap ;
const char* p;
int count = 0;
int temp = 0;
long int temp_long = 0;


struct ErrorCode iserror;
iserror.code = 0;

va_start( ap, format );

for( p = format ; *p ; p++ ) {
if( *p != '%' ) {
continue;
}
switch( *++p ) {
case 'd' :
temp = (int)getLong( 0, &iserror );
if( !iserror.code ) {
*va_arg( ap, int* ) = temp;
count ++ ;
}
else {
*va_arg( ap, int* ) = 0;
iserror.code = 0;
}

break;

case 'l':
if( (*++p) == 'd' ) {
temp_long = getLong( 1, &iserror );
if( !iserror.code ) {
*va_arg( ap, long * ) = temp_long;
count ++;
}
else {
*va_arg( ap, long * ) = 0;
iserror.code = 0;
}
}

break;

default :
break;
}
}
va_end(ap);
return count;
}


int main( void ) {

long a = 0, b = 0;
int c = 0, d = 0;

myscanf("%ld %ld" ,&a ,&b);
printf("%d %d \n",a,b);

myscanf("%d %d" ,&c ,&d);
printf("%d %d\n",c,d);

return (EXIT_SUCCESS);
}

Tarique.
 
C

Chris Torek

I have just one small correction here...

I stumbled over your invocations of va_arg, such as:
va_arg() is required to be a macro, and va_arg(ap, int*) expands to an
expression of type int*, so this seems to be valid.

It is.
But note that an invocation of va_arg *looks like* a function call.
If it really were, then the unary "*" operator would apply to the name
"va_arg", not to the result of the call, and the assignment would be
invalid.

No, it is still valid even then:

*f() = var;

binds the same as:

(*(f())) = var;

because the function-call operator (the parentheses following an
identifier) binds more tightly than the unary-* dereference operator.

(As an aside, va_arg looks like a function call only superficially,
since its second argument is a type-name. Note also that the type
name is required to be one that can have one more unary "*" added
to the end, so va_arg is the only place in C where typedef is
actually required, though even then only sometimes. In particular,
to extract a parameter of type "pointer to function (args) returning
T", you cannot write:

va_arg(ap, T (args))

because the syntatic construct for "pointer to function returning T"
is not "T (args) *" but rather "T (*)(args)". But given:

typedef T alias(args);

we can then write:

va_arg(ap, alias)

This uses, or at least potentially uses, the syntactic construct
"alias *", which has type "pointer to function (args) returning
T", which is what we need.)
 
K

Keith Thompson

Chris Torek said:
I have just one small correction here...



It is.


No, it is still valid even then:

*f() = var;

binds the same as:

(*(f())) = var;

because the function-call operator (the parentheses following an
identifier) binds more tightly than the unary-* dereference operator.
[...]

You're right, as usual.

I'd still be happier with more parentheses, even though they're not
strictly necessary:

*(va_arg(ap, int*)) = temp;
 
K

Keith Thompson

Chris Torek said:
I have just one small correction here...



It is.


No, it is still valid even then:

*f() = var;

binds the same as:

(*(f())) = var;

because the function-call operator (the parentheses following an
identifier) binds more tightly than the unary-* dereference operator.
[...]

You're right, as usual.

I'd still be happier with more parentheses, even though they're not
strictly necessary:

*(va_arg(ap, int*)) = temp;
 
K

Keith Thompson

Chris Torek said:
I have just one small correction here...



It is.


No, it is still valid even then:

*f() = var;

binds the same as:

(*(f())) = var;

because the function-call operator (the parentheses following an
identifier) binds more tightly than the unary-* dereference operator.
[...]

You're right, as usual.

I'd still be happier with more parentheses, even though they're not
strictly necessary:

*(va_arg(ap, int*)) = temp;
 
K

Keith Thompson

Chris Torek said:
I have just one small correction here...



It is.


No, it is still valid even then:

*f() = var;

binds the same as:

(*(f())) = var;

because the function-call operator (the parentheses following an
identifier) binds more tightly than the unary-* dereference operator.

You're right, as usual.

I'd still be happier with more parentheses, even though they're not
strictly necessary:

*(va_arg(ap, int*)) = temp;

(Having trouble with my news server; I hope this shows up no more or
less than once.)
 
K

Keith Thompson

Keith Thompson said:
(Having trouble with my news server; I hope this shows up no more or
less than once.)

Naturally it was posted 4 times. I might have to change news servers
again. I'll try posting this exactly once; if it fails, I won't
retry. We'll see what happens.
 
V

vippstar

[...]
(Having trouble with my news server; I hope this shows up no more or
less than once.)

Naturally it was posted 4 times. I might have to change news servers
again. I'll try posting this exactly once; if it fails, I won't
retry. We'll see what happens.
You could try alt.test instead of posting here.
Your message appeared, I think you're just impatient with your slow?
news server :)
 
K

Keith Thompson

[...]
(Having trouble with my news server; I hope this shows up no more or
less than once.)

Naturally it was posted 4 times. I might have to change news servers
again. I'll try posting this exactly once; if it fails, I won't
retry. We'll see what happens.
You could try alt.test instead of posting here.
Your message appeared, I think you're just impatient with your slow?
news server :)

Sorry again for the junk posts. None of them were intended to be test
posts, they just turned out that way. In at least one case, the
server apparently posted the article and then gave me an error
message. Most of the time it posts right away. I'll be more careful
in the future.
 
S

santosh

Keith said:
[...]

(Having trouble with my news server; I hope this shows up no more
or less than once.)

Naturally it was posted 4 times. I might have to change news
servers
again. I'll try posting this exactly once; if it fails, I won't
retry. We'll see what happens.
You could try alt.test instead of posting here.
Your message appeared, I think you're just impatient with your slow?
news server :)

Sorry again for the junk posts. None of them were intended to be test
posts, they just turned out that way. In at least one case, the
server apparently posted the article and then gave me an error
message. Most of the time it posts right away. I'll be more careful
in the future.

If your news server is motzarella.org then yes, this happens
occasionally to me too. If I receive an error message after I attempt
to post an article, I wait for five minutes, then check the group and
retry if the article has not appeared despite the error. Naturally it's
annoying but thankfully it doesn't happen often.
 

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
473,774
Messages
2,569,599
Members
45,164
Latest member
quinoxflush
Top