home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / OS2 / EMXFIX04.ZIP / INPUT.C < prev    next >
C/C++ Source or Header  |  1994-01-22  |  13KB  |  607 lines

  1. /* input.c (emx+gcc) -- Copyright (c) 1990-1994 by Eberhard Mattes */
  2.  
  3. #include <sys/emx.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <stdarg.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #include <setjmp.h>
  10. #include <limits.h>
  11.  
  12. #define JEOF       1     /* longjmp: EOF reached */
  13. #define JDONE      2     /* longjmp: input doesn't match */
  14.  
  15. /* This structure holds the local variables of _input() which are
  16.    passed to the functions called by _input(). */
  17.  
  18. typedef struct
  19. {
  20.   FILE *stream;                 /* Where input comes from */
  21.   int width;                    /* Field width or what's left over of it */
  22.   int chars;                    /* Number of characters read */
  23.   int volatile count;           /* Number of fields assigned */
  24.   char * volatile more;         /* Big buffer for %e format */
  25.   int collected;                /* Number of characters collected */
  26.   size_t more_size;             /* Size of the above */
  27.   char size;                    /* Size (0, 'h', 'l' or 'L') */
  28.   char at_eof;                  /* End of file or string reached */
  29.   jmp_buf jump;                 /* Jump there when done or on error */
  30. } ilocal;
  31.  
  32.  
  33. static unsigned char next (ilocal *v)
  34. {
  35.   int c;
  36.  
  37.   c = getc (v->stream);
  38.   if (c == EOF)
  39.     longjmp (v->jump, JEOF);
  40.   ++v->chars;
  41.   return ((unsigned char)c);
  42. }
  43.  
  44.  
  45. static int get (ilocal *v, unsigned char *pc)
  46. {
  47.   int c;
  48.  
  49.   c = getc (v->stream);
  50.   if (c == EOF)
  51.     {
  52.       v->at_eof = 1;
  53.       return (0);
  54.     }
  55.   *pc = (unsigned char)c;
  56.   ++v->chars;
  57.   return (1);
  58. }
  59.  
  60.  
  61. static void push_back (ilocal *v, unsigned char c)
  62. {
  63.   ungetc (c, v->stream);
  64.   --v->chars;
  65. }
  66.  
  67.  
  68. #define COLLECT(X) collect (v, buf, sizeof (buf), X)
  69.  
  70. static void collect (ilocal *v, unsigned char *buf, size_t buf_size,
  71.                      unsigned char c)
  72. {
  73.   if (v->more == NULL && v->collected < buf_size)
  74.     buf[v->collected] = c;
  75.   else
  76.     {
  77.       if (v->collected >= v->more_size)
  78.         {
  79.           v->more_size += 512;
  80.           v->more = realloc (v->more, v->more_size);
  81.           if (v->more == NULL)
  82.             longjmp (v->jump, JDONE);
  83.           if (v->collected == buf_size)
  84.             memcpy (v->more, buf, buf_size);
  85.         }
  86.       v->more[v->collected] = c;
  87.     }
  88.   ++v->collected;
  89. }
  90.  
  91.  
  92. static unsigned char skip (ilocal *v)
  93. {
  94.   unsigned char c;
  95.  
  96.   do
  97.     {
  98.       c = next (v);
  99.     } while (isspace (c));
  100.   return (c);
  101. }
  102.  
  103.  
  104. static void inp_char (ilocal *v, unsigned char *dst)
  105. {
  106.   unsigned char c;
  107.   int width;
  108.  
  109.   width = ((v->width == INT_MAX) ? 1 : v->width);
  110.   while (width > 0)
  111.     {
  112.       --width;
  113.       c = next (v);
  114.       if (dst != NULL)
  115.         {
  116.           *dst++ = c;
  117.           ++v->count;
  118.         }
  119.     }
  120. }
  121.  
  122.  
  123. static void inp_string (ilocal *v, unsigned char c, char *map, char end,
  124.                         unsigned char *dst)
  125. {
  126.   while (v->width > 0 && map[c] != end)
  127.     {
  128.       --v->width;
  129.       if (dst != NULL)
  130.         *dst++ = c;
  131.       if (!get (v, &c))
  132.         break;
  133.     }
  134.   if (dst != NULL)
  135.     {
  136.       *dst = 0;
  137.       ++v->count;
  138.     }
  139.   if (v->at_eof)
  140.     longjmp (v->jump, JEOF);
  141.   push_back (v, c);
  142. }
  143.  
  144.  
  145. static void inp_str (ilocal *v, unsigned char *dst)
  146. {
  147.   char map[256];
  148.   unsigned char c;
  149.  
  150.   memset (map, 0, 256);
  151.   map[' '] = 1;
  152.   map['\n'] = 1;
  153.   map['\t'] = 1;
  154.   c = skip (v);
  155.   inp_string (v, c, map, 1, dst);
  156. }
  157.  
  158.  
  159. static void inp_set (ilocal *v, const char **pfmt, void *dst)
  160. {
  161.   char map[256], end, done;
  162.   unsigned char f;
  163.   const char *format;
  164.   int i;
  165.  
  166.   format = *pfmt;
  167.   memset (map, 0, 256);
  168.   end = 0;
  169.   ++format;
  170.   if (*format == '^')
  171.     {
  172.       ++format; end = 1;
  173.     }
  174.   i = 0; done = 0;
  175.   do
  176.     {
  177.       f = (unsigned char)*format;
  178.       switch (f)
  179.         {
  180.         case 0:
  181.           *pfmt = format - 1;   /* Avoid skipping past 0 */
  182.           done = 1;
  183.           break;
  184.         case ']':
  185.           if (i > 0)
  186.             {
  187.               *pfmt = format;
  188.               done = 1;
  189.               break;
  190.             }
  191.           /* no break */
  192.         default:
  193.           if (format[1] == '-' && format[2] != 0 &&
  194.               f < (unsigned char)format[2])
  195.             {
  196.               memset (map+f, 1, (unsigned char)format[2]-f);
  197.               format += 2;
  198.             }
  199.           else
  200.             map[f] = 1;
  201.           break;
  202.         }
  203.       ++format; ++i;
  204.     } while (!done);
  205.   inp_string (v, next (v), map, end, dst);
  206. }
  207.  
  208.  
  209. static void inp_int_base (ilocal *v, void *dst, unsigned char c, int base)
  210. {
  211.   char neg, ok;
  212.   unsigned long long n;
  213.   int digit;
  214.  
  215.   neg = FALSE;
  216.   if (v->width > 0)
  217.     {
  218.       if (c == '+')
  219.         {
  220.           c = next (v); --v->width;
  221.         }
  222.       else if (c == '-')
  223.         {
  224.           neg = TRUE;
  225.           c = next (v); --v->width;
  226.         }
  227.     }
  228.  
  229.   n = 0; ok = FALSE;
  230.  
  231.   if (base == 0)
  232.     {
  233.       base = 10;
  234.       if (v->width > 0 && c == '0')
  235.         {
  236.           c = next (v); --v->width;
  237.           if (v->width > 0 && (c == 'x' || c == 'X'))
  238.             {
  239.               base = 16;
  240.               c = next (v); --v->width;
  241.             }
  242.           else
  243.             {
  244.               base = 8;
  245.               ok = TRUE; /* We've seen a digit! */
  246.             }
  247.         }
  248.     }
  249.  
  250.   while (v->width > 0)
  251.     {
  252.       --v->width;
  253.       if (isdigit (c))
  254.         digit = c - '0';
  255.       else if (isupper (c))
  256.         digit = c - 'A' + 10;
  257.       else if (islower (c))
  258.         digit = c - 'a' + 10;
  259.       else
  260.         break;
  261.       if (digit < 0 || digit >= base)
  262.         break;
  263.       ok = TRUE;
  264.       n = n * base + digit;
  265.       if (!get (v, &c))
  266.         break;
  267.     }
  268.   if (!ok)
  269.     longjmp (v->jump, JDONE);
  270.   if (neg)
  271.     n = -n;
  272.   if (dst != NULL)
  273.     {
  274.       switch (v->size)
  275.         {
  276.         case 'L':
  277.           *(long long *)dst = n;
  278.           break;
  279.         case 'h':
  280.           *(short *)dst = n;
  281.           break;
  282.         default:
  283.           *(int *)dst = n;
  284.           break;
  285.         }
  286.       ++v->count;
  287.     }
  288.   if (v->at_eof)
  289.     longjmp (v->jump, JDONE);
  290.   push_back (v, c);
  291. }
  292.  
  293.  
  294. static void inp_int (ilocal *v, unsigned char f, void *dst)
  295. {
  296.   unsigned char c;
  297.  
  298.   c = skip (v);
  299.   switch (f)
  300.     {
  301.     case 'i':
  302.       inp_int_base (v, dst, c, 0);
  303.       break;
  304.  
  305.     case 'd':
  306.       inp_int_base (v, dst, c, 10);
  307.       break;
  308.  
  309.     case 'u':
  310.       inp_int_base (v, dst, c, 10);
  311.       break;
  312.  
  313.     case 'o':
  314.       inp_int_base (v, dst, c, 8);
  315.       break;
  316.  
  317.     case 'x':
  318.     case 'X':
  319.     case 'p':
  320.       inp_int_base (v, dst, c, 16);
  321.       break;
  322.  
  323.     default:
  324.       abort ();
  325.     }
  326. }
  327.  
  328.  
  329. static void inp_float (ilocal *v, void *dst)
  330. {
  331.   unsigned char c;
  332.   char *q;
  333.   int width;
  334.   char ok;
  335.   char buf[128];
  336.   long double x;
  337.  
  338.   v->collected = 0;
  339.   width = v->width;
  340.   c = skip (v);
  341.   ok = FALSE;
  342.   if (c == '+' || c == '-')
  343.     {
  344.       COLLECT (c);
  345.       c = next (v); --width;
  346.     }
  347.   while (width > 0 && isdigit (c))
  348.     {
  349.       --width;
  350.       COLLECT (c);
  351.       ok = TRUE;
  352.       if (!get (v, &c))
  353.         break;
  354.     }
  355.   if (width > 0 && !v->at_eof && c == '.')
  356.     {
  357.       --width;
  358.       COLLECT (c);
  359.       while (get (v, &c) && width > 0 && isdigit (c))
  360.         {
  361.           --width;
  362.           COLLECT (c);
  363.           ok = TRUE;
  364.         }
  365.     }
  366.   if (!ok)
  367.     longjmp (v->jump, JDONE);
  368.  
  369.   if (width > 0 && !v->at_eof && (c == 'e' || c == 'E'))
  370.     {
  371.       COLLECT (c);
  372.       c = next (v); --width;
  373.       if (width > 0 && (c == '+' || c == '-'))
  374.         {
  375.           COLLECT (c);
  376.           c = next (v); --width;
  377.         }
  378.       if (!(width > 0 && isdigit (c)))
  379.         {
  380.           push_back (v, c);
  381.           longjmp (v->jump, JDONE);
  382.         }
  383.       while (width > 0 && isdigit (c))
  384.         {
  385.           --width;
  386.           COLLECT (c);
  387.           if (!get (v, &c))
  388.             break;
  389.         }
  390.     }
  391.   if (!v->at_eof)
  392.     push_back (v, c);
  393.   COLLECT (0);
  394.  
  395.   x = _strtold (((v->more != NULL) ? v->more : buf), &q);
  396.   if (q == buf || *q != 0) /* Ignore overflow! */
  397.     longjmp (v->jump, JDONE);
  398.   if (dst != NULL)
  399.     {
  400.       switch (v->size)
  401.         {
  402.         case 'L':
  403.           *(long double *)dst = x;
  404.           break;
  405.         case 'l':
  406.           *(double *)dst = x;
  407.           break;
  408.         default:
  409.           *(float *)dst = x;
  410.           break;
  411.         }
  412.       ++v->count;
  413.     }
  414.   if (v->at_eof)
  415.     longjmp (v->jump, JEOF);
  416. }
  417.  
  418.  
  419. static int inp_main (ilocal *v, const char *format, char *arg_ptr)
  420. {
  421.   void *dst;
  422.   unsigned char f, c;
  423.   char assign;
  424.  
  425.   c = 0;
  426.   while ((f = *format) != 0)
  427.     {
  428.       if (isspace (f))
  429.         {
  430.           do
  431.             {
  432.               ++format; f = *format;
  433.             } while (isspace (f));
  434.           do
  435.             {
  436.               if (!get (v, &c))
  437.                 {
  438.                   if (f == 0 || v->count != 0)
  439.                     return (v->count);
  440.                   else
  441.                     return (EOF);
  442.                 }
  443.             } while (isspace (c));
  444.           push_back (v, c);
  445.         }
  446.       else if (f != '%')
  447.         {
  448.           c = next (v);
  449.           if (c != f)
  450.             {
  451.               push_back (v, c);
  452.               return (v->count);
  453.             }
  454.           ++format;
  455.         }
  456.       else
  457.         {
  458.           v->size = 0; v->width = INT_MAX; assign = TRUE; dst = NULL;
  459.           ++format;
  460.           if (*format == '*')
  461.             {
  462.               assign = FALSE;
  463.               ++format;
  464.             }
  465.           if (isdigit (*format))
  466.             {
  467.               v->width = 0;
  468.               while (isdigit (*format))
  469.                 v->width = v->width * 10 + (*format++ - '0');
  470.               if (v->width == 0)
  471.                 v->width = INT_MAX;
  472.             }
  473.           if (*format == 'h' || *format == 'l' || *format == 'L')
  474.             v->size = *format++;
  475.           f = *format;
  476.           switch (f)
  477.             {
  478.             case 'c':
  479.               if (assign)
  480.                 dst = va_arg (arg_ptr, char *);
  481.               inp_char (v, dst);
  482.               break;
  483.  
  484.             case '[':
  485.               if (assign)
  486.                 dst = va_arg (arg_ptr, char *);
  487.               inp_set (v, &format, dst);
  488.               break;
  489.  
  490.             case 's':
  491.               if (assign)
  492.                 dst = va_arg (arg_ptr, char *);
  493.               inp_str (v, dst);
  494.               break;
  495.  
  496.             case 'f':
  497.             case 'e':
  498.             case 'E':
  499.             case 'g':
  500.             case 'G':
  501.               if (assign)
  502.                 switch (v->size)
  503.                   {
  504.                   case 'L':
  505.                     dst = va_arg (arg_ptr, long double *);
  506.                     break;
  507.                   case 'l':
  508.                       dst = va_arg (arg_ptr, double *);
  509.                     break;
  510.                   default:
  511.                     dst = va_arg (arg_ptr, float *);
  512.                     break;
  513.                   }
  514.               inp_float (v, dst);
  515.               break;
  516.  
  517.             case 'i':
  518.             case 'd':
  519.             case 'u':
  520.             case 'o':
  521.             case 'x':
  522.             case 'X':
  523.             case 'p':
  524.               if (assign)
  525.                 switch (v->size)
  526.                   {
  527.                   case 'L':
  528.                     dst = va_arg (arg_ptr, long long *);
  529.                     break;
  530.                   case 'h':
  531.                     dst = va_arg (arg_ptr, short *);
  532.                     break;
  533.                   default:
  534.                     dst = va_arg (arg_ptr, int *);
  535.                     break;
  536.                   }
  537.               inp_int (v, f, dst);
  538.               break;
  539.  
  540.             case 'n':
  541.               if (assign)
  542.                 switch (v->size)
  543.                   {
  544.                   case 'L':
  545.                     *(va_arg (arg_ptr, long long *)) = v->chars;
  546.                     break;
  547.                   case 'h':
  548.                     *(va_arg (arg_ptr, short *)) = v->chars;
  549.                     break;
  550.                   default:
  551.                     *(va_arg (arg_ptr, int *)) = v->chars;
  552.                     break;
  553.                   }
  554.               break;
  555.  
  556.             default:
  557.               if (f == 0)                 /* % at end of string */
  558.                 return (v->count);
  559.               c = next (v);
  560.               if (c != f)
  561.                 return (v->count);
  562.               break;
  563.             }
  564.           ++format;
  565.         }
  566.     }
  567.   return (v->count);
  568. }
  569.  
  570.  
  571. int _input (FILE *stream, const char *format, char *arg_ptr)
  572. {
  573.   ilocal v;
  574.   int rc;
  575.  
  576.   v.stream = stream;
  577.   v.more = NULL; v.more_size = 0;
  578.   v.count = 0; v.chars = 0; v.at_eof = 0;
  579.   switch (setjmp (v.jump))
  580.     {
  581.     case JEOF:
  582.       /* End of file (or string) reached.  If no fields were assigned,
  583.          return EOF.  Otherwise return the number of fields
  584.          assigned. */
  585.  
  586.       rc = ((v.count == 0) ? EOF : v.count);
  587.       break;
  588.  
  589.     case JDONE:
  590.       /* Stop conversion due to non-matching character.  Return the
  591.          number of fields assigned. */
  592.  
  593.       rc = v.count;
  594.       break;
  595.  
  596.     default:
  597.       /* This is the main line. */
  598.  
  599.       rc = inp_main (&v, format, arg_ptr);
  600.       break;
  601.     }
  602.  
  603.   if (v.more != NULL)
  604.     free (v.more);
  605.   return (rc);
  606. }
  607.