Back to home page
 
  
Re: Need help with stdio in C  
Author:   cbfalconer <cbfalconer@worldnet.att.net>
Date:   1998/09/04
Forum:   alt.comp.lang.learn.c-c++ 
 

In article <clcm-19980903-0034@plethora.net>,
  Herb Illfelder <illfeldr@hal-pc.org> wrote:
> You can also use the file functions (ie. fgets) by using the stdin,
> stdout, & stderr.  However, as with the console I/O routines, nothing
> is read in until the carriage return is fit (passed as a linefeed ).

------------------------------
Whoa - this is system dependant and often depends on how you have opened the
file from which you are reading.  For many interactive operations you want to
receive a key as soon as it is bashed, and getc or getchar will do this.

At any rate, I consider the C i/o parsing mechanisms brain dead, and much
prefer std Pascal techniques.  Here you can input numbers, skip leading
blanks and/or zero digits, and detect exactly what character terminated the
read.  No string storage is needed, and thus they don't create sneaky paths
for vandals. The system routines are easily ported to C, and the following
code does that.  The magic is all in the use of ungetc(), to replace Pascals
f^ for lookahead.

WARNING - I just did this translation and haven't really tested it.  I have
passed it through lint.

/*-----------------9/4/98 3:26PM--------------------
 * File input.c
 * --------------------------------------------------*/

#include <stdio.h>
#include <stdbool.h>
#include <limits.h>

#include "input.h"

/* These routines are written so that simple conditionals can be used
 *
 *      if (readxint(&myint, stdin))
 *      {  do_error_recovery; normally_abort_to_somewhere;
 *      }
 *      else
 *      {  do_normal_things; usually_much_longer_than_bad_case;
 *      }
 *
 * They allow overflow detection, and permit other routines to
 * detect the character that terminated a numerical field. No
 * string storage is required, thus there is no limitation on
 * the length of input fields.  For example, a number entered
 * with a string of 1000 leading zeroes will not annoy these.
 *
 * They are also re-entrant, subject to the limitations of file
 * systems.  e.g interrupting readxint(v, stdin) operation with
 * a call to readxwd(wd, stdin) would not be well defined, if the
 * same stdin is being used for both calls.  If ungetc is
 * interruptible the run-time system is broken.
 *
 * They are C translations from my input routines for ISO-Pascal,
 * which were written in ISO-Pascal, and are tried and true.
 *
 * These really should be slaved to <limits.h> values.
 */

/*----------------------------------------------------------------------
 * skip all whitespace on f.  At completion getc(f) will
 *  return a non-blank character, which may be \n or EOF
 */
void skipblks(FILE *f)
{
   int ch;

   ch = getc(f);
   while ((' ' == ch) || ('\t' == ch)) ch = getc(f);
   ungetc(ch, f);
} /* skipblks */

/*----------------------------------------------------------------------
 * skip all whitespace on f, including \n.  At completion getc(f) will
 *  return a non-blank character, which may be EOF
 * WARNING: If the system is non-std and returns the cr/lf sequence,
 *          this code won't work right.  i.e. use text mode for f.
 */
void skipwhite(FILE *f)
{
   int ch;

   ch = getc(f);
   while ((' ' == ch) || ('\t' == ch) || ('\n' == ch))  ch = getc(f);
   ungetc(ch, f);
} /* skipwhite */

/*----------------------------------------------------------------------
 * Read a 16 bit unsigned value.  Signal error for overflow or no
 * valid number found.  Returns true for error, false for noerror
 * Skip all leading whitespace on f.  At completion getc(f) will
 * return the character terminating the number, which may be \n or EOF
 * among others. It will NOT be a digit.   The 16 bit size is built
 * into the overflow detection.
 */
bool readxwd(unsigned int *wd, FILE *f)
{
   unsigned int value, digit;
   bool status;
   int ch;

   *wd = value = 0;                      /* default */
   status = true;                       /* default error */
   do
   {  ch = getc(f);
   } while ((' ' == ch) || ('\t' == ch)); /* skipwhite */

   if (!(EOF == ch))
   {  if (('0' <= ch) && ('9' >= ch))   /* found digit, no error */
         status = false;
      while (('0' <= ch) && ('9' >= ch))
      {  digit = (unsigned) (ch - '0');
         if ((value < 6553) || ((6553 == value) && (6 > digit)))
            value = 10 * value + digit;
         else                           /* overflow */
            status = true;
         ch = getc(f);
      } /* while (ch is a digit) */
      if (!status) *wd = value;
   }
   ungetc(ch, f);
   return status;
} /* readxwd */

/*----------------------------------------------------------------------
 * Read a 16 bit signed value.  Signal error for overflow or no
 * valid number found.  Returns true for error, false for noerror
 * Skip all leading whitespace on f.  At completion getc(f) will
 * return the character terminating the number, which may be \n or EOF
 * among others.  It will NOT be a digit.
 * The 16 bit size is built into the overflow detection.
 */
bool readxint(int *val, FILE *f)
{
   unsigned int value, digit;
   bool status, negative;
   int ch;

   ch = getc(f);
   *val = value = 0;                    /* default */
   status = true;                       /* default error */
   negative = false;
   while ((' ' == ch) || ('\t' == ch))  /* skipwhite */
      ch = getc(f);
   if (!(EOF == ch))
   {  if (('+' == ch) || ('-' == ch))
      {  negative = ('-' == ch);
         ch = getc(f);                  /* absorb any sign */
      }
      if (('0' <= ch) && ('9' >= ch))   /* found digit, no error */
         status = false;
      while (('0' <= ch) && ('9' >= ch))  /* effectively readxwd */
      {  digit = (unsigned) (ch - '0');
         if (value < 3277)
            value = 10 * value + digit;
         else                           /* overflow */
            status = true;
         ch = getc(f);
      } /* while (ch is a digit) */
      if (!status)
         if (negative && (value <= 32768u)) *val = -value;
         else if (value <= 32767)           *val = value;
         else status = true;
   }
   ungetc(ch, f);
   return status;
} /* readxint */

/* End of INPUT.c */


creation of input.h is left as an exercize. :-)


> Hoser wrote:
>
> > I know C++ well, but I am having a problem with a program in C.
> >
> > I am trying to input an integer from STDIN, but the only functions I can
> > find are the gets, getchar, etc. functions to read from STDIN.  Those
> > functions only read characters and strings and are useless when trying to
> > get integers for calculations.  Does anyone know how to get around this?  Or
> > is there a 'getint' function in some library that I could use?


--
    Chuck Falconer (cbfalconer@worldnet.att.net)


comp.lang.c.moderated - clcm@plethora.net
 Back to home page