Back to index

tetex-bin  3.0
vsscanf.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  State-machine fallback written by Thomas E. Dickey 2002                 *
00031  ****************************************************************************/
00032 
00033 /*
00034  * This function is needed to support vwscanw
00035  */
00036 
00037 #include <curses.priv.h>
00038 
00039 #if !HAVE_VSSCANF
00040 
00041 MODULE_ID("$Id: vsscanf.c,v 1.18 2004/04/03 20:27:02 tom Exp $")
00042 
00043 #if !(HAVE_VFSCANF || HAVE__DOSCAN)
00044 
00045 #include <ctype.h>
00046 
00047 #define L_SQUARE '['
00048 #define R_SQUARE ']'
00049 
00050 typedef enum {
00051     cUnknown
00052     ,cError                 /* anything that isn't ANSI */
00053     ,cAssigned
00054     ,cChar
00055     ,cInt
00056     ,cFloat
00057     ,cDouble
00058     ,cPointer
00059     ,cLong
00060     ,cShort
00061     ,cRange
00062     ,cString
00063 } ChunkType;
00064 
00065 typedef enum {
00066     oUnknown
00067     ,oShort
00068     ,oLong
00069 } OtherType;
00070 
00071 typedef enum {
00072     sUnknown
00073     ,sPercent               /* last was '%' beginning a format */
00074     ,sNormal                /* ...somewhere in the middle */
00075     ,sLeft                  /* last was left square bracket beginning a range */
00076     ,sRange                 /* ...somewhere in the middle */
00077     ,sFinal                 /* last finished a format */
00078 } ScanState;
00079 
00080 static ChunkType
00081 final_ch(int ch, OtherType other)
00082 {
00083     ChunkType result = cUnknown;
00084 
00085     switch (ch) {
00086     case 'c':
00087        if (other == oUnknown)
00088            result = cChar;
00089        else
00090            result = cError;
00091        break;
00092     case 'd':
00093     case 'i':
00094     case 'X':
00095     case 'x':
00096        switch (other) {
00097        case oUnknown:
00098            result = cInt;
00099            break;
00100        case oShort:
00101            result = cShort;
00102            break;
00103        case oLong:
00104            result = cLong;
00105            break;
00106        }
00107        break;
00108     case 'E':
00109     case 'e':
00110     case 'f':
00111     case 'g':
00112        switch (other) {
00113        case oUnknown:
00114            result = cFloat;
00115            break;
00116        case oShort:
00117            result = cError;
00118            break;
00119        case oLong:
00120            result = cDouble;
00121            break;
00122        }
00123        break;
00124     case 'n':
00125        if (other == oUnknown)
00126            result = cAssigned;
00127        else
00128            result = cError;
00129        break;
00130     case 'p':
00131        if (other == oUnknown)
00132            result = cPointer;
00133        else
00134            result = cError;
00135        break;
00136     case 's':
00137        if (other == oUnknown)
00138            result = cString;
00139        else
00140            result = cError;
00141        break;
00142     }
00143     return result;
00144 }
00145 
00146 static OtherType
00147 other_ch(int ch)
00148 {
00149     OtherType result = oUnknown;
00150     switch (ch) {
00151     case 'h':
00152        result = oShort;
00153        break;
00154     case 'l':
00155        result = oLong;
00156        break;
00157     }
00158     return result;
00159 }
00160 #endif
00161 
00162 /*VARARGS2*/
00163 NCURSES_EXPORT(int)
00164 vsscanf(const char *str, const char *format, va_list ap)
00165 {
00166 #if HAVE_VFSCANF || HAVE__DOSCAN
00167     /*
00168      * This code should work on anything descended from AT&T SVr1.
00169      */
00170     FILE strbuf;
00171 
00172     strbuf._flag = _IOREAD;
00173     strbuf._ptr = strbuf._base = (unsigned char *) str;
00174     strbuf._cnt = strlen(str);
00175     strbuf._file = _NFILE;
00176 
00177 #if HAVE_VFSCANF
00178     return (vfscanf(&strbuf, format, ap));
00179 #else
00180     return (_doscan(&strbuf, format, ap));
00181 #endif
00182 #else
00183     static int can_convert = -1;
00184 
00185     int assigned = 0;
00186     int consumed = 0;
00187 
00188     T((T_CALLED("vsscanf(%s,%s,...)"),
00189        _nc_visbuf2(1, str),
00190        _nc_visbuf2(2, format)));
00191 
00192     /*
00193      * This relies on having a working "%n" format conversion.  Check if it
00194      * works.  Only very old C libraries do not support it.
00195      *
00196      * FIXME: move this check into the configure script.
00197      */
00198     if (can_convert < 0) {
00199        int check1;
00200        int check2;
00201        if (sscanf("123", "%d%n", &check1, &check2) > 0
00202            && check1 == 123
00203            && check2 == 3) {
00204            can_convert = 1;
00205        } else {
00206            can_convert = 0;
00207        }
00208     }
00209 
00210     if (can_convert) {
00211        size_t len_fmt = strlen(format) + 32;
00212        char *my_fmt = malloc(len_fmt);
00213        ChunkType chunk, ctest;
00214        OtherType other, otest;
00215        ScanState state;
00216        unsigned n;
00217        int eaten;
00218        void *pointer;
00219 
00220        if (my_fmt != 0) {
00221            /*
00222             * Split the original format into chunks, adding a "%n" to the end
00223             * of each (except of course if it used %n), and use that
00224             * information to decide where to start scanning the next chunk.
00225             *
00226             * FIXME:  does %n count bytes or characters?  If the latter, this
00227             * will require further work for multibyte strings.
00228             */
00229            while (*format != '\0') {
00230               /* find a chunk */
00231               state = sUnknown;
00232               chunk = cUnknown;
00233               other = oUnknown;
00234               pointer = 0;
00235               for (n = 0; format[n] != 0 && state != sFinal; ++n) {
00236                   my_fmt[n] = format[n];
00237                   switch (state) {
00238                   case sUnknown:
00239                      if (format[n] == '%')
00240                          state = sPercent;
00241                      break;
00242                   case sPercent:
00243                      if (format[n] == '%') {
00244                          state = sUnknown;
00245                      } else if (format[n] == L_SQUARE) {
00246                          state = sLeft;
00247                      } else {
00248                          state = sNormal;
00249                          --n;
00250                      }
00251                      break;
00252                   case sLeft:
00253                      state = sRange;
00254                      if (format[n] == '^') {
00255                          ++n;
00256                          my_fmt[n] = format[n];
00257                      }
00258                      break;
00259                   case sRange:
00260                      if (format[n] == R_SQUARE) {
00261                          state = sFinal;
00262                          chunk = cRange;
00263                      }
00264                      break;
00265                   case sNormal:
00266                      if (format[n] == '*') {
00267                          state = sUnknown;
00268                      } else {
00269                          if ((ctest = final_ch(format[n], other)) != cUnknown) {
00270                             state = sFinal;
00271                             chunk = ctest;
00272                          } else if ((otest = other_ch(format[n])) != oUnknown) {
00273                             other = otest;
00274                          } else if (isalpha(UChar(format[n]))) {
00275                             state = sFinal;
00276                             chunk = cError;
00277                          }
00278                      }
00279                      break;
00280                   case sFinal:
00281                      break;
00282                   }
00283               }
00284               my_fmt[n] = '\0';
00285               format += n;
00286 
00287               if (chunk == cUnknown
00288                   || chunk == cError) {
00289                   if (assigned == 0)
00290                      assigned = EOF;
00291                   break;
00292               }
00293 
00294               /* add %n, if the format was not that */
00295               if (chunk != cAssigned) {
00296                   strcat(my_fmt, "%n");
00297               }
00298 
00299               switch (chunk) {
00300               case cAssigned:
00301                   strcat(my_fmt, "%n");
00302                   pointer = &eaten;
00303                   break;
00304               case cInt:
00305                   pointer = va_arg(ap, int *);
00306                   break;
00307               case cShort:
00308                   pointer = va_arg(ap, short *);
00309                   break;
00310               case cFloat:
00311                   pointer = va_arg(ap, float *);
00312                   break;
00313               case cDouble:
00314                   pointer = va_arg(ap, double *);
00315                   break;
00316               case cLong:
00317                   pointer = va_arg(ap, long *);
00318                   break;
00319               case cPointer:
00320                   pointer = va_arg(ap, void *);
00321                   break;
00322               case cChar:
00323               case cRange:
00324               case cString:
00325                   pointer = va_arg(ap, char *);
00326                   break;
00327               case cError:
00328               case cUnknown:
00329                   break;
00330               }
00331               /* do the conversion */
00332               T(("...converting chunk #%d type %d(%s,%s)",
00333                  assigned + 1, chunk,
00334                  _nc_visbuf2(1, str + consumed),
00335                  _nc_visbuf2(2, my_fmt)));
00336               if (sscanf(str + consumed, my_fmt, pointer, &eaten) > 0)
00337                   consumed += eaten;
00338               else
00339                   break;
00340               ++assigned;
00341            }
00342            free(my_fmt);
00343        }
00344     }
00345     returnCode(assigned);
00346 #endif
00347 }
00348 #else
00349 extern
00350 NCURSES_EXPORT(void)
00351 _nc_vsscanf(void);          /* quiet's gcc warning */
00352 NCURSES_EXPORT(void)
00353 _nc_vsscanf(void)
00354 {
00355 }                           /* nonempty for strict ANSI compilers */
00356 #endif /* !HAVE_VSSCANF */