home *** CD-ROM | disk | FTP | other *** search
/ RISC DISC 1 / RISC_DISC_1.iso / pd_share / code / unixlib / !UnixLib / src / stdio / c / scan < prev    next >
Encoding:
Text File  |  1994-09-30  |  13.4 KB  |  857 lines

  1. static char sccs_id[] = "@(#) scan.c 3.0 " __DATE__ " HJR";
  2.  
  3. /* scan.c (c) Copyright 1990 H.Rogers */
  4.  
  5. /* Implements __scanf(fp,format,argp,cnt) which is called by all
  6.  * scanf() functions to perform formatted input. __scanf() returns a count
  7.  * of the number of characters read. *cnt is assigned to an item count. */
  8.  
  9. /* A conversion is of the form "%[*][width][size]function".
  10.  * For full details RTFM for scanf(3). */
  11.  
  12. #include <stddef.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <stdarg.h>
  17. #include <stdio.h>
  18.  
  19. #define IGNORE(x) x = x
  20.  
  21. __STDIOLIB__
  22.  
  23. #define ungetc(c,f) \
  24.     (((f)->i_ptr > (f)->i_base) ? ((f)->i_cnt++,*--(f)->i_ptr = (c)) : -1)
  25.  
  26. /* To avoid truncation SCBUFSIZ should be 256+.
  27.  * This library will *not* buffer overflow unless SCBUFSIZ < 4. */
  28.  
  29. #define SCBUFSIZ    256    /* size of buffer for %feEgG & %[ */
  30.  
  31.  
  32. /* the prototypes for the input functions */
  33.  
  34. static int __s_nin (FILE *, va_list *, const char **);
  35.  
  36. static int __s_char (FILE *, va_list *, const char **);
  37. static int __s_str (FILE *, va_list *, const char **);
  38. static int __s_sdec (FILE *, va_list *, const char **);
  39. static int __s_sint (FILE *, va_list *, const char **);
  40. static int __s_uoct (FILE *, va_list *, const char **);
  41. static int __s_udec (FILE *, va_list *, const char **);
  42. static int __s_uhex (FILE *, va_list *, const char **);
  43. static int __s_fdbl (FILE *, va_list *, const char **);
  44. static int __s_ptr (FILE *, va_list *, const char **);
  45. static int __s_sdel (FILE *, va_list *, const char **);
  46.  
  47.  
  48. /* __scnt is set to the number of characters read by __scanf() and
  49.  * is used by __s_nin() to output the number of characters read. */
  50.  
  51. static size_t __scnt;
  52.  
  53. static int __scflag;        /* assignment suppression flag */
  54. static int __scsize;        /* -1 = unspecified */
  55. static unsigned int __scwidth;    /* width */
  56.  
  57. static signed char __scfnc[32] =    /* conversions */
  58. {
  59.   -1, -1,
  60.   1,                /* %c */
  61.   3,                /* %d */
  62.   8,                /* %eE */
  63.   8,                /* %f */
  64.   8,                /* %gG */
  65.   -1,
  66.   4,                /* %i */
  67.   -1, -1, -1, -1,
  68.   0,                /* %n */
  69.   5,                /* %o */
  70.   9,                /* %p */
  71.   -1, -1,
  72.   2,                /* %s */
  73.   -1,
  74.   6,                /* %u */
  75.   -1, -1,
  76.   7,                /* %xX */
  77.   -1, -1, -1, -1, -1, -1, -1, -1
  78. };
  79.  
  80. /* __scfn[] is the array of input functions called by __scanf() -
  81.  * They return a value indicating whether they successfully interpreted
  82.  * the input or not. 0 indicates failure; a +ve value is a count
  83.  * of the number of characters read. */
  84.  
  85. static int (*__scfn[]) (FILE *, va_list *, const char **) =
  86. {
  87.   __s_nin,            /* %n no. of characters read so far */
  88.     __s_char,            /* %c character */
  89.     __s_str,            /* %s string */
  90.     __s_sdec,            /* %d signed decimal */
  91.     __s_sint,            /* %i signed integer */
  92.     __s_uoct,            /* %o unsigned octal */
  93.     __s_udec,            /* %u unsigned decimal */
  94.     __s_uhex,            /* %xX unsigned hex */
  95.     __s_fdbl,            /* %feEgG float (double) */
  96.     __s_ptr,            /* %p unsigned hex value of pointer */
  97.     __s_sdel            /* %[ delimited string */
  98. };
  99.  
  100.  
  101. /* __scanf() */
  102.  
  103. int
  104. __scanf (register FILE * f, const char *format, va_list ap, int *cnt)
  105. {
  106.   register const char *s1 = format;
  107.   register int n = 0;
  108.   register int c;
  109.  
  110.   for (;;)
  111.     {
  112.       if (!(c = *s1++))
  113.     goto ret;
  114.  
  115.       if (isspace (c))
  116.     continue;        /* white space in formatting string is ignored */
  117.  
  118.       if (c != '%')
  119.     {
  120.       register int m, l = 0;
  121.  
  122.     match:
  123.       do
  124.         {
  125.           if ((l++, m = getc (f)) < 0)
  126.         {
  127.           if (!n)
  128.             goto eof;
  129.           goto ret;
  130.         }
  131.         }
  132.       while (isspace (m));
  133.       __scnt += l;
  134.       if (m == c)
  135.         continue;
  136.       (void) ungetc (m, f);
  137.       goto ret;
  138.     }
  139.       else
  140.     {
  141.       if (!(c = *s1++))
  142.         goto ret;
  143.       if (c == '%')
  144.         goto match;
  145.     }
  146.  
  147.       {                /* we now have a % conversion */
  148.     register int i, j;
  149.     const char *s;
  150.  
  151. /* looking for "%[*][width][size]function" */
  152.  
  153. /* set __scflag */
  154.  
  155.     __scflag = 0;
  156.     if (c == '*')
  157.       {
  158.         if (!(c = *s1++))
  159.           goto ret;
  160.         __scflag = 1;
  161.       }
  162.  
  163. /* set __scwidth */
  164.  
  165.     __scwidth = 0;
  166.     if (isdigit (c))
  167.       {
  168.         __scwidth = (unsigned int) strtoul (s1 - 1, (char **) &s, 0);
  169.         s1 = s;
  170.         if (!(c = *s1++))
  171.           goto ret;
  172.         if (__scwidth > SCBUFSIZ)
  173.           __scwidth = SCBUFSIZ;
  174.       }
  175.  
  176. /* set __scsize */
  177.  
  178.     switch (c)
  179.       {
  180.       case 'h':
  181.         __scsize = 0;
  182.         if (!(c = *s1++))
  183.           goto ret;
  184.         break;
  185.       case 'l':
  186.         __scsize = 1;
  187.         if (!(c = *s1++))
  188.           goto ret;
  189.         break;
  190.       case 'L':
  191.         __scsize = 2;
  192.         if (!(c = *s1++))
  193.           goto ret;
  194.         break;
  195.       default:
  196.         __scsize = -1;
  197.         break;
  198.       }
  199.  
  200. /* call appropriate input function */
  201.  
  202.     i = (c == '[') ? 10 : __scfnc[(_tolower (c) - 'a') & 31];
  203.  
  204.     if (i >= 0)
  205.       {
  206.         s = s1;
  207.         j = (*__scfn[i]) (f, (va_list *) (&ap), &s);
  208.         s1 = s;
  209.  
  210.         if (j < 0 && !n)
  211.           goto eof;
  212.         else if (j <= 0)
  213.           goto ret;
  214.         else
  215.           {
  216.         __scnt += j;
  217.         if (!__scflag)
  218.           n++;
  219.           }
  220.       }
  221.     else
  222.       {
  223.         if (!n)
  224.           goto eof;
  225.         goto ret;
  226.       }
  227.       }
  228.     }
  229.  
  230. ret:*cnt = n;
  231.   return (__scnt);
  232.  
  233. eof:*cnt = 0;
  234.   return (-1);
  235. }
  236.  
  237.  
  238. /* __s_nin() */
  239.  
  240. static int
  241. __s_nin (register FILE * f, va_list * ap, const char **e)
  242. {
  243.   IGNORE (e);
  244.   IGNORE (f);
  245.   if (!__scflag)
  246.     {
  247.       switch (__scsize)
  248.     {
  249.     case 0:
  250.       *va_arg (*ap, short *) = (short) __scnt;
  251.       break;
  252.     case 1:
  253.       *va_arg (*ap, long *) = (long) __scnt;
  254.       break;
  255.     default:
  256.       *va_arg (*ap, int *) = (int) __scnt;
  257.       break;
  258.     }
  259.     }
  260.  
  261.   return (0);
  262. }
  263.  
  264. /* __s_char() */
  265.  
  266. static int
  267. __s_char (register FILE * f, va_list * ap, const char **e)
  268. {
  269.   register unsigned int w;
  270.   register int n = 0;
  271.   register char *s;
  272.   register int c;
  273.  
  274.   IGNORE (e);
  275.  
  276.   w = __scwidth;
  277.   if (!w)
  278.     w = 1;            /* default - 1 char */
  279.  
  280.   s = __scflag ? 0 : va_arg (*ap, char *);
  281.  
  282.   while (w)
  283.     {
  284.       if ((c = getc (f)) < 0)
  285.     return (n ? n : -1);
  286.       if (s)
  287.     *s++ = c;
  288.       n++, w--;
  289.     }
  290.  
  291.   return (n);
  292. }
  293.  
  294. /* __s_str() */
  295.  
  296. static int
  297. __s_str (register FILE * f, va_list * ap, const char **e)
  298. {
  299.   register unsigned int w;
  300.   register int n = 0;
  301.   register char *s;
  302.   register int c;
  303.  
  304.   IGNORE (e);
  305.  
  306.   w = __scwidth;
  307.   if (!w)
  308.     w = SCBUFSIZ;
  309.  
  310.   s = __scflag ? 0 : va_arg (*ap, char *);
  311.  
  312.   do
  313.     {
  314.       if ((c = getc (f)) < 0)
  315.     {
  316.       if (s)
  317.         *s = 0;
  318.       return (-1);
  319.     }
  320.     }
  321.   while (isspace (c));
  322.  
  323.   while (!isspace (c) && w)
  324.     {
  325.       if (s)
  326.     *s++ = c;
  327.       n++, w--;
  328.       if ((c = getc (f)) < 0)
  329.     {
  330.       if (s)
  331.         *s = 0;
  332.       return (n);
  333.     }
  334.     }
  335.  
  336.   if (s)
  337.     *s = 0;
  338.   (void) ungetc (c, f);
  339.  
  340.   return (n);
  341. }
  342.  
  343. /* __s_sdec() */
  344.  
  345. static int
  346. __s_sdec (register FILE * f, va_list * ap, const char **e)
  347. {
  348.   register unsigned int w;
  349.   register int n = 0;
  350.   register int c;
  351.   register int i = 0, i_ = 0;
  352.  
  353.   IGNORE (e);
  354.  
  355.   w = __scwidth;
  356.   if (!w)
  357.     w = SCBUFSIZ;
  358.  
  359.   do
  360.     {
  361.       if ((c = getc (f)) < 0)
  362.     return (-1);
  363.     }
  364.   while (isspace (c));
  365.  
  366.   if (c == '+' || c == '-')
  367.     {
  368.       if (c == '-')
  369.     i_ = 1;
  370.       n++, w--;
  371.       if ((c = getc (f)) < 0)
  372.     goto ret;
  373.     }
  374.  
  375.   while (isdigit (c) && w)
  376.     {
  377.       i = i * 10 + (c - '0');
  378.       n++, w--;
  379.       if ((c = getc (f)) < 0)
  380.     goto ret;
  381.     }
  382.  
  383.   (void) ungetc (c, f);
  384.  
  385. ret:if (!__scflag && n)
  386.     {
  387.       if (i_)
  388.     i = -i;
  389.       switch (__scsize)
  390.     {
  391.     case 0:
  392.       *va_arg (*ap, short *) = (short) i;
  393.       break;
  394.     case 1:
  395.       *va_arg (*ap, long *) = (long) i;
  396.       break;
  397.     default:
  398.       *va_arg (*ap, int *) = i;
  399.       break;
  400.     }
  401.     }
  402.  
  403.   return (n);
  404. }
  405.  
  406. /* __s_sint() */
  407.  
  408. static int
  409. __s_sint (register FILE * f, va_list * ap, const char **e)
  410. {
  411.   register unsigned int w;
  412.   register int n = 0;
  413.   register int c;
  414.   register int i = 0, i_ = 0;
  415.   register int b = 10;
  416.  
  417.   IGNORE (e);
  418.  
  419.   w = __scwidth;
  420.   if (!w)
  421.     w = SCBUFSIZ;
  422.  
  423.   do
  424.     {
  425.       if ((c = getc (f)) < 0)
  426.     return (-1);
  427.     }
  428.   while (isspace (c));
  429.  
  430.   if (c == '+' || c == '-')
  431.     {
  432.       if (c == '-')
  433.     i_ = 1;
  434.       n++, w--;
  435.       if ((c = getc (f)) < 0)
  436.     goto ret;
  437.     }
  438.  
  439.   if (c == '0' && w)
  440.     {
  441.       b = 010;
  442.       n++, w--;
  443.       if ((c = getc (f)) < 0)
  444.     goto ret;
  445.       if ((c == 'x' || c == 'X') && w)
  446.     {
  447.       b = 0x10;
  448.       n++, w--;
  449.       if ((c = getc (f)) < 0)
  450.         goto ret;
  451.     }
  452.     }
  453.  
  454.   switch (b)
  455.     {
  456.     case 010:
  457.       while (c >= '0' && c < '8' && w)
  458.     {
  459.       i = i * b + (c - '0');
  460.       n++, w--;
  461.       if ((c = getc (f)) < 0)
  462.         goto ret;
  463.     }
  464.       break;
  465.     case 10:
  466.       while (isdigit (c) && w)
  467.     {
  468.       i = i * b + (c - '0');
  469.       n++, w--;
  470.       if ((c = getc (f)) < 0)
  471.         goto ret;
  472.     }
  473.       break;
  474.     case 0x10:
  475.       while (isxdigit (c) && w)
  476.     {
  477.       i = i * b + ((c > '9') ? ((c & 31) + 9) : (c - '0'));
  478.       n++, w--;
  479.       if ((c = getc (f)) < 0)
  480.         goto ret;
  481.     }
  482.       break;
  483.     }
  484.  
  485.   (void) ungetc (c, f);
  486.  
  487. ret:if (!__scflag && n)
  488.     {
  489.       if (i_)
  490.     i = -i;
  491.       switch (__scsize)
  492.     {
  493.     case 0:
  494.       *va_arg (*ap, short *) = (short) i;
  495.       break;
  496.     case 1:
  497.       *va_arg (*ap, long *) = (long) i;
  498.       break;
  499.     default:
  500.       *va_arg (*ap, int *) = i;
  501.       break;
  502.     }
  503.     }
  504.  
  505.   return (n);
  506. }
  507.  
  508. /* __s_uoct() */
  509.  
  510. static int
  511. __s_uoct (register FILE * f, va_list * ap, const char **e)
  512. {
  513.   register unsigned int w;
  514.   register int n = 0;
  515.   register int c;
  516.   register unsigned int i = 0;
  517.  
  518.   IGNORE (e);
  519.  
  520.   w = __scwidth;
  521.   if (!w)
  522.     w = SCBUFSIZ;
  523.  
  524.   do
  525.     {
  526.       if ((c = getc (f)) < 0)
  527.     return (-1);
  528.     }
  529.   while (isspace (c));
  530.  
  531.   while (c >= '0' && c <= '7' && w)
  532.     {
  533.       i = i * 010 + (c - '0');
  534.       n++, w--;
  535.       if ((c = getc (f)) < 0)
  536.     goto ret;
  537.     }
  538.  
  539.   (void) ungetc (c, f);
  540.  
  541. ret:if (!__scflag && n)
  542.     {
  543.       switch (__scsize)
  544.     {
  545.     case 0:
  546.       *va_arg (*ap, short *) = (short) i;
  547.       break;
  548.     case 1:
  549.       *va_arg (*ap, long *) = (long) i;
  550.       break;
  551.     default:
  552.       *va_arg (*ap, int *) = i;
  553.       break;
  554.     }
  555.     }
  556.  
  557.   return (n);
  558. }
  559.  
  560. /* __s_udec() */
  561.  
  562. static int
  563. __s_udec (register FILE * f, va_list * ap, const char **e)
  564. {
  565.   register unsigned int w;
  566.   register int n = 0;
  567.   register int c;
  568.   register unsigned int i = 0;
  569.  
  570.   IGNORE (e);
  571.  
  572.   w = __scwidth;
  573.   if (!w)
  574.     w = SCBUFSIZ;
  575.  
  576.   do
  577.     {
  578.       if ((c = getc (f)) < 0)
  579.     return (-1);
  580.     }
  581.   while (isspace (c));
  582.  
  583.   while (isdigit (c) && w)
  584.     {
  585.       i = i * 10 + (c - '0');
  586.       n++, w--;
  587.       if ((c = getc (f)) < 0)
  588.     goto ret;
  589.     }
  590.  
  591.   (void) ungetc (c, f);
  592.  
  593. ret:if (!__scflag && n)
  594.     {
  595.       switch (__scsize)
  596.     {
  597.     case 0:
  598.       *va_arg (*ap, short *) = (short) i;
  599.       break;
  600.     case 1:
  601.       *va_arg (*ap, long *) = (long) i;
  602.       break;
  603.     default:
  604.       *va_arg (*ap, int *) = i;
  605.       break;
  606.     }
  607.     }
  608.  
  609.   return (n);
  610. }
  611.  
  612. /* __s_uhex() */
  613.  
  614. static int
  615. __s_uhex (register FILE * f, va_list * ap, const char **e)
  616. {
  617.   register unsigned int w;
  618.   register int n = 0;
  619.   register int c;
  620.   register unsigned int i = 0;
  621.  
  622.   IGNORE (e);
  623.  
  624.   w = __scwidth;
  625.   if (!w)
  626.     w = SCBUFSIZ;
  627.  
  628.   do
  629.     {
  630.       if ((c = getc (f)) < 0)
  631.     return (-1);
  632.     }
  633.   while (isspace (c));
  634.  
  635.   if (c == '0' && w)
  636.     {
  637.       n++, w--;
  638.       if ((c = getc (f)) < 0)
  639.     goto ret;
  640.       if ((c == 'x' || c == 'X') && w)
  641.     {
  642.       n++, w--;
  643.       if ((c = getc (f)) < 0)
  644.         goto ret;
  645.     }
  646.     }
  647.  
  648.   while (isxdigit (c) && w)
  649.     {
  650.       i = i * 0x10 + (isdigit (c) ? (c - '0') : ((c & 7) + 9));
  651.       n++, w--;
  652.       if ((c = getc (f)) < 0)
  653.     goto ret;
  654.     }
  655.  
  656.   (void) ungetc (c, f);
  657.  
  658. ret:if (!__scflag && n)
  659.     {
  660.       switch (__scsize)
  661.     {
  662.     case 0:
  663.       *va_arg (*ap, short *) = (short) i;
  664.       break;
  665.     case 1:
  666.       *va_arg (*ap, long *) = (long) i;
  667.       break;
  668.     default:
  669.       *va_arg (*ap, int *) = i;
  670.       break;
  671.     }
  672.     }
  673.  
  674.   return (n);
  675. }
  676.  
  677. /* __s_fdbl() */
  678.  
  679. static int
  680. __s_fdbl (register FILE * f, va_list * ap, const char **e)
  681. {
  682.   register unsigned int w;
  683.   register int n = 0;
  684.   register int c;
  685.   register double i;
  686.   register char *s;
  687.   register int l = 0;
  688.  
  689. #define F_SIGN    0001
  690. #define F_DP    0002
  691. #define F_XP    0004
  692. #define F_XSIGN 0010
  693.  
  694.   IGNORE (e);
  695.  
  696.   if (!__scflag)
  697.     {
  698.       if (!(s = __sbuf))
  699.     if (!(s = __sbuf = malloc (SCBUFSIZ)))
  700.       return (0);
  701.     }
  702.   else
  703.     s = 0;
  704.  
  705.   w = __scwidth;
  706.   if (!w)
  707.     w = SCBUFSIZ;
  708.  
  709.   do
  710.     {
  711.       if ((c = getc (f)) < 0)
  712.     return (-1);
  713.     }
  714.   while (isspace (c));
  715.  
  716.   if ((c == '-' || c == '+') && !(l & F_SIGN))
  717.     {
  718.       l |= F_SIGN;
  719.       goto l1;
  720.     }
  721.  
  722.   if (!isdigit (c))
  723.     goto l2;
  724.  
  725. l1:
  726.  
  727.   if (!w)
  728.     goto ret;
  729.  
  730.   if (s)
  731.     *s++ = c;
  732.   n++, w--;
  733.   if ((c = getc (f)) < 0)
  734.     goto ret;
  735.  
  736.   if (isdigit (c))
  737.     goto l1;
  738.  
  739. l2:
  740.  
  741.   if ((c == '-' || c == '+') && (l & F_XP) && !(l & F_XSIGN))
  742.     {
  743.       l |= F_XSIGN;
  744.       goto l1;
  745.     }
  746.   if (c == '.' && !(l & F_DP))
  747.     {
  748.       l |= F_DP;
  749.       goto l1;
  750.     }
  751.   if ((c == 'e' || c == 'E') && !(l & F_XP))
  752.     {
  753.       l |= F_XP;
  754.       goto l1;
  755.     }
  756.  
  757. ret:if (c >= 0)
  758.     (void) ungetc (c, f);
  759.  
  760.   if (!__scflag && n)
  761.     {
  762.       *s = 0;
  763.       i = strtod (__sbuf, 0);
  764.       switch (__scsize)
  765.     {
  766.     case 2:
  767.       *va_arg (*ap, long double *) = (long double) i;
  768.       break;
  769.     case 1:
  770.       *va_arg (*ap, double *) = i;
  771.       break;
  772.     default:
  773.       *va_arg (*ap, float *) = (float) i;
  774.       break;
  775.     }
  776.     }
  777.  
  778.   return (n);
  779.  
  780. #undef F_SIGN
  781. #undef F_DP
  782. #undef F_XP
  783. #undef F_XSIGN
  784. }
  785.  
  786. /* __s_ptr() */
  787.  
  788. static int
  789. __s_ptr (register FILE * f, va_list * ap, const char **e)
  790. {
  791.   return (__s_uhex (f, ap, e));
  792. }
  793.  
  794. /* __s_sdel() */
  795.  
  796. static int
  797. __s_sdel (register FILE * f, va_list * ap, const char **e)
  798. {
  799.   register const char *o;
  800.   register char *s, *d;
  801.   register int w, n = 0, m = 0, c;
  802.  
  803.   if (!(d = __sbuf))
  804.     if (!(d = __sbuf = malloc (SCBUFSIZ)))
  805.       return (0);
  806.  
  807.   o = (*e);
  808.   if (*o == '^')
  809.     o++, m++;
  810.  
  811.   w = SCBUFSIZ;
  812.   if (*o == ']')
  813.     *d++ = *o++, w--;
  814.  
  815.   while (w--)
  816.     {
  817.       if (!(c = *o++) || c == ']')
  818.     break;
  819.       *d++ = c;
  820.     }
  821.  
  822.   (*e) = o;
  823.   *d = 0;
  824.   d = __sbuf;
  825.  
  826.   w = __scwidth;
  827.   if (!w)
  828.     w = SCBUFSIZ;
  829.  
  830.   s = __scflag ? 0 : va_arg (*ap, char *);
  831.  
  832.   if ((c = getc (f)) < 0)
  833.     {
  834.       if (s)
  835.     *s = 0;
  836.       return (-1);
  837.     }
  838.  
  839.   while (w--)
  840.     {
  841.       if (!strchr (d, c) ^ m)
  842.     break;
  843.       if (s)
  844.     *s++ = c;
  845.       n++;
  846.       if ((c = getc (f)) < 0)
  847.     goto ret;
  848.     }
  849.  
  850.   (void) ungetc (c, f);
  851.  
  852. ret:if (s)
  853.     *s = 0;
  854.  
  855.   return (n);
  856. }
  857.