home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / alde_c / misc / lib / dlibssrc / scanf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-10-08  |  7.3 KB  |  306 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. extern    char    _numstr[];
  5.  
  6. /* #define    skip()    do{c=(*get)(ip); if (c<1) goto done;}while(isspace(c))*/
  7.  
  8. #define    skip()    while(isspace(c)) { if ((c=(*get)(ip))<1) goto done; }
  9.  
  10. _scanf(ip, get, unget, fmt, args)
  11. register unsigned char *ip;
  12. int (*get)();
  13. int (*unget)();
  14. register unsigned char *fmt;
  15. char **args;
  16.  
  17. /*
  18.  *    <fmt> points to a format control string.  <args> pointers to a
  19.  *    list of arguments, each of which is the address of a variable in
  20.  *    which input data may be stored.  The format string is used to
  21.  *    control reading of characters from the <get> function.  As each
  22.  *    character is needed <get> is called in the form "c = (*get)(ip);"
  23.  *    where <c> is the character read (negative for errors) and <ip> is
  24.  *    the auxiliary pointer specified by the <ip> parameter.  If a
  25.  *    character needs to be un-gotten, a call to <unget> of the form
  26.  *    "(*unget)(c, ip);" is made.  The format string is composed of
  27.  *    characters and format specifications.  Any characters in <fmt>,
  28.  *    except whitespace characters, which are not part of a format
  29.  *    specifier are expected to be matched one-to-one by characters in
  30.  *    the input stream.  Scanning terminates if a mismatch occurs or if
  31.  *    any call to <get> results in an error.  Whitespace characters
  32.  *    match 0 or more whitespace characters in the input stream.  The
  33.  *    '%' character introduces a format specifier.  The general form of
  34.  *    a format specifier is:
  35.  *
  36.  *         %[*][<width>][l|h]{d|u|o|x|b|i|c|s}
  37.  *
  38.  *    The '*' specifies that a field is to be scanned by not stored.
  39.  *    No variable pointer should be provided for non-stored format
  40.  *    specs.  The <width> field specifies that maximum number of
  41.  *    characters to be process to fill the given format type.  Less
  42.  *    than <width> characters will be processed if the field ends
  43.  *    before <width> characters have been processed.  A field ends when
  44.  *    either a whitespace character, or a character which does not fit
  45.  *    the specified format, is read.  The preceding 'l' (or
  46.  *    capitalizing the conversion character) specifies that the
  47.  *    associated variable is a "long" type.  The trailing character
  48.  *    specifies the format type, as follows:
  49.  *
  50.  *        d Signed decimal integer
  51.  *        u Unsigned decimal integer
  52.  *        o Unsigned octal integer
  53.  *        x Unsigned hexadecimal integer
  54.  *        b Unsigned binary integer
  55.  *        i Unsigned decimal/octal/hexadecimal/binary integer
  56.  *        c Character
  57.  *        s String
  58.  *
  59.  *    If a <width> is specified with the 'c' format, exactly <width>
  60.  *    characters (including whitespace) are read from the input stream,
  61.  *    and written to a string.  No '\0' character is added If the
  62.  *    character following the '%' is not recognized, it is expected to
  63.  *    match the input stream as a non-format character, thus "%%" is
  64.  *    used to match a single '%' character.
  65.  *
  66.  *    One additional conversion is the brace-format.  Shown as "%[...]",
  67.  *    the '...' represent a list of characters.  If the first character
  68.  *    in the list is a '^', the field contains any characters -not- in
  69.  *    the list (starting with the 1st character after the '^').  If the
  70.  *    first character of the list is not a '^', then the field will
  71.  *    only contain those characters found in the list.  The field will
  72.  *    be stored as a null terminated string.  Unlike most of the other
  73.  *    formats, this conversion does allow the programmer to specify
  74.  *    that whitespace characters will be included in the resulting
  75.  *    string.
  76.  */
  77.  
  78. {
  79.     register long n;
  80.     register int c, width, lval, cnt = 0;
  81.     int store, neg, base, wide1, endnull;
  82.     register unsigned char *p;
  83.     char unsigned delim[128], digits[17], *q;
  84.     char *strchr(), *strcpy();
  85.  
  86.     if (!*fmt)
  87.         return(0);
  88.  
  89.     c = (*get)(ip);
  90.     while(c > 0)
  91.         {
  92.         store = FALSE;
  93.         if (*fmt == '%')
  94.             {
  95.             n    = 0;
  96.             width    = -1;
  97.             wide1    = 1;
  98.             base    = 10;
  99.             lval    = FALSE;
  100.             store    = TRUE;
  101.             endnull    = TRUE;
  102.             neg    = -1;
  103.  
  104.             strcpy(delim,  "\011\012\013\014\015 ");
  105.             strcpy(digits, _numstr); /* "01234567890ABCDEF" */
  106.  
  107.             if (fmt[1] == '*')
  108.                 {
  109.                 store = FALSE;
  110.                 ++fmt;
  111.                 }
  112.  
  113.             while (isdigit(*++fmt))        /* width digit(s) */
  114.                 {
  115.                 if (width == -1)
  116.                     width = 0;
  117.                 wide1 = width = (width * 10) + (*fmt - '0');
  118.                 }
  119.             --fmt;
  120. fmtnxt:
  121.             ++fmt;
  122.             switch(tolower(*fmt))    /* tolower() is a MACRO! */
  123.                 {
  124.                 case '*':
  125.                     store = FALSE;
  126.                     goto fmtnxt;
  127.  
  128.                 case 'l':    /* long data */
  129.                     lval = TRUE;
  130. /* for compatability --> */    case 'h':    /* short data */
  131.                     goto fmtnxt;
  132.  
  133.                 case 'i':    /* any-base numeric */
  134.                     base = 0;
  135.                     goto numfmt;
  136.  
  137.                 case 'b':    /* unsigned binary */
  138.                     base = 2;
  139.                     goto numfmt;
  140.  
  141.                 case 'o':    /* unsigned octal */
  142.                     base = 8;
  143.                     goto numfmt;
  144.  
  145.                 case 'x':    /* unsigned hexadecimal */
  146.                     base = 16;
  147.                     goto numfmt;
  148.  
  149.                 case 'd':    /* SIGNED decimal */
  150.                     neg = FALSE;
  151.                     /* FALL-THRU */
  152.  
  153.                 case 'u':    /* unsigned decimal */
  154. numfmt:                    skip();
  155.  
  156.                     if (isupper(*fmt))
  157.                         lval = TRUE;
  158.  
  159.                     if (!base)
  160.                         {
  161.                         base = 10;
  162.                         neg = FALSE;
  163.                         if (c == '%')
  164.                             {
  165.                             base = 2;
  166.                             goto skip1;
  167.                             }
  168.                         else if (c == '0')
  169.                             {
  170.                             c = (*get)(ip);
  171.                             if (c < 1)
  172.                                 goto savnum;
  173.                             if ((c != 'x')
  174.                              && (c != 'X'))
  175.                                 {
  176.                                 base = 8;
  177.                                 digits[8]= '\0';
  178.                                 goto zeroin;
  179.                                 }
  180.                             base = 16;
  181.                             goto skip1;
  182.                             }
  183.                         }
  184.  
  185.                     if ((neg == FALSE) && (base == 10)
  186.                      && ((neg = (c == '-')) || (c == '+')))
  187.                         {
  188. skip1:
  189.                         c = (*get)(ip);
  190.                         if (c < 1)
  191.                             goto done;
  192.                         }
  193.  
  194.                     digits[base] = '\0';
  195.                     p = strchr(digits,toupper(c));
  196.  
  197.                     if (!p && width)
  198.                         goto done;
  199.  
  200.                     while (p && width-- && c)
  201.                         {
  202.                         n = (n * base) + (p - digits);
  203.                         c = (*get)(ip);
  204. zeroin:
  205.                         p = strchr(digits,toupper(c));
  206.                         }
  207. savnum:
  208.                     if (store)
  209.                         {
  210.                         p = *args;
  211.                         if (neg == TRUE)
  212.                             n = -n;
  213.                         if (lval)
  214.                             *((long*) p) = n;
  215.                         else
  216.                             *((int *) p) = n;
  217.                         ++cnt;
  218.                         }
  219.                     break;
  220.  
  221.                 case 'c':    /* character data */
  222.                     width = wide1;
  223.                     endnull    = FALSE;
  224.                     delim[0] = '\0';
  225.                     goto strproc;
  226.  
  227.                 case '[':    /* string w/ delimiter set */
  228.  
  229.                     /* get delimiters */
  230.                     p = delim;
  231.                     if (*++fmt == '^')
  232.                         fmt++;
  233.                     else
  234.                         lval = TRUE;
  235.  
  236.                     while ((*p++ = *fmt) != ']')
  237.                         if (*fmt++ == '\0')
  238.                             goto done;
  239.                     *--p = '\0';
  240.                     goto strproc;
  241.  
  242.                 case 's':    /* string data */
  243.                     skip();
  244. strproc:
  245.                     /* process string */
  246.                     p = *args;
  247.  
  248.                     while (width--)
  249.                         {
  250.                         q = strchr(delim, c);
  251.                         if (lval ? !q : q)
  252.                             break;
  253.                         if (store)
  254.                             *p++ = c;
  255.                         c = (*get)(ip);
  256.                         if (width && (c < 1))
  257.                             {
  258.                             if (endnull)
  259.                                 *p = '\0';
  260.                             goto done;
  261.                             }
  262.                         }
  263.  
  264.                     if (store)
  265.                         {
  266.                         if (endnull)
  267.                             *p = '\0';
  268.                         ++cnt;
  269.                         }
  270.                     break;
  271.  
  272.                 case '\0':    /* early EOS */
  273.                     --fmt;
  274.                     /* FALL THRU */
  275.  
  276.                 default:
  277.                     goto cmatch;
  278.                 }
  279.             }
  280.         else if (isspace(*fmt))        /* skip whitespace */
  281.             {
  282.             skip();
  283.             }
  284.         else 
  285.             {            /* normal match char */
  286. cmatch:
  287.             if (c != *fmt) 
  288.                 break;
  289.             c = (*get)(ip);
  290.             }
  291.  
  292.         if (store)
  293.             args++;
  294.  
  295.         if (!*++fmt)
  296.             break;
  297.         }
  298.  
  299. done:                        /* end of scan */
  300.     if ((c < 1) && (cnt == 0))
  301.         return(EOF);
  302.     (*unget)(c, ip);
  303.     return(cnt);
  304. }
  305.  
  306.