vfscanf.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       vfscanf.c (4229B)
       ---
            1 #include <stdio.h>
            2 #include <stdarg.h>
            3 #include <inttypes.h>
            4 #include <stdlib.h>
            5 
            6 #include "ioprivate.h"
            7 
            8 typedef unsigned char                uchar;
            9 
           10 static void skipspace(FILE *fin)
           11 {
           12         int c;
           13         
           14         while ((c = fgetc(fin)) != EOF) {
           15                 if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
           16                         continue;
           17                 ungetc(c, fin);
           18                 break;
           19         }
           20 }
           21 
           22 // Main function to format and print a string.
           23 int vfscanf(FILE *fin, const char *fmt, va_list ap)
           24 {
           25         char *p;
           26         int ch, c;
           27         int nout = 0;
           28         int off0;
           29         int sign;
           30 
           31         off0 = ftell(fin);
           32         unsigned long long ull;
           33 
           34         for (;;) {
           35                 while ((ch = *(uchar *) fmt++) != '%') {
           36                         if (ch == '\0')
           37                                 return nout;
           38                         if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') {
           39                                 skipspace(fin);
           40                                 continue;
           41                         }
           42                         if ((c = fgetc(fin)) != ch) {
           43                                 ungetc(c, fin);
           44                                 break;
           45                         }
           46                 }
           47 
           48                 // Process a %-escape sequence
           49                 int flag[256];
           50                 int width = 0;
           51 
           52         reswitch:
           53                 switch (ch = *(uchar *) fmt++) {
           54                 case '*':
           55                 case 'h':
           56                 case 'l':
           57                 case 'L':
           58                 case 'j':
           59                 case 't':
           60                 case 'z':
           61                 case 'q':
           62                         flag[ch]++;
           63                         goto reswitch;
           64 
           65                 // width field
           66                 case '1':
           67                 case '2':
           68                 case '3':
           69                 case '4':
           70                 case '5':
           71                 case '6':
           72                 case '7':
           73                 case '8':
           74                 case '9':
           75                 case '0':
           76                         for (width = 0;; ++fmt) {
           77                                 width = width * 10 + ch - '0';
           78                                 ch = *fmt;
           79                                 if (ch < '0' || ch > '9')
           80                                         break;
           81                         }
           82                         goto reswitch;
           83 
           84                 // character
           85                 case '%':
           86                         skipspace(fin);
           87                         if ((c = fgetc(fin)) != '%') {
           88                                 ungetc(c, fin);
           89                                 return nout;
           90                         }
           91                         break;
           92                 
           93                 case 'n':
           94                         *va_arg(ap, int*) = ftell(fin) - off0;
           95                         nout++;
           96                         break;
           97                         
           98                 case 'd':
           99                 case 'u':
          100                         // optionally signed decimal
          101                         sign = 1;
          102                         c = fgetc(fin);
          103                         if (c == '-'){
          104                                 sign = -1;
          105                                 c = fgetc(fin);
          106                         }else if (c == '+'){
          107                                 sign = 1;
          108                                 c = fgetc(fin);
          109                         }
          110                         if (c < '0' || '9' < c) {
          111                                 ungetc(c, fin);
          112                                 return nout;
          113                         }
          114                 decimal:
          115                         ull = 0;
          116                         while ('0' <= c && c <= '9') {
          117                                 ull = 10 * ull + c - '0';
          118                                 c = fgetc(fin);
          119                         }
          120                         ungetc(c, fin);
          121                 assign:
          122                         if(sign < 0)
          123                                 ull = -ull;
          124                         if(flag['h'] == 2)
          125                                 *va_arg(ap, char*) = ull;
          126                         else if(flag['h'] == 1)
          127                                 *va_arg(ap, short*) = ull;
          128                         else if(flag['l'] == 1)
          129                                 *va_arg(ap, long*) = ull;
          130                         else if(flag['l'] == 2)
          131                                 *va_arg(ap, long long*) = ull;
          132                         else
          133                                 *va_arg(ap, int*) = ull;
          134                         nout++;
          135                         break;
          136                 
          137                 case 'i':
          138                         // optionally signed integer
          139                         c = fgetc(fin);
          140                         sign = 1;
          141                         if (c == '-'){
          142                                 sign = -1;
          143                                 c = fgetc(fin);
          144                         }else if (c == '+'){
          145                                 sign = 1;
          146                                 c = fgetc(fin);
          147                         }
          148                         if (c < '0' || '9' < c) {
          149                                 ungetc(c, fin);
          150                                 return nout;
          151                         }
          152                         if (c == '0') {
          153                                 c = fgetc(fin);
          154                                 if (c == 'x') {
          155                                         c = fgetc(fin);
          156                                         if (('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))
          157                                                 goto hex;
          158                                         return nout;
          159                                 }
          160                                 if ('0' <= c && c <= '7')
          161                                         goto octal;
          162                         }
          163                         goto decimal;
          164                 
          165                 case 'o':
          166                         // octal
          167                         sign = 1;
          168                         c = fgetc(fin);
          169                         if (c < '0' || '7' < c) {
          170                                 ungetc(c, fin);
          171                                 return nout;
          172                         }
          173                 octal:
          174                         ull = 0;
          175                         while ('0' <= c && c <= '7') {
          176                                 ull = 8 * ull + c - '0';
          177                                 c = fgetc(fin);
          178                         }
          179                         ungetc(c, fin);
          180                         goto assign;
          181 
          182                 case 'x':
          183                 case 'X':
          184                         // optionally signed integer
          185                 case 'p':
          186                         // pointer value
          187                         sign = 1;
          188                         c = fgetc(fin);
          189                         if (c == '-'){
          190                                 sign = -1;
          191                                 c = fgetc(fin);
          192                         }else if (c == '+'){
          193                                 sign = 1;
          194                                 c = fgetc(fin);
          195                         }
          196                         if ((c < '0' || '9' < c) && (c < 'a' || 'z' < c) && (c < 'A' || 'Z' < c)) {
          197                                 ungetc(c, fin);
          198                                 return nout;
          199                         }
          200                 hex:
          201                         ull = 0;
          202                         for (;; c = fgetc(fin)) {
          203                                 if ('0' <= c && c <= '9')
          204                                         ull = 16 * ull + c - '0';
          205                                 else if ('a' <= c && c <= 'f')
          206                                         ull = 16 * ull + c - 'a' + 10;
          207                                 else if ('A' <= c && c <= 'F')
          208                                         ull = 16 * ull + c - 'A' + 10;
          209                                 else
          210                                         break;
          211                         }
          212                         ungetc(c, fin);
          213                         goto assign;
          214                         
          215                 case 'a':
          216                 case 'A':
          217                 case 'e':
          218                 case 'E':
          219                 case 'f':
          220                 case 'F':
          221                 case 'g':
          222                 case 'G':
          223                         // float in style of strtod
          224 
          225                 case 's':
          226                         // string
          227 
          228                 case 'S':
          229                         // long string
          230                 
          231                 case 'c':
          232                         // fixed # chars
          233                 
          234                 case 'C':
          235                         // same as lc
          236                 
          237                 case '[':
          238                         // nonempty sequence of chars from specified char set
          239                         
          240                         printf("sscanf only partially implemented\n");
          241                         abort();
          242                 
          243                 default:
          244                         printf("unrecognized verb %c (%d)\n", ch, ch);
          245                         abort();
          246                 }
          247         }
          248 }
          249