home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / compiler / clib / __vcscan.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-28  |  8.6 KB  |  451 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: __vcscan.c,v 1.1 1997/01/28 15:32:32 digulla Exp $
  4.  
  5.     Desc: Function to scan a string like scanf().
  6.     Lang: english
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <stdarg.h>
  11. #include <limits.h>
  12. #include <ctype.h>
  13. #include <math.h>
  14.  
  15. /* some macros to cut this short
  16.  * NEXT(c);     read next character
  17.  * PREV(c);     ungetc a character
  18.  * VAL(a)       leads to 1 if a is true and valid
  19.  */
  20. #define NEXT(c) ((c)=(*getc)(data),size++,incount++)
  21. #define PREV(c) do{if((c)!=EOF)(*ungetc)((c),data);size--;incount--;}while(0)
  22. #define VAL(a)  ((a)&&size<=width)
  23.  
  24. extern unsigned char *__decimalpoint;
  25.  
  26. #ifdef FULL_SPECIFIERS
  27. static unsigned char undef[3][sizeof(double)]= /* Undefined numeric values, IEEE */
  28. { { 0x7f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* +inf */
  29.   { 0xff,0xf0,0x00,0x00,0x00,0x00,0x00,0x00 }, /* -inf */
  30.   { 0x7f,0xf1,0x00,0x00,0x00,0x00,0x00,0x00 }  /*  NaN */
  31. };
  32. #endif
  33.  
  34. /*****************************************************************************
  35.  
  36.     NAME */
  37.  
  38.     int __vcscan (
  39.  
  40. /*  SYNOPSIS */
  41.     void       * data,
  42.     int      (* getc)(void *),
  43.     int      (* ungetc)(int,void *),
  44.     const char * format,
  45.     va_list      args)
  46.  
  47. /*  FUNCTION
  48.     Scan an input stream as specified in format. The result of
  49.     the scan will be placed in args.
  50.  
  51.     INPUTS
  52.     data - This is passed to the usercallback getc and ungetc
  53.     getc - This function gets called when the routine wants to
  54.         read the next character. It whould return EOF when
  55.         no more characters are available.
  56.     ungetc - This function gets called when the routine wants to
  57.         put a read character back into the stream. The next
  58.         call to getc should return this character. It is possible
  59.         that this function is called more than once before the
  60.         next getc.
  61.     format - A scanf() format string.
  62.     args - A list of arguments in which the result of the scan should
  63.         be placed.
  64.  
  65.     RESULT
  66.     The number of arguments converted.
  67.  
  68.     NOTES
  69.  
  70.     EXAMPLE
  71.  
  72.     BUGS
  73.  
  74.     SEE ALSO
  75.  
  76.     INTERNALS
  77.  
  78.     HISTORY
  79.     06.12.1996 digulla copied from libnix
  80.  
  81. ******************************************************************************/
  82. {
  83.   size_t blocks=0,incount=0;
  84.   int c=0;
  85.  
  86.   while(*format)
  87.   {
  88.     size_t size=0;
  89.  
  90.     if(*format=='%')
  91.     {
  92.       size_t width=ULONG_MAX;
  93.       char type,subtype='i',ignore=0;
  94.       const unsigned char *ptr=format+1;
  95.       size_t i;
  96.  
  97.       if(isdigit(*ptr))
  98.       { width=0;
  99.     while(isdigit(*ptr))
  100.       width=width*10+(*ptr++-'0'); }
  101.  
  102.       while(*ptr=='h'||*ptr=='l'||*ptr=='L'||*ptr=='*')
  103.       { if(*ptr=='*')
  104.       ignore=1;
  105.     else
  106.       subtype=*ptr;
  107.     ptr++;
  108.       }
  109.  
  110.       type=*ptr++;
  111.  
  112.       if(type&&type!='%'&&type!='c'&&type!='n'&&type!='[')
  113.       { do /* ignore leading whitespace characters */
  114.       NEXT(c);
  115.     while(isspace(c));
  116.     size=1; } /* The first non-whitespace character is already read */
  117.  
  118.       switch(type)
  119.       { case 'c':
  120.     { unsigned char *bp;
  121.  
  122.       if(width==ULONG_MAX) /* Default */
  123.         width=1;
  124.  
  125.       if(!ignore)
  126.         bp=va_arg(args,char *);
  127.       else
  128.         bp=NULL; /* Just to get the compiler happy */
  129.  
  130.       NEXT(c); /* 'c' did not skip whitespace */
  131.       while(VAL(c!=EOF))
  132.       { if(!ignore)
  133.           *bp++=c;
  134.         NEXT(c);
  135.       }
  136.       PREV(c);
  137.  
  138.       if(!ignore&&size)
  139.         blocks++;
  140.       break;
  141.     }
  142.     case '[':
  143.     { unsigned char *bp;
  144.       unsigned char tab[32],a,b;
  145.       char circflag=0;
  146.  
  147.       if(*ptr=='^')
  148.       { circflag=1;
  149.         ptr++; }
  150.       for(i=0;i<sizeof(tab);i++)
  151.         tab[i]=circflag?255:0;
  152.       for(;;)
  153.       { if(!*ptr)
  154.           break;
  155.         a=b=*ptr++;
  156.         if(*ptr=='-'&&ptr[1]&&ptr[1]!=']')
  157.         { ptr++;
  158.           b=*ptr++; }
  159.         for(i=a;i<=b;i++)
  160.           if(circflag)
  161.         tab[i/8]&=~(1<<(i&7));
  162.           else
  163.         tab[i/8]|=1<<(i&7);
  164.         if(*ptr==']')
  165.         { ptr++;
  166.           break; }
  167.       }
  168.  
  169.       if(!ignore)
  170.         bp=va_arg(args,char *);
  171.       else
  172.         bp=NULL; /* Just to get the compiler happy */
  173.  
  174.       NEXT(c);
  175.       while(VAL(c!=EOF&&tab[c/8]&(1<<(c&7))))
  176.       { if(!ignore)
  177.           *bp++=c;
  178.         NEXT(c);
  179.       }
  180.       PREV(c);
  181.  
  182.       if(!ignore&&size)
  183.       { *bp++='\0';
  184.         blocks++; }
  185.       break;
  186.     }
  187.     case 's':
  188.     { unsigned char *bp;
  189.  
  190.       if(!ignore)
  191.         bp=va_arg(args,char *);
  192.       else
  193.         bp=NULL; /* Just to get the compiler happy */
  194.  
  195.       while(VAL(c!=EOF&&!isspace(c)))
  196.       { if(!ignore)
  197.           *bp++=c;
  198.         NEXT(c);
  199.       }
  200.       PREV(c);
  201.  
  202.       if(!ignore&&size)
  203.       { *bp++='\0';
  204.         blocks++; }
  205.       break;
  206.     }
  207. #ifdef FULL_SPECIFIERS
  208.     case 'e':
  209.     case 'f':
  210.     case 'g':
  211.     { double v;
  212.       int ex=0;
  213.       int min=0,mine=0; /* This is a workaround for gcc 2.3.3: should be char */
  214.  
  215.       do /* This is there just to be able to break out */
  216.       {
  217.         if(VAL(c=='-'||c=='+'))
  218.         { min=c;
  219.           NEXT(c); }
  220.  
  221.         if(VAL(tolower(c)=='i')) /* +- inf */
  222.         { int d;
  223.           NEXT(d);
  224.           if(VAL(tolower(d)=='n'))
  225.           { int e;
  226.         NEXT(e);
  227.         if(VAL(tolower(e)=='f'))
  228.         { v=*(double *)&undef[min=='-'];
  229.           break; } /* break out */
  230.         PREV(e);
  231.           }
  232.           PREV(d);
  233.         }
  234.         else if(VAL(toupper(c)=='N')) /* NaN */
  235.         { int d;
  236.           NEXT(d);
  237.           if(VAL(tolower(d)=='a'))
  238.           { int e;
  239.         NEXT(e);
  240.         if(VAL(toupper(e)=='N'))
  241.         { v=*(double *)&undef[2];
  242.           break; }
  243.         PREV(e);
  244.           }
  245.           PREV(d);
  246.         }
  247.  
  248.         v=0.0;
  249.         while(VAL(isdigit(c)))
  250.         { v=v*10.0+(c-'0');
  251.           NEXT(c);
  252.         }
  253.  
  254.         if(VAL(c==__decimalpoint[0]))
  255.         { double dp=0.1;
  256.           NEXT(c);
  257.           while(VAL(isdigit(c)))
  258.           { v=v+dp*(c-'0');
  259.         dp=dp/10.0;
  260.         NEXT(c); }
  261.           if(size==2+(min!=0)) /* No number read till now -> malformatted */
  262.           { PREV(c);
  263.         c=__decimalpoint[0]; }
  264.         }
  265.  
  266.         if(min&&size==2) /* No number read till now -> malformatted */
  267.         { PREV(c);
  268.           c=min; }
  269.         if(size==1)
  270.           break;
  271.  
  272.         if(VAL(tolower(c)=='e'))
  273.         { int d;
  274.           NEXT(d);
  275.           if(VAL(d=='-'||d=='+'))
  276.           { mine=d;
  277.         NEXT(d); }
  278.  
  279.           if(VAL(isdigit(d)))
  280.           { do
  281.         { ex=ex*10+(d-'0');
  282.           NEXT(d);
  283.         }while(VAL(isdigit(d)&&ex<100));
  284.         c=d;
  285.           }else
  286.           { PREV(d);
  287.         if(mine)
  288.           PREV(mine);
  289.           }
  290.         }
  291.         PREV(c);
  292.  
  293.         if(mine=='-')
  294.           v=v/pow(10.0,ex);
  295.         else
  296.           v=v*pow(10.0,ex);
  297.  
  298.         if(min=='-')
  299.           v=-v;
  300.  
  301.       }while(0);
  302.  
  303.       if(!ignore&&size)
  304.       { switch(subtype)
  305.         { case 'l':
  306.           case 'L':
  307.         *va_arg(args,double *)=v;
  308.         break;
  309.           case 'i':
  310.         *va_arg(args,float *)=v;
  311.         break;
  312.         }
  313.         blocks++;
  314.       }
  315.       break;
  316.     }
  317. #endif
  318.     case '%':
  319.       NEXT(c);
  320.       if(c!='%')
  321.         PREV(c); /* unget non-'%' character */
  322.       break;
  323.     case 'n':
  324.       if(!ignore)
  325.         *va_arg(args,int *)=incount;
  326.       size=1; /* fake a valid argument */
  327.       blocks++;
  328.       break;
  329.     default:
  330.     { unsigned long v=0;
  331.       int base;
  332.       int min=0;
  333.  
  334.       if(!type)
  335.         ptr--; /* unparse NUL character */
  336.  
  337.       if(type=='p')
  338.       { subtype='l'; /* This is the same as %lx */
  339.         type='x'; }
  340.  
  341.       if(VAL((c=='-'&&type!='u')||c=='+'))
  342.       { min=c;
  343.         NEXT(c); }
  344.  
  345.       if(type=='i') /* which one to use ? */
  346.       { if(VAL(c=='0')) /* Could be octal or sedecimal */
  347.         { int d;
  348.           NEXT(d); /* Get a look at next character */
  349.           if(VAL(tolower(d)=='x'))
  350.           { int e;
  351.         NEXT(e); /* And the next */
  352.         if(VAL(isxdigit(c)))
  353.           type='x'; /* Is a valid x number with '0x?' */
  354.         PREV(e);
  355.           }else
  356.         type='o';
  357.           PREV(d);
  358.         }else if(VAL(!isdigit(c)&&isxdigit(c)))
  359.           type='x'; /* Is a valid x number without '0x' */
  360.       }
  361.  
  362.       while(type=='x'&&VAL(c=='0')) /* sedecimal */
  363.       { int d;
  364.         NEXT(d);
  365.         if(VAL(tolower(d)=='x'))
  366.         { int e;
  367.           NEXT(e);
  368.           if(VAL(isxdigit(e)))
  369.           { c=e;
  370.         break; } /* Used while just to do this ;-) */
  371.           PREV(e);
  372.         }
  373.         PREV(d);
  374.         break; /* Need no loop */
  375.       }
  376.  
  377.       base=type=='x'||type=='X'?16:(type=='o'?8:10);
  378.       while(VAL(isxdigit(c)&&(base!=10||isdigit(c))&&(base!=8||c<='7')))
  379.       { v=v*base+(isdigit(c)?c-'0':0)+(isupper(c)?c-'A'+10:0)+(islower(c)?c-'a'+10:0);
  380.         NEXT(c);
  381.       }
  382.  
  383.       if(min&&size==2) /* If there is no valid character after sign, unget last */
  384.       { PREV(c);
  385.         c=min; }
  386.  
  387.       PREV(c);
  388.  
  389.       if(ignore||!size)
  390.         break;
  391.  
  392.       if(type=='u')
  393.         switch(subtype)
  394.         { case 'l':
  395.           case 'L':
  396.         *va_arg(args,unsigned long *)=v;
  397.         break;
  398.           case 'i':
  399.         *va_arg(args,unsigned int *)=v;
  400.         break;
  401.           case 'h':
  402.         *va_arg(args,unsigned short *)=v;
  403.         break;
  404.         }
  405.       else
  406.       { signed long v2;
  407.         if(min=='-')
  408.           v2=-v;
  409.         else
  410.           v2=v;
  411.         switch(subtype)
  412.         { case 'l':
  413.           case 'L':
  414.         *va_arg(args,signed long *)=v2;
  415.         break;
  416.           case 'i':
  417.         *va_arg(args,signed int *)=v2;
  418.         break;
  419.           case 'h':
  420.         *va_arg(args,signed short *)=v2;
  421.         break;
  422.         }
  423.       }
  424.       blocks++;
  425.       break;
  426.     }
  427.       }
  428.       format=ptr;
  429.     }else
  430.     { if(isspace(*format))
  431.       { do
  432.       NEXT(c);
  433.     while(isspace(c));
  434.     PREV(c);
  435.     size=1; }
  436.       else
  437.       { NEXT(c);
  438.     if(c!=*format)
  439.       PREV(c); }
  440.       format++;
  441.     }
  442.     if(!size)
  443.       break;
  444.   }
  445.  
  446.   if(c==EOF&&!blocks)
  447.     return c;
  448.   else
  449.     return blocks;
  450. }
  451.