home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib25.zoo / scanf.c < prev    next >
C/C++ Source or Header  |  1992-09-22  |  9KB  |  468 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include <stdarg.h>
  5. #include "lib.h"
  6.     
  7. /*
  8.  * %efg were loosing big time
  9.  *    fixed  ++jrb
  10.  * all floating conversion now done by atof. much is gained by this.
  11.  *    ++jrb
  12.  *
  13.  * hacked to use stdarg by bm
  14.  */
  15.  
  16. #ifndef __NO_FLOAT__
  17. #define FLOATS 1
  18. #endif
  19.     
  20. #ifndef TRUE
  21. #define TRUE  1
  22. #define FALSE 0
  23. #endif
  24.     
  25. extern        char    _numstr[];
  26.  
  27. #define    skip()    while(isspace(c)) { charcnt++; if ((c=(*get)(ip))<1) goto done; }
  28. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  29.  
  30. #if FLOATS
  31. /* fp scan actions */
  32. #define F_NADA    0    /* just change state */
  33. #define F_SIGN    1    /* set sign */
  34. #define F_ESIGN    2    /* set exponent's sign */
  35. #define F_INT    3    /* adjust integer part */
  36. #define F_FRAC    4    /* adjust fraction part */
  37. #define F_EXP    5    /* adjust exponent part */
  38. #define F_QUIT    6
  39.  
  40. #define NSTATE    8
  41. #define FS_INIT        0    /* initial state */
  42. #define FS_SIGNED    1    /* saw sign */
  43. #define FS_DIGS        2    /* saw digits, no . */
  44. #define FS_DOT        3    /* saw ., no digits */
  45. #define FS_DD        4    /* saw digits and . */
  46. #define FS_E        5    /* saw 'e' */
  47. #define FS_ESIGN    6    /* saw exp's sign */
  48. #define FS_EDIGS    7    /* saw exp's digits */
  49.  
  50. #define FC_DIG        0
  51. #define FC_DOT        1
  52. #define FC_E        2
  53. #define FC_SIGN        3
  54.  
  55. /* given transition,state do what action? */
  56. int fp_do[][NSTATE] = {
  57. {F_INT,F_INT,F_INT,
  58.      F_FRAC,F_FRAC,
  59.      F_EXP,F_EXP,F_EXP},    /* see digit */
  60. {F_NADA,F_NADA,F_NADA,
  61.      F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},    /* see '.' */
  62. {F_QUIT,F_QUIT,
  63.      F_NADA,F_QUIT,F_NADA,
  64.      F_QUIT,F_QUIT,F_QUIT},    /* see e/E */
  65. {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
  66.      F_ESIGN,F_QUIT,F_QUIT},    /* see sign */
  67. };
  68. /* given transition,state what is new state? */
  69. int fp_ns[][NSTATE] = {
  70. {FS_DIGS,FS_DIGS,FS_DIGS,
  71.      FS_DD,FS_DD,
  72.      FS_EDIGS,FS_EDIGS,FS_EDIGS},    /* see digit */
  73. {FS_DOT,FS_DOT,FS_DD,
  74.  },    /* see '.' */
  75. {0,0,
  76.      FS_E,0,FS_E,
  77.  },    /* see e/E */
  78. {FS_SIGNED,0,0,0,0,
  79.      FS_ESIGN,0,0},    /* see sign */
  80. };
  81. /* which states are valid terminators? */
  82. int fp_sval[NSTATE] = {
  83.     0,0,1,0,1,0,0,1
  84. };
  85. #endif
  86.  
  87. #ifdef __STDC__
  88. int _scanf(register void *ip, int (*get)(void *),
  89.  int (*unget)(int, void *), unsigned char *fmt, va_list args)
  90. #else
  91. int
  92. _scanf(ip, get, unget, fmt, args)
  93. unsigned char *ip;
  94. int (*get) __PROTO((unsigned char *));
  95. int (*unget) __PROTO((int, unsigned char *));
  96. const unsigned char *fmt;
  97. char **args;
  98. #endif
  99. {
  100.     register long n;
  101.     register int c, width, lval, sval, cnt = 0, charcnt = 1;
  102.     int store, neg, base, wide1, endnull, rngflag, c2;
  103.     register unsigned char *p = 0;
  104.     unsigned char delim[128], digits[17], *q;
  105. #if FLOATS
  106.     double fx;
  107.     char fbuf[128], *fbp;
  108.     int fstate, trans;
  109.     extern double atof __PROTO((const char *));
  110. #endif
  111.     
  112.     if (!*fmt)
  113.     return(0);
  114.     
  115.     c = (*get)(ip);
  116.     while(c > 0)
  117.     {
  118.     store = FALSE;
  119.     if (*fmt == '%')
  120.     {
  121.         n    = 0;
  122.         width    = -1;
  123.         wide1    = 1;
  124.         base    = 10;
  125.         lval    = FALSE;
  126.         sval    = FALSE;
  127.         store    = TRUE;
  128.         endnull    = TRUE;
  129.         neg    = -1;
  130.         
  131.         strcpy((char *)delim,  "\011\012\013\014\015 ");
  132.         strcpy((char *)digits, (const char *)_numstr); /* "01234567890ABCDEF" */
  133.         
  134.         if (fmt[1] == '*')
  135.         {
  136.         endnull = store = FALSE;
  137.         ++fmt;
  138.         }
  139.         
  140.         while (isdigit(*++fmt))        /* width digit(s) */
  141.         {
  142.         if (width == -1)
  143.             width = 0;
  144.         wide1 = width = TEN_MUL(width) + (*fmt - '0');
  145.         }
  146.         --fmt;
  147.       fmtnxt:
  148.         ++fmt;
  149.         switch(tolower(*fmt))    /* tolower() is a MACRO! */
  150.         {
  151.           case '*':
  152.         endnull = store = FALSE;
  153.         goto fmtnxt;
  154.         
  155.           case 'l':    /* long data */
  156.         lval = TRUE;
  157.           case 'h':    /* short data (for compatibility) */
  158.         sval = TRUE;
  159.         goto fmtnxt;
  160.         
  161.           case 'i':    /* any-base numeric */
  162.         base = 0;
  163.         goto numfmt;
  164.         
  165.           case 'b':    /* unsigned binary */
  166.         base = 2;
  167.         goto numfmt;
  168.         
  169.           case 'o':    /* unsigned octal */
  170.         base = 8;
  171.         goto numfmt;
  172.         
  173.           case 'x':    /* unsigned hexadecimal */
  174.         base = 16;
  175.         goto numfmt;
  176.         
  177.           case 'd':    /* SIGNED decimal */
  178.         neg = FALSE;
  179.         /* FALL-THRU */
  180.         
  181.           case 'u':    /* unsigned decimal */
  182.           numfmt:                    skip();
  183.         
  184.         if (isupper(*fmt))
  185.             lval = TRUE;
  186.         
  187.         if (!base)
  188.         {
  189.             base = 10;
  190.             neg = FALSE;
  191.             if (c == '%')
  192.             {
  193.             base = 2;
  194.             goto skip1;
  195.             }
  196.             else if (c == '0')
  197.             {
  198.             charcnt++;
  199.             c = (*get)(ip);
  200.             if (c < 1)
  201.                 goto savnum;
  202.             if ((c != 'x')
  203.                 && (c != 'X'))
  204.             {
  205.                 base = 8;
  206.                 digits[8]= '\0';
  207.                 goto zeroin;
  208.             }
  209.             base = 16;
  210.             goto skip1;
  211.             }
  212.         }
  213.         
  214.         if ((neg == FALSE) && (base == 10)
  215.             && (((neg = (c == '-')) != 0) || (c == '+')))
  216.         {
  217.           skip1:
  218.             charcnt++;
  219.             c = (*get)(ip);
  220.             if (c < 1)
  221.             goto done;
  222.         }
  223.         
  224.         digits[base] = '\0';
  225.         p = ((unsigned char *)
  226.              strchr((const char *)digits,toupper(c)));
  227.         
  228.         if ((!c || !p) && width)
  229.             goto done;
  230.         
  231.         while (p && width-- && c)
  232.         {
  233.             n = (n * base) + (p - digits);
  234.             charcnt++;
  235.             c = (*get)(ip);
  236.           zeroin:
  237.             p = ((unsigned char *)
  238.              strchr((const char *)digits,toupper(c)));
  239.         }
  240.           savnum:
  241.         if (store)
  242.         {
  243. #ifdef __STDC__
  244.             p = va_arg(args, void *);
  245. #else
  246.             p = ((unsigned char *) *args);
  247. #endif
  248.             if (neg == TRUE)
  249.             n = -n;
  250.             if (lval)
  251.             *((long*) p) = n;
  252.             else if (sval)
  253.             *((short *) p) = (short) n;
  254.             else
  255.             *((int *) p) = (int) n;
  256.             ++cnt;
  257.         }
  258.         break;
  259.         
  260. #if FLOATS
  261.           case 'e':    /* float */
  262.           case 'f':
  263.           case 'g':
  264.         skip();
  265.         
  266.         if (isupper(*fmt))
  267.             lval = TRUE;
  268.         
  269.         fstate = FS_INIT;
  270.         fbp = fbuf;
  271.         while (c && width--) {
  272.             if (c >= '0' && c <= '9')
  273.             trans = FC_DIG;
  274.             else if (c == '.')
  275.             trans = FC_DOT;
  276.             else if (c == '+' || c == '-')
  277.             trans = FC_SIGN;
  278.             else if (tolower(c) == 'e')
  279.             trans = FC_E;
  280.             else
  281.             goto fdone;
  282.             
  283.             *fbp++ = c;
  284.  
  285.             if (fp_do[trans][fstate] == F_QUIT)
  286.             goto fdone;
  287.             fstate = fp_ns[trans][fstate];
  288.             charcnt++;
  289.             c = (*get)(ip);
  290.         }
  291.         
  292.           fdone:
  293.         *fbp = '\0';
  294.         if (!fp_sval[fstate])
  295.             goto done;
  296.         if (store) {
  297.             fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
  298. #ifdef __STDC__
  299.             p = va_arg(args, void *);
  300. #else
  301.             p = (unsigned char *) *args;
  302. #endif
  303.             if (lval)
  304.             *((double *) p) = fx;
  305.             else
  306.             *((float *) p) = (float)fx;
  307.             ++cnt;
  308.         }
  309.         break;
  310. #endif
  311.         
  312.           case 'n':
  313.         if (store) {
  314. #ifdef __STDC__
  315.           p = va_arg(args, void *);
  316. #else
  317.           p = (unsigned char *) *args;
  318. #endif
  319.           *((int *) p) = charcnt;
  320.         }
  321.         break;
  322.         
  323.           case 'c':    /* character data */
  324.         width = wide1;
  325.         endnull    = FALSE;
  326.         delim[0] = '\0';
  327.         goto strproc;
  328.         
  329.           case '[':    /* string w/ delimiter set */
  330.         
  331.         /* get delimiters */
  332.         p = delim;
  333.         
  334.         if (*++fmt == '^')
  335.             fmt++;
  336.         else
  337.             lval = TRUE;
  338.         
  339.         rngflag = 2;
  340.         if ((*fmt == ']') || (*fmt == '-'))
  341.         {
  342.             *p++ = *fmt++;
  343.             rngflag = FALSE;
  344.         }
  345.         
  346.         while (*fmt != ']')
  347.         {
  348.             if (*fmt == '\0')
  349.             goto done;
  350.             switch (rngflag)
  351.             {
  352.               case TRUE:
  353.             c2 = *(p-2);
  354.             if (c2 <= *fmt)
  355.             {
  356.                 p -= 2;
  357.                 while (c2 < *fmt)
  358.                 *p++ = c2++;
  359.                 rngflag = 2;
  360.                 break;
  361.             }
  362.             /* fall thru intentional */
  363.             
  364.               case FALSE:
  365.             rngflag = (*fmt == '-');
  366.             break;
  367.             
  368.               case 2:
  369.             rngflag = FALSE;
  370.             }
  371.             
  372.             *p++ = *fmt++;
  373.         }
  374.         
  375.         *p = '\0';
  376.         goto strproc;
  377.         
  378.           case 's':    /* string data */
  379.         skip();
  380.           strproc:
  381.         /* process string */
  382. #ifdef __STDC__
  383.         if (store)
  384.             p = va_arg(args, void *);
  385. #else
  386.         p = ((unsigned char *) *args);
  387. #endif
  388.         
  389.         /* if the 1st char fails, match fails */
  390.         if (width)
  391.         {
  392.             q = ((unsigned char *)
  393.              strchr((const char *)delim, c));
  394.             if((c < 1)
  395.                || (lval ? (q == NULL) : (q != NULL)))
  396.             {
  397.             if (endnull)
  398.                 if (store)
  399.                     *p = '\0';
  400.             goto done;
  401.             }
  402.         }
  403.         
  404.         for (;;) /* FOREVER */
  405.         {
  406.             if (store)
  407.             *p++ = c;
  408.             charcnt++;
  409.             if (((c = (*get)(ip)) < 1) ||
  410.             (--width == 0))
  411.             break;
  412.             q = ((unsigned char *)
  413.              strchr((const char *)delim, c));
  414.             if (lval ? (q == NULL) : (q != NULL))
  415.             break;
  416.         }
  417.         
  418.         if (store)
  419.         {
  420.             if (endnull)
  421.             *p = '\0';
  422.             ++cnt;
  423.         }
  424.         break;
  425.         
  426.           case '\0':    /* early EOS */
  427.         --fmt;
  428.         /* FALL THRU */
  429.         
  430.           default:
  431.         goto cmatch;
  432.         }
  433.     }
  434.     else if (isspace(*fmt))        /* skip whitespace */
  435.     {
  436.         skip();
  437.     }
  438.     else 
  439.     {            /* normal match char */
  440.       cmatch:
  441.         if (c != *fmt) 
  442.         break;
  443.         if (fmt[1] == 0) {    /* we're not going to have any more matches */
  444.         return (cnt);
  445.         }
  446.         charcnt++;
  447.         c = (*get)(ip);
  448.     }
  449.     
  450. #ifdef __STDC__
  451.     /* nothing to do */
  452. #else
  453.     if (store)
  454.         args++;
  455. #endif
  456.     
  457.     if (!*++fmt)
  458.         break;
  459.     }
  460.     
  461.   done:                        /* end of scan */
  462.     if ((c < 0) && (cnt == 0))
  463.     return(EOF);
  464.     
  465.     (*unget)(c, ip);
  466.     return(cnt);
  467. }
  468.