Back to index

tetex-bin  3.0
Defines | Enumerations | Functions
vsscanf.c File Reference
#include <curses.priv.h>
#include <ctype.h>

Go to the source code of this file.

Defines

#define L_SQUARE   '['
#define R_SQUARE   ']'

Enumerations

enum  ChunkType {
  cUnknown, cError, cAssigned, cChar,
  cInt, cFloat, cDouble, cPointer,
  cLong, cShort, cRange, cString
}
enum  OtherType { oUnknown, oShort, oLong }
enum  ScanState {
  sUnknown, sPercent, sNormal, sLeft,
  sRange, sFinal
}

Functions

static ChunkType final_ch (int ch, OtherType other)
static OtherType other_ch (int ch)
 vsscanf (const char *str, const char *format, va_list ap)

Define Documentation

#define L_SQUARE   '['

Definition at line 47 of file vsscanf.c.

#define R_SQUARE   ']'

Definition at line 48 of file vsscanf.c.


Enumeration Type Documentation

enum ChunkType
Enumerator:
cUnknown 
cError 
cAssigned 
cChar 
cInt 
cFloat 
cDouble 
cPointer 
cLong 
cShort 
cRange 
cString 

Definition at line 50 of file vsscanf.c.

             {
    cUnknown
    ,cError                 /* anything that isn't ANSI */
    ,cAssigned
    ,cChar
    ,cInt
    ,cFloat
    ,cDouble
    ,cPointer
    ,cLong
    ,cShort
    ,cRange
    ,cString
} ChunkType;
enum OtherType
Enumerator:
oUnknown 
oShort 
oLong 

Definition at line 65 of file vsscanf.c.

enum ScanState
Enumerator:
sUnknown 
sPercent 
sNormal 
sLeft 
sRange 
sFinal 

Definition at line 71 of file vsscanf.c.

             {
    sUnknown
    ,sPercent               /* last was '%' beginning a format */
    ,sNormal                /* ...somewhere in the middle */
    ,sLeft                  /* last was left square bracket beginning a range */
    ,sRange                 /* ...somewhere in the middle */
    ,sFinal                 /* last finished a format */
} ScanState;

Function Documentation

static ChunkType final_ch ( int  ch,
OtherType  other 
) [static]

Definition at line 81 of file vsscanf.c.

{
    ChunkType result = cUnknown;

    switch (ch) {
    case 'c':
       if (other == oUnknown)
           result = cChar;
       else
           result = cError;
       break;
    case 'd':
    case 'i':
    case 'X':
    case 'x':
       switch (other) {
       case oUnknown:
           result = cInt;
           break;
       case oShort:
           result = cShort;
           break;
       case oLong:
           result = cLong;
           break;
       }
       break;
    case 'E':
    case 'e':
    case 'f':
    case 'g':
       switch (other) {
       case oUnknown:
           result = cFloat;
           break;
       case oShort:
           result = cError;
           break;
       case oLong:
           result = cDouble;
           break;
       }
       break;
    case 'n':
       if (other == oUnknown)
           result = cAssigned;
       else
           result = cError;
       break;
    case 'p':
       if (other == oUnknown)
           result = cPointer;
       else
           result = cError;
       break;
    case 's':
       if (other == oUnknown)
           result = cString;
       else
           result = cError;
       break;
    }
    return result;
}

Here is the caller graph for this function:

static OtherType other_ch ( int  ch) [static]

Definition at line 147 of file vsscanf.c.

{
    OtherType result = oUnknown;
    switch (ch) {
    case 'h':
       result = oShort;
       break;
    case 'l':
       result = oLong;
       break;
    }
    return result;
}

Here is the caller graph for this function:

vsscanf ( const char *  str,
const char *  format,
va_list  ap 
)

Definition at line 164 of file vsscanf.c.

