Beispiel #1
0
static inline void
SetBit(unsigned long *bitmap, unsigned int bit) {
  bitmap[bit/LongBit()] |= 1UL << (bit%LongBit());
}
Beispiel #2
0
static inline int
TestBit(unsigned long *bitmap, unsigned int bit) {
  return static_cast<int>(bitmap[bit/LongBit()] >> (bit%LongBit())) & 1;
}
int vfscanf(FILE* stream, const char *format, va_list ap)
{
  const char *p = format;
  char ch;
  int q = 0;
  uintmax_t val = 0;
  int rank = RANK_INT;    // Default rank
  unsigned int width = UINT_MAX;
  int base;
  int flags = 0;
  enum {
    ST_NORMAL,        // Ground state
    ST_FLAGS,         // Special flags
    ST_WIDTH,         // Field width
    ST_MODIFIERS,     // Length or conversion modifiers
    ST_MATCH_INIT,    // Initial state of %[ sequence
    ST_MATCH,         // Main state of %[ sequence
    ST_MATCH_RANGE,   // After - in a %[ sequence
  } state = ST_NORMAL;
  char *oarg, *sarg = NULL;    // %s %c or %[ string argument
  enum Bail bail = BAIL_NONE;
  int sign;
  int converted = 0;    // Successful conversions
  unsigned long matchmap[((1 << CHAR_BIT)+(LongBit()-1))/LongBit()];
  int matchinv = 0;   // Is match map inverted?
  unsigned char range_start = 0;
  off_t start_off = ftell(stream);

  // Skip leading spaces
  SkipSpace(stream);
  
  while ((ch = *p++) && !bail) {
    switch (state) {
      case ST_NORMAL:
        if (ch == '%') {
          state = ST_FLAGS;
          flags = 0; rank = RANK_INT; width = UINT_MAX;
        } else if (isspace(static_cast<unsigned char>(ch))) {
          SkipSpace(stream);
        } else {
          if (fgetc(stream) != ch) 
            bail = BAIL_ERR;  // Match failure 
        }
        break;

      case ST_FLAGS:
        switch (ch) {
          case '*':
            flags |= FL_SPLAT;
          break;

          case '0' ... '9':
            width = (ch-'0');
            state = ST_WIDTH;
            flags |= FL_WIDTH;
          break;

          default:
            state = ST_MODIFIERS;
            p--;      // Process this character again
          break;
        }
      break;

      case ST_WIDTH:
        if (ch >= '0' && ch <= '9') {
          width = width*10+(ch-'0');
        } else {
          state = ST_MODIFIERS;
          p--;      // Process this character again
        }
      break;

      case ST_MODIFIERS:
        switch (ch) {
          // Length modifiers - nonterminal sequences
          case 'h':
            rank--;     // Shorter rank
          break;
          case 'l':
            rank++;     // Longer rank
          break;
          case 'j':
            rank = kIntMaxRank;
          break;
          case 'z':
            rank = kSizeTRank;
          break;
          case 't':
            rank = kPtrDiffRank;
          break;
          case 'L':
          case 'q':
            rank = RANK_LONGLONG; // long double/long long
          break;

          default:
            // Output modifiers - terminal sequences
            state = ST_NORMAL;  // Next state will be normal
            if (rank < kMinRank)  // Canonicalize rank
              rank = kMinRank;
            else if (rank > kMaxRank)
              rank = kMaxRank;

          switch (ch) {
            case 'P':   // Upper case pointer
            case 'p':   // Pointer
              rank = RANK_PTR;
              base = 0; sign = 0;
            goto scan_int;
        
            case 'i':   // Base-independent integer
              base = 0; sign = 1;
            goto scan_int;
        
            case 'd':   // Decimal integer
              base = 10; sign = 1;
            goto scan_int;
        
            case 'o':   // Octal integer
              base = 8; sign = 0;
            goto scan_int;
        
            case 'u':   // Unsigned decimal integer
              base = 10; sign = 0;
            goto scan_int;
            
            case 'x':   // Hexadecimal integer
            case 'X':
              base = 16; sign = 0;
            goto scan_int;
        
            case 'n':   // Number of characters consumed
              val = ftell(stream) - start_off;
            goto set_integer;
        
            scan_int:
              q = SkipSpace(stream);
              if ( q <= 0 ) {
                bail = BAIL_EOF;
                break;
              }
              val = streamtoumax(stream, base);
              converted++;
              // fall through

            set_integer:
              if (!(flags & FL_SPLAT)) {
                switch(rank) {
                  case RANK_CHAR:
                    *va_arg(ap, unsigned char *) 
                      = static_cast<unsigned char>(val);
                  break;
                  case RANK_SHORT:
                    *va_arg(ap, unsigned short *) 
                      = static_cast<unsigned short>(val);
                  break;
                  case RANK_INT:
                    *va_arg(ap, unsigned int *) 
                      = static_cast<unsigned int>(val);
                  break;
                  case RANK_LONG:
                    *va_arg(ap, unsigned long *) 
                      = static_cast<unsigned long>(val);
                  break;
                  case RANK_LONGLONG:
                    *va_arg(ap, unsigned long long *) 
                      = static_cast<unsigned long long>(val);
                  break;
                  case RANK_PTR:
                    *va_arg(ap, void **) 
                      = reinterpret_cast<void *>(static_cast<uintptr_t>(val));
                  break;
                }
              }
            break;

            case 'f':   // Preliminary float value parsing
            case 'g':
            case 'G':
            case 'e':
            case 'E':
              q = SkipSpace(stream);
              if (q <= 0) {
                bail = BAIL_EOF;
                break;
              }

              double fval = streamtofloat(stream);
              switch(rank) {
                case RANK_INT:
                  *va_arg(ap, float *) = static_cast<float>(fval);
                break;
                case RANK_LONG:
                  *va_arg(ap, double *) = static_cast<double>(fval);
                break;
              }
              converted++;
            break;

            case 'c':               // Character
              width = (flags & FL_WIDTH) ? width : 1; // Default width == 1
              sarg = va_arg(ap, char *);
              while (width--) {
                if ((q = fgetc(stream)) <= 0) {
                  bail = BAIL_EOF;
                  break;
                }
                *sarg++ = q;
              }
              if (!bail)
                converted++;
            break;
      
            case 's':               // String
            {
              char *sp;
              sp = sarg = va_arg(ap, char *);
              while (width--) {
                q = fgetc(stream);
                if (isspace(static_cast<unsigned char>(q)) || q <= 0) {
                  ungetc(q, stream);
                  break;
                }
                *sp++ = q;
              }
              if (sarg != sp) {
                *sp = '\0'; // Terminate output
                converted++;
              } else {
                bail = BAIL_EOF;
              }
            }
            break;
          
            case '[':   // Character range
              sarg = va_arg(ap, char *);
              state = ST_MATCH_INIT;
              matchinv = 0;
              memset(matchmap, 0, sizeof matchmap);
            break;
      
            case '%':   // %% sequence
              if (fgetc(stream) != '%' ) 
                bail = BAIL_ERR;
            break;
      
            default:    // Anything else
              bail = BAIL_ERR;  // Unknown sequence 
            break;
          }
        }
      break;

      case ST_MATCH_INIT:   // Initial state for %[ match
        if (ch == '^' && !(flags & FL_INV)) {
          matchinv = 1;
        } else {
          SetBit(matchmap, static_cast<unsigned char>(ch));
          state = ST_MATCH;
        }
      break;
  
      case ST_MATCH:    // Main state for %[ match
        if (ch == ']') {
          goto match_run;
        } else if (ch == '-') {
          range_start = static_cast<unsigned char>(ch);
          state = ST_MATCH_RANGE;
        } else {
          SetBit(matchmap, static_cast<unsigned char>(ch));
        }
      break;
  
      case ST_MATCH_RANGE:    // %[ match after -
        if (ch == ']') {
          SetBit(matchmap, static_cast<unsigned char>('-'));
          goto match_run;
        } else {
          int i;
          for (i = range_start ; i < (static_cast<unsigned char>(ch)) ; i++)
          SetBit(matchmap, i);
          state = ST_MATCH;
        }
      break;

      match_run:      // Match expression finished
        char* oarg = sarg;
        while (width) {
          q = fgetc(stream);
          unsigned char qc = static_cast<unsigned char>(q);
          if (q <= 0 || !(TestBit(matchmap, qc)^matchinv)) {
            ungetc(q, stream);
            break;
          }
          *sarg++ = q;
        }
        if (oarg != sarg) {
          *sarg = '\0';
          converted++;
        } else {
          bail = (q <= 0) ? BAIL_EOF : BAIL_ERR;
        }
      break;
    }
  }

  if (bail == BAIL_EOF && !converted)
    converted = -1;   // Return EOF (-1)

  return converted;
}