ANSI C Challenge on readint

R

RoSsIaCrIiLoIA

/* What do you say ? */
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <errno.h>

#define P printf
#define R return
#define W while
#define F for
#define is_digit(x) ('0'<=(x) && (x)<='9')

#define IERR_EOF 8u
#define IERR_UNGET 4u
#define IERR_RANGE 2u
#define IERR_NONUM 1u

unsigned ierrno = 0;

int read_int(FILE* fp);


int main( void )
{
int i, c;
char a[81]={0};

do {
P("Enter an int[1919 or EOF for end]>\n");
ierrno = 0;
i = read_int( stdin );
P( "%d==NUMBER\n", i );
if(ierrno & IERR_RANGE)
puts( "Out of range for int." );
if(ierrno & IERR_EOF)
puts( "Find EOF." );
if(ierrno & IERR_NONUM)
puts( "Nonum" );
if(ierrno & IERR_UNGET)
puts( "Unget" );
if( !feof(stdin) )
{P("Scan..."); fflush(stdout);
if(scanf("%80[^\n]", a)>0)
/*## in stdin there is '\n' ##*/
P("\"%s\"\n", a);
else P("NO out from scanf\n");
}
else P("Press eof\n");
}while(i!=1919 && !feof(stdin));
R 0;
}


/* #### int skip_spaces(FILE* fp) ####
* skip the spaces = ' ' and '\t' and '\n'
* Return EERR_EOF if it meets the eof of fp
* Return EERR_UNGET on error in the preserve the stream
* otherwise return 0.
* (ierrno & IERR_EOF ) !=0 if EOF is meet
* (ierrno & IERR_UNGET) !=0 if stream error (no ungetc)
*/
int skip_spaces(FILE* fp)
{int c;
if( feof(fp) )
R ( ierrno |= IERR_EOF );
W( (c = fgetc(fp))==' ' || c=='\t' || c=='\n') ;
R (c == EOF ? (ierrno |= IERR_EOF ):
ungetc(c, fp)==EOF ? (ierrno |= IERR_UNGET): 0
);
}


/* #### int readint(FILE* fp) #####
* It gets an integer from fp; it is allowed this input
* ({+}||{-}||{}) && ({.}||{}) && [0123456789] &&
* ( ({.}&&[0123456789])||{} )
* range=[ INT_MIN, INT_MAX ]
* on error it returns
* INT_MAX (number too big ;
* or not good input)
* or INT_MIN (a negative number too big)
*
* (ierrno & IERR_RANGE) !=0 if a range error
* (ierrno & IERR_NONUM) !=0 if number is not gets
* (ierrno & IERR_EOF ) !=0 if EOF is meet
* (ierrno & IERR_UNGET) !=0 if stream error in ungetc
* Examples:
* fp="+a+bbb" -> readint(fp)=INT_MAX, fp="+a+bbb"
* fp="++aabbb" -> readint(fp)=INT_MAX, fp="++aabbb"
* fp="+999999999999999999999+9" -> readint(fp)= INT_MAX, fp="+9"
* fp="-999999999999999999999+9" -> readint(fp)= INT_MIN, fp="+9"
* fp="+EOF" -> readint(fp)=INT_MAX, fp="+EOF"
* fp="add" -> readint(fp)=INT_MAX, fp="add"
* fp="+8989s"-> readint(fp)=8989 , fp="s"
* fp=".1231M" -> readint(fp)=0, fp="M"
* fp="-.8989s" -> readint(fp)=-1 , fp="s"
* fp="23.1231M" -> readint(fp)=23, fp="M"
* fp="-23.8989s" -> readint(fp)=-24,fp="s"
*/