{
#if HAVE_VFSCANF || HAVE__DOSCAN
    /*
     * This code should work on anything descended from AT&T SVr1.
     */
    FILE strbuf;

    strbuf._flag = _IOREAD;
    strbuf._ptr = strbuf._base = (unsigned char *) str;
    strbuf._cnt = strlen(str);
    strbuf._file = _NFILE;

#if HAVE_VFSCANF
    return (vfscanf(&strbuf, format, ap));
#else
    return (_doscan(&strbuf, format, ap));
#endif
#else
    static int can_convert = -1;

    int assigned = 0;
    int consumed = 0;

    T((T_CALLED("vsscanf(%s,%s,...)"),
       _nc_visbuf2(1, str),
       _nc_visbuf2(2, format)));

    /*
     * This relies on having a working "%n" format conversion.  Check if it
     * works.  Only very old C libraries do not support it.
     *
     * FIXME: move this check into the configure script.
     */
    if (can_convert < 0) {
       int check1;
       int check2;
       if (sscanf("123", "%d%n", &check1, &check2) > 0
           && check1 == 123
           && check2 == 3) {
           can_convert = 1;
       } else {
           can_convert = 0;
       }
    }

    if (can_convert) {
       size_t len_fmt = strlen(format) + 32;
       char *my_fmt = malloc(len_fmt);
       ChunkType chunk, ctest;
       OtherType other, otest;
       ScanState state;
       unsigned n;
       int eaten;
       void *pointer;

       if (my_fmt != 0) {
           /*
            * Split the original format into chunks, adding a "%n" to the end
            * of each (except of course if it used %n), and use that
            * information to decide where to start scanning the next chunk.
            *
            * FIXME:  does %n count bytes or characters?  If the latter, this
            * will require further work for multibyte strings.
            */
           while (*format != '\0') {
              /* find a chunk */
              state = sUnknown;
              chunk = cUnknown;
              other = oUnknown;
              pointer = 0;
              for (n = 0; format[n] != 0 && state != sFinal; ++n) {
                  my_fmt[n] = format[n];
                  switch (state) {
                  case sUnknown:
                     if (format[n] == '%')
                         state = sPercent;
                     break;
                  case sPercent:
                     if (format[n] == '%') {
                         state = sUnknown;
                     } else if (format[n] == L_SQUARE) {
                         state = sLeft;
                     } else {
                         state = sNormal;
                         --n;
                     }
                     break;
                  case sLeft:
                     state = sRange;
                     if (format[n] == '^') {
                         ++n;
                         my_fmt[n] = format[n];
                     }
                     break;
                  case sRange:
                     if (format[n] == R_SQUARE) {
                         state = sFinal;
                         chunk = cRange;
                     }
                     break;
                  case sNormal:
                     if (format[n] == '*') {
                         state = sUnknown;
                     } else {
                         if ((ctest = final_ch(format[n], other)) != cUnknown) {
                            state = sFinal;
                            chunk = ctest;
                         } else if ((otest = other_ch(format[n])) != oUnknown) {
                            other = otest;
                         } else if (isalpha(UChar(format[n]))) {
                            state = sFinal;
                            chunk = cError;
                         }
                     }
                     break;
                  case sFinal:
                     break;
                  }
              }
              my_fmt[n] = '\0';
              format += n;

              if (chunk == cUnknown
                  || chunk == cError) {
                  if (assigned == 0)
                     assigned = EOF;
                  break;
              }

              /* add %n, if the format was not that */
              if (chunk != cAssigned) {
                  strcat(my_fmt, "%n");
              }

              switch (chunk) {
              case cAssigned:
                  strcat(my_fmt, "%n");
                  pointer = &eaten;
                  break;
              case cInt:
                  pointer = va_arg(ap, int *);
                  break;
              case cShort:
                  pointer = va_arg(ap, short *);
                  break;
              case cFloat:
                  pointer = va_arg(ap, float *);
                  break;
              case cDouble:
                  pointer = va_arg(ap, double *);
                  break;
              case cLong:
                  pointer = va_arg(ap, long *);
                  break;
              case cPointer:
                  pointer = va_arg(ap, void *);
                  break;
              case cChar:
              case cRange:
              case cString:
                  pointer = va_arg(ap, char *);
                  break;
              case cError:
              case cUnknown:
                  break;
              }
              /* do the conversion */
              T(("...converting chunk #%d type %d(%s,%s)",
                 assigned + 1, chunk,
                 _nc_visbuf2(1, str + consumed),
                 _nc_visbuf2(2, my_fmt)));
              if (sscanf(str + consumed, my_fmt, pointer, &eaten) > 0)
                  consumed += eaten;
              else
                  break;
              ++assigned;
           }
           free(my_fmt);
       }
    }
    returnCode(assigned);
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function: