Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <ctype.h>
  6. #include <libc/file.h>
  7. #include <libc/local.h>
  8. #include <stdarg.h>
  9.  
  10. #define SPC     01
  11. #define STP     02
  12.  
  13. #define SHORT   0
  14. #define REGULAR 1
  15. #define LONG    2
  16. #define LONGDOUBLE 4
  17. #define INT     0
  18. #define FLOAT   1
  19.  
  20. static int _innum(void *ptr, int type, int len, int size, FILE *iop,
  21.                   int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *),
  22.                   int *eofptr);
  23. static int _instr(char *ptr, int type, int len, FILE *iop,
  24.                   int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *),
  25.                   int *eofptr);
  26. static const char *_getccl(const unsigned char *s);
  27.  
  28. static char _sctab[256] = {
  29.         0,0,0,0,0,0,0,0,
  30.         0,SPC,SPC,SPC,SPC,SPC,0,0,
  31.         0,0,0,0,0,0,0,0,
  32.         0,0,0,0,0,0,0,0,
  33.         SPC,0,0,0,0,0,0,0,
  34.         0,0,0,0,0,0,0,0,
  35.         0,0,0,0,0,0,0,0,
  36.         0,0,0,0,0,0,0,0,
  37. };
  38.  
  39. static int nchars = 0;
  40.  
  41. int
  42. _doscan(FILE *iop, const char *fmt, va_list argp)
  43. {
  44.   return(_doscan_low(iop, fgetc, ungetc, fmt, argp));
  45. }
  46.  
  47. int
  48. _doscan_low(FILE *iop, int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *),
  49.             const char *fmt, va_list argp)
  50. {
  51.   register int ch;
  52.   int nmatch, len, ch1;
  53.   void* ptr;
  54.   int fileended, size;
  55.  
  56.   nchars = 0;
  57.   nmatch = 0;
  58.   fileended = 0;
  59.   for (;;) switch (ch = *fmt++) {
  60.   case '\0':
  61.     return (nmatch);
  62.   case '%':
  63.     if ((ch = *fmt++) == '%')
  64.       goto def;
  65.     if (ch == 'n')
  66.     {
  67.       int* arg = va_arg(argp, int*);
  68.       *arg = nchars;
  69.       break;
  70.     }
  71.     if (fileended)
  72.       return(nmatch? nmatch: -1);
  73.     ptr = 0;
  74.     if (ch != '*')
  75.       ptr = va_arg(argp, void*);
  76.     else
  77.       ch = *fmt++;
  78.     len = 0;
  79.     size = REGULAR;
  80.     while (isdigit(ch)) {
  81.       len = len*10 + ch - '0';
  82.       ch = *fmt++;
  83.     }
  84.     if (len == 0)
  85.       len = 30000;
  86.     if (ch=='l') {
  87.       size = LONG;
  88.       ch = *fmt++;
  89.     } else if (ch=='h') {
  90.       size = SHORT;
  91.       ch = *fmt++;
  92.     } else if (ch=='L') {
  93.       size = LONGDOUBLE;
  94.       ch = *fmt++;
  95.     } else if (ch=='[')
  96.       fmt = _getccl((const unsigned char *)fmt);
  97.     if (isupper(ch)) {
  98.       /* ch = tolower(ch);
  99.          gcc gives warning: ANSI C forbids braced
  100.          groups within expressions */
  101.       ch += 'a' - 'A';
  102.       size = LONG;
  103.     }
  104.     if (ch == '\0')
  105.       return(-1);
  106.     if (_innum(ptr, ch, len, size, iop, scan_getc, scan_ungetc,
  107.                &fileended) && ptr)
  108.       nmatch++;
  109. /* breaks %n */
  110. /*    if (fileended) {
  111.       return(nmatch? nmatch: -1);
  112.     } */
  113.     break;
  114.   case ' ':
  115.   case '\n':
  116.   case '\t':
  117.   case '\r':
  118.   case '\f':
  119.   case '\v':
  120.     while (((nchars++, ch1 = scan_getc(iop))!=EOF) && (_sctab[ch1] & SPC))
  121.       ;
  122.     if (ch1 != EOF)
  123.     {
  124.       scan_ungetc(ch1, iop);
  125.     }
  126.     nchars--;
  127.     break;
  128.  
  129.   default:
  130.   def:
  131.     ch1 = scan_getc(iop);
  132.     if (ch1 != EOF) nchars++;
  133.     if (ch1 != ch) {
  134.       if (ch1==EOF)
  135.         return(-1);
  136.       scan_ungetc(ch1, iop);
  137.       nchars--;
  138.       return(nmatch);
  139.     }
  140.   }
  141. }
  142.  
  143. static int
  144. _innum(void *ptr, int type, int len, int size, FILE *iop,
  145.        int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr)
  146. {
  147.   register char *np;
  148.   char numbuf[64];
  149.   register c, base;
  150.   int expseen, scale, negflg, c1, ndigit;
  151.   long lcval;
  152.   int cpos;
  153.  
  154.   if (type=='c' || type=='s' || type=='[')
  155.     return(_instr(ptr, type, len,
  156.                   iop, scan_getc, scan_ungetc, eofptr));
  157.   lcval = 0;
  158.   ndigit = 0;
  159.   scale = INT;
  160.   if (type=='e'||type=='f'||type=='g')
  161.     scale = FLOAT;
  162.   base = 10;
  163.   if (type=='o')
  164.     base = 8;
  165.   else if (type=='x')
  166.     base = 16;
  167.   np = numbuf;
  168.   expseen = 0;
  169.   negflg = 0;
  170.   while (((nchars++, c = scan_getc(iop)) != EOF) && (_sctab[c] & SPC))
  171.     ;
  172.   if (c == EOF) nchars--;
  173.   if (c=='-') {
  174.     negflg++;
  175.     *np++ = c;
  176.     c = scan_getc(iop);
  177.     nchars++;
  178.     len--;
  179.   } else if (c=='+') {
  180.     len--;
  181.     c = scan_getc(iop);
  182.     nchars++;
  183.   }
  184.   cpos = 0;
  185.   for ( ; --len>=0; *np++ = c, c = scan_getc(iop), nchars++) {
  186.     cpos++;
  187.     if (c == '0' && cpos == 1 && type == 'i')
  188.       base = 8;
  189.     if ((c == 'x' || c == 'X') && (type == 'i' || type == 'x')
  190.         && cpos == 2 && lcval == 0)
  191.     {
  192.       base = 16;
  193.       continue;
  194.     }
  195.     if (isdigit(c)
  196.         || (base==16 && (('a'<=c && c<='f') || ('A'<=c && c<='F')))) {
  197.       ndigit++;
  198.       if (base==8)
  199.         lcval <<=3;
  200.       else if (base==10)
  201.         lcval = ((lcval<<2) + lcval)<<1;
  202.       else
  203.         lcval <<= 4;
  204.       c1 = c;
  205.       if (isdigit(c))
  206.         c -= '0';
  207.       else if ('a'<=c && c<='f')
  208.         c -= 'a'-10;
  209.       else
  210.         c -= 'A'-10;
  211.       lcval += c;
  212.       c = c1;
  213.       continue;
  214.     } else if (c=='.') {
  215.       if (base!=10 || scale==INT)
  216.         break;
  217.       ndigit++;
  218.       continue;
  219.     } else if ((c=='e'||c=='E') && expseen==0) {
  220.       if (base!=10 || scale==INT || ndigit==0)
  221.         break;
  222.       expseen++;
  223.       *np++ = c;
  224.       c = scan_getc(iop);
  225.       nchars++;
  226.       if (c!='+'&&c!='-'&&('0'>c||c>'9'))
  227.         break;
  228.     } else
  229.       break;
  230.   }
  231.   if (negflg)
  232.     lcval = -lcval;
  233.   if (c != EOF) {
  234.     scan_ungetc(c, iop);
  235.     *eofptr = 0;
  236.   } else
  237.     *eofptr = 1;
  238.   nchars--;
  239.   if (ptr==NULL || np==numbuf || (negflg && np==numbuf+1) ) /* gene dykes*/
  240.     return(0);
  241.   *np++ = 0;
  242.   switch((scale<<4) | size) {
  243.  
  244.   case (FLOAT<<4) | SHORT:
  245.   case (FLOAT<<4) | REGULAR:
  246.     *(float *)ptr = atof(numbuf);
  247.     break;
  248.  
  249.   case (FLOAT<<4) | LONG:
  250.     *(double *)ptr = atof(numbuf);
  251.     break;
  252.  
  253.   case (FLOAT<<4) | LONGDOUBLE:
  254.     *(long double *)ptr = _atold(numbuf);
  255.     break;
  256.  
  257.   case (INT<<4) | SHORT:
  258.     *(short *)ptr = (short)lcval;
  259.     break;
  260.  
  261.   case (INT<<4) | REGULAR:
  262.     *(int *)ptr = (int)lcval;
  263.     break;
  264.  
  265.   case (INT<<4) | LONG:
  266.   case (INT<<4) | LONGDOUBLE:
  267.     *(long *)ptr = lcval;
  268.     break;
  269.   }
  270.   return(1);
  271. }
  272.  
  273. static int
  274. _instr(char *ptr, int type, int len, FILE *iop,
  275.        int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr)
  276. {
  277.   register ch;
  278.   register char *optr;
  279.   int ignstp;
  280.  
  281.   *eofptr = 0;
  282.   optr = ptr;
  283.   if (type=='c' && len==30000)
  284.     len = 1;
  285.   ignstp = 0;
  286.   if (type=='s')
  287.     ignstp = SPC;
  288.   while ((nchars++, ch = scan_getc(iop)) != EOF && _sctab[ch] & ignstp)
  289.     ;
  290.   ignstp = SPC;
  291.   if (type=='c')
  292.     ignstp = 0;
  293.   else if (type=='[')
  294.     ignstp = STP;
  295.   while (ch!=EOF && (_sctab[ch]&ignstp)==0) {
  296.     if (ptr)
  297.       *ptr++ = ch;
  298.     if (--len <= 0)
  299.       break;
  300.     ch = scan_getc(iop);
  301.     nchars++;
  302.   }
  303.   if (ch != EOF) {
  304.     if (len > 0)
  305.     {
  306.       scan_ungetc(ch, iop);
  307.       nchars--;
  308.     }
  309.     *eofptr = 0;
  310.   } else
  311.   {
  312.     nchars--;
  313.     *eofptr = 1;
  314.   }
  315.   if (ptr && ptr!=optr) {
  316.     if (type!='c')
  317.       *ptr++ = '\0';
  318.     return(1);
  319.   }
  320.   return(0);
  321. }
  322.  
  323. static const char *
  324. _getccl(const unsigned char *s)
  325. {
  326.   register c, t;
  327.  
  328.   t = 0;
  329.   if (*s == '^') {
  330.     t++;
  331.     s++;
  332.   }
  333.   for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++)
  334.     if (t)
  335.       _sctab[c] &= ~STP;
  336.     else
  337.       _sctab[c] |= STP;
  338.   if ((c = *s) == ']' || c == '-') { /* first char is special */
  339.     if (t)
  340.       _sctab[c] |= STP;
  341.     else
  342.       _sctab[c] &= ~STP;
  343.     s++;
  344.   }
  345.   while ((c = *s++) != ']') {
  346.     if (c==0)
  347.       return((const char *)--s);
  348.     else if (c == '-' && *s != ']' && s[-2] < *s) {
  349.       for (c = s[-2] + 1; c < *s; c++)
  350.         if (t)
  351.           _sctab[c] |= STP;
  352.         else
  353.           _sctab[c] &= ~STP;
  354.     } else if (t)
  355.       _sctab[c] |= STP;
  356.     else
  357.       _sctab[c] &= ~STP;
  358.   }
  359.   return((const char *)s);
  360. }
  361.