int readint(FILE* fp)
{int c, sign = +1;
unsigned n, u = 'a', led=0;

assert(fp != NULL);
if( feof(fp) )
{ierrno |= (IERR_EOF|IERR_NONUM) ; R INT_MAX;}

if((c = fgetc(fp))=='+') u = '+';
else if(c == '-') {u = '-'; sign = -1;}
else if(c == '.')
{
thePoint: /*### case of ".else" exit ###*/
if( sign = fgetc(fp), is_digit(sign) )
{ /*## case .number return 0 or -1 ##*/
if(sign != '0') led = 1;
W( sign = fgetc(fp), is_digit(sign))
if(sign != '0') led = 1;
if(sign != EOF)
{if(ungetc(sign, fp) == EOF)
ierrno |= IERR_UNGET;
}
else ierrno |= IERR_EOF;
R (u=='-' && led) ? -1: 0;
}
else { /*## case ".no_num" exit ##*/
if(sign == EOF) clearerr(fp);
else if(ungetc( sign, fp) == EOF)
goto label1;
if( ungetc('.', fp) == EOF )
{ /*## A waste stream ##*/
label1:
ierrno |= IERR_UNGET|IERR_NONUM;
R INT_MAX;
}
if( u!='a' && ungetc(u, fp)==EOF )
goto label1;
ierrno |= IERR_NONUM;
R INT_MAX;
}
}
else if(!is_digit(c) )
{ /* "no_num" --> exit */
if(c != EOF)
{ if( ungetc(c, fp)==EOF ) goto label1; }
else ierrno |= IERR_EOF;
ierrno |= IERR_NONUM;
R INT_MAX;
}

if( !is_digit(c) && (c = fgetc(fp), !is_digit(c)) )
{ /*## case fp="+else" or fp="-else" ##*/
if(c == '.')
goto thePoint;
/*## fp="+no_num"||"-no_num" ##*/
if(c == EOF) clearerr( fp );
else if( ungetc(c, fp) == EOF )
goto label1;
if( ungetc(u, fp) == EOF ) /*## u=='+' || u=='-'##*/
goto label1;
ierrno |= IERR_NONUM;
R INT_MAX;
}

n = 0; /*## here c would be digit ##*/
if(sign>0) u = INT_MAX;
else {u = -(INT_MIN + 1); u += 1;}

W( 1 )
{
if( n > ( u - ( c - '0' ))/10 )
{
W( c = fgetc(fp), is_digit(c) );
n = u; ierrno |= IERR_RANGE;
break;
}
n = 10*n + (c - '0');
if(c = fgetc(fp), !is_digit(c))
break;
}
if(c == '.') /*# number.else#*/
{ /*#I'm here ^ #*/
if( c = fgetc(fp), !is_digit(c) )
{
if(c == EOF) clearerr(fp);
else if(ungetc( c, fp) == EOF)
ierrno |= IERR_UNGET;
if( !(ierrno & IERR_UNGET) &&
ungetc('.', fp) == EOF )
ierrno |= IERR_UNGET;
R sign>=0 ? n:
n==u ? INT_MIN: (-1)*( (int)n ) ;
}
}
if(is_digit(c)) /*## it jumps .numbers ##*/
{
if(c != '0') led = 1;
W( c = fgetc(fp), is_digit(c))
if(c != '0') led = 1;
}
if(c != EOF)
{
if(ungetc(c, fp) == EOF)
ierrno |= IERR_UNGET;
}
else ierrno |= IERR_EOF;
R sign>=0 ? n:
n==u && led ? (ierrno|=IERR_RANGE, INT_MIN):
n==u ? INT_MIN:
led ? (-1)*( (int)n ) - 1: (-1) * ( (int)n );
}


/* #### int read_int(FILE* fp) #####
* It gets an integer from fp; it is allowed this input
* ([' \t\n']||{}) && ({+}||{-}||{}) && ({.}||{}) && [0123456789] &&
* ( ({.}&&[0123456789])||{} )
* range=[ INT_MIN, INT_MAX ]
* on error it returns
* INT_MAX (number too big;
* or not good input)
* or INT_MIN (a negative number too big)
*
* (ierrno & IERR_RANGE) !=0 if a range error
* (ierrno & IERR_NONUM) !=0 if number is not gets
* (ierrno & IERR_EOF ) !=0 if EOF is meet
* (ierrno & IERR_UNGET) !=0 if stream error in ungetc
*/
int read_int(FILE* fp)
{
skip_spaces(fp);
if(ierrno & IERR_UNGET) /* stream problem */
{ierrno |= IERR_NONUM; R INT_MAX;}
R readint(fp);
}
 

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

Similar Threads

ANSI C Challenge on readint 20
Beginner at c 0
URGENT 1
looking at binary files with C 44
code snippet 92
How to do Lexical analysis for c/c++ source file? 0
Cgi and file access 8
Lexical Analysis on C++ 1

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top