scanf/vsscanf.c

Go to the documentation of this file.
00001 // Copyright (C) 2006-2007 Benedikt Böhm <hollow@gentoo.org>
00002 //
00003 // This program is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU General Public License
00005 // as published by the Free Software Foundation; either version 2
00006 // of the License, or (at your option) any later version.
00007 //
00008 // This program is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 // GNU General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this program; if not, write to the Free Software
00015 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00016 
00017 #include "char.h"
00018 #include "scanf.h"
00019 #include "str.h"
00020 
00021 enum __scanf_flags {
00022         SFL_NOOP  = 0x01,
00023         SFL_WIDTH = 0x02,
00024 };
00025 
00026 enum __scanf_rank {
00027         SFR_CHAR,
00028         SFR_SHORT,
00029         SFR_INT,
00030         SFR_LONG,
00031         SFR_LLONG,
00032 };
00033 
00034 #define SFR_MIN SFR_CHAR
00035 #define SFR_MAX SFR_LLONG
00036 
00037 enum __scanf_state {
00038         SFS_NORMAL,
00039         SFS_FLAGS,
00040         SFS_WIDTH,
00041         SFS_MOD,
00042         SFS_CONV,
00043         SFS_STORE,
00044         SFS_EOF,
00045         SFS_ERR,
00046 };
00047 
00048 typedef struct {
00049         int f; /* flags */
00050         int l; /* length */
00051         int s; /* state */
00052         int w; /* width */
00053 } __scanf_t;
00054 
00055 /* supported formats:
00056 ** - field width
00057 ** - length mods: hh, h, l, and ll
00058 ** - conversion spec: d, i, u, o, x, X, c, s, p, P, n */
00059 int _lucid_vsscanf(const char *str, const char *fmt, va_list _ap)
00060 {
00061         /* keep track of converted arguments */
00062         int converted = 0;
00063 
00064         /* current character in format */
00065         char c;
00066 
00067         /* current conversion data */
00068         __scanf_t f;
00069 
00070         /* arguments */
00071         union {
00072                 /* unsigned argument */
00073                 unsigned long long int u;
00074 
00075                 /* string argument */
00076                 char *s;
00077         } arg;
00078 
00079         /* base used for integer conversions */
00080         int base;
00081 
00082         /* number of bytes converted in str_toumax */
00083         int len;
00084 
00085         /* pointer for string conversion */
00086         char *sp;
00087 
00088         /* don't consume original ap */
00089         va_list ap;
00090         va_copy(ap, _ap);
00091 
00092         /* initialize conversion data */
00093         f.f = 0;
00094         f.l = SFR_INT;
00095         f.s = SFS_NORMAL;
00096         f.w = str_len(str);
00097 
00098         while ((c = *fmt++)) {
00099                 switch (f.s) {
00100                 case SFS_NORMAL:
00101                         if (c == '%') {
00102                                 f.f = 0;
00103                                 f.l = SFR_INT;
00104                                 f.s = SFS_FLAGS;
00105                                 f.w = str_len(str);
00106                         }
00107 
00108                         else if (char_isspace(c))
00109                                 while (char_isspace(*str))
00110                                         str++;
00111 
00112                         else if (*str == c)
00113                                 str++;
00114 
00115                         else
00116                                 f.s = SFS_ERR;
00117 
00118                         break;
00119 
00120                 case SFS_FLAGS:
00121                         switch (c) {
00122                         case '*':
00123                                 f.f |= SFL_NOOP;
00124                                 break;
00125 
00126                         case '0':
00127                         case '1':
00128                         case '2':
00129                         case '3':
00130                         case '4':
00131                         case '5':
00132                         case '6':
00133                         case '7':
00134                         case '8':
00135                         case '9':
00136                                 f.w  = (c - '0');
00137                                 f.f |= SFL_WIDTH;
00138                                 f.s  = SFS_WIDTH;
00139                                 break;
00140 
00141                         default:
00142                                 f.s = SFS_MOD;
00143                                 fmt--;
00144                                 break;
00145                         }
00146 
00147                         break;
00148 
00149                 case SFS_WIDTH:
00150                         if (c >= '0' && c <= '9')
00151                                 f.w = f.w * 10  + (c - '0');
00152 
00153                         else {
00154                                 f.s = SFS_MOD;
00155                                 fmt--;
00156                         }
00157 
00158                         break;
00159 
00160                 case SFS_MOD:
00161                         switch (c) {
00162                         case 'h':
00163                                 f.l--;
00164                                 break;
00165 
00166                         case 'l':
00167                                 f.l++;
00168                                 break;
00169 
00170                         default:
00171                                 f.s = SFS_CONV;
00172                                 fmt--;
00173                                 break;
00174                         }
00175 
00176                         break;
00177 
00178                 case SFS_CONV:
00179                         f.s = SFS_NORMAL;
00180 
00181                         if (f.l > SFR_MAX)
00182                                 f.l = SFR_MAX;
00183 
00184                         if (f.l < SFR_MIN)
00185                                 f.l = SFR_MIN;
00186 
00187                         switch (c) {
00188                         case 'd':
00189                                 base = 10;
00190                                 goto scan_int;
00191 
00192                         case 'i': /* signed conversion */
00193                                 base = 0;
00194                                 goto scan_int;
00195 
00196                         case 'o':
00197                                 base = 8;
00198                                 goto scan_int;
00199 
00200                         case 'u':
00201                                 base = 10;
00202                                 goto scan_int;
00203 
00204                         case 'X':
00205                         case 'x':
00206                                 base = 16;
00207                                 goto scan_int;
00208 
00209                         scan_int:
00210                                 while (char_isspace(*str))
00211                                         str++;
00212 
00213                                 if (!*str) {
00214                                         f.s = SFS_EOF;
00215                                         break;
00216                                 }
00217 
00218                                 len = str_toumax(str, &arg.u, base, f.w);
00219 
00220                                 if (len <= 0) {
00221                                         f.s = SFS_ERR;
00222                                         break;
00223                                 }
00224 
00225                                 str += len;
00226                                 converted++;
00227 
00228                                 if (!(f.f & SFL_NOOP)) {
00229                                         switch (f.l) {
00230                                         case SFR_CHAR:
00231                                                 *va_arg(ap, unsigned char *) = arg.u;
00232                                                 break;
00233 
00234                                         case SFR_SHORT:
00235                                                 *va_arg(ap, unsigned short int *) = arg.u;
00236                                                 break;
00237 
00238                                         case SFR_INT:
00239                                                 *va_arg(ap, unsigned int *) = arg.u;
00240                                                 break;
00241 
00242                                         case SFR_LONG:
00243                                                 *va_arg(ap, unsigned long int *) = arg.u;
00244                                                 break;
00245 
00246                                         case SFR_LLONG:
00247                                                 *va_arg(ap, unsigned long long int *) = arg.u;
00248                                                 break;
00249 
00250                                         default:
00251                                                 *va_arg(ap, unsigned long long int *) = arg.u;
00252                                                 break;
00253                                         }
00254                                 }
00255 
00256                                 break;
00257 
00258                         case 'c': /* character conversion */
00259                                 /* default width = 1 */
00260                                 f.w = (f.f & SFL_WIDTH) ? f.w : 1;
00261 
00262                                 if ((f.f & SFL_NOOP)) {
00263                                         while (f.w--) {
00264                                                 if (!*str) {
00265                                                         f.s = SFS_EOF;
00266                                                         break;
00267                                                 }
00268 
00269                                                 str++;
00270                                         }
00271                                 }
00272 
00273                                 else {
00274                                         arg.s = va_arg(ap, char *);
00275 
00276                                         while (f.w--) {
00277                                                 if (!*str) {
00278                                                         f.s = SFS_EOF;
00279                                                         break;
00280                                                 }
00281 
00282                                                 *arg.s++ = *str++;
00283                                         }
00284                                 }
00285 
00286                                 if (f.s != SFS_EOF && !(f.f & SFL_NOOP))
00287                                         converted++;
00288 
00289                                 break;
00290 
00291                         case 's': /* string conversion */
00292                                 if (!(f.f & SFL_NOOP)) {
00293                                         while (f.w-- && !char_isspace(*str)) {
00294                                                 if (!*str) {
00295                                                         f.s = SFS_EOF;
00296                                                         break;
00297                                                 }
00298 
00299                                                 str++;
00300                                         }
00301                                 }
00302 
00303                                 else {
00304                                         sp = arg.s = va_arg(ap, char *);
00305 
00306                                         while (f.w-- && !char_isspace(*str)) {
00307                                                 if (!*str) {
00308                                                         f.s = SFS_EOF;
00309                                                         break;
00310                                                 }
00311 
00312                                                 *sp++ = *str++;
00313                                         }
00314 
00315                                         if (f.s != SFS_EOF)
00316                                                 *sp = '\0';
00317                                 }
00318 
00319                                 if (f.s != SFS_EOF && !(f.f & SFL_NOOP))
00320                                         converted++;
00321 
00322                                 break;
00323 
00324                         case 'P':
00325                         case 'p': /* pointer conversion */
00326                                 while (char_isspace(*str))
00327                                         str++;
00328 
00329                                 if (!*str) {
00330                                         f.s = SFS_EOF;
00331                                         break;
00332                                 }
00333 
00334                                 len = str_toumax(str, &arg.u, 0, f.w);
00335 
00336                                 if (len <= 0) {
00337                                         f.s = SFS_ERR;
00338                                         break;
00339                                 }
00340 
00341                                 if (!(f.f & SFL_NOOP))
00342                                         *va_arg(ap, void **) = (void *) (unsigned long int) arg.u;
00343 
00344                                 str += len;
00345                                 converted++;
00346 
00347                                 break;
00348 
00349                         case 'n':
00350                                 *va_arg(ap, int *) = converted;
00351 
00352                                 break;
00353 
00354                         case '%':
00355                                 if (*str == '%')
00356                                         str++;
00357                                 else
00358                                         f.s = SFS_ERR;
00359 
00360                                 break;
00361 
00362                         default:
00363                                 f.s = SFS_ERR;
00364                                 break;
00365                         }
00366 
00367                         break;
00368 
00369                 case SFS_EOF:
00370                         converted = converted ? converted : -1;
00371 
00372                 case SFS_ERR:
00373                         va_end(ap);
00374                         return converted;
00375                 }
00376         }
00377 
00378         if (f.s == SFS_EOF)
00379                 converted = converted ? converted : -1;
00380 
00381         va_end(ap);
00382         return converted;
00383 }

Generated on Tue Jun 19 20:38:26 2007 for lucid by  doxygen 1.5.2