Annotation of embedaddon/trafshow/snprintf.c, revision 1.1.1.1

1.1       misho       1: #ifndef SNPRINTF_C
                      2: #define SNPRINTF_C
                      3: 
                      4: #include "config.h"
                      5: 
                      6: /* This source code are distributed under following license: */
                      7: /*
                      8:  * Copyright (c) 1995 - 2000 Kungliga Tekniska H?gskolan
                      9:  * (Royal Institute of Technology, Stockholm, Sweden).
                     10:  * All rights reserved.
                     11:  * 
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 
                     16:  * 1. Redistributions of source code must retain the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer.
                     18:  * 
                     19:  * 2. Redistributions in binary form must reproduce the above copyright
                     20:  *    notice, this list of conditions and the following disclaimer in the
                     21:  *    documentation and/or other materials provided with the distribution.
                     22:  * 
                     23:  * 3. Neither the name of the Institute nor the names of its contributors
                     24:  *    may be used to endorse or promote products derived from this software
                     25:  *    without specific prior written permission.
                     26:  * 
                     27:  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
                     28:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     29:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     30:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
                     31:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     32:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     33:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     34:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     35:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     36:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     37:  * SUCH DAMAGE.
                     38:  */
                     39:  
                     40: #include <ctype.h>
                     41: #include <sys/types.h>
                     42: #include <stdlib.h>
                     43: #include <string.h>
                     44: #include <stdio.h>
                     45: #include <stdarg.h>
                     46: #include "snprintf.h"
                     47: 
                     48: #define max(a,b)        ((a)>(b)?(a):(b))
                     49: #define min(a,b)        ((a)<(b)?(a):(b))
                     50: 
                     51: enum format_flags {
                     52:     minus_flag     =  1,
                     53:     plus_flag      =  2,
                     54:     space_flag     =  4,
                     55:     alternate_flag =  8,
                     56:     zero_flag      = 16
                     57: };
                     58: 
                     59: /*
                     60:  * Common state
                     61:  */
                     62: 
                     63: struct state {
                     64:   unsigned char *str;
                     65:   unsigned char *s;
                     66:   unsigned char *theend;
                     67:   size_t sz;
                     68:   size_t max_sz;
                     69:   int (*append_char)(struct state *, unsigned char);
                     70:   int (*reserve)(struct state *, size_t);
                     71:   /* XXX - methods */
                     72: };
                     73: 
                     74: static int
                     75: sn_reserve (struct state *state, size_t n)
                     76: {
                     77:   return state->s + n > state->theend;
                     78: }
                     79: 
                     80: static int
                     81: sn_append_char (struct state *state, unsigned char c)
                     82: {
                     83:   if (sn_reserve (state, 1)) {
                     84:     return 1;
                     85:   } else {
                     86:     *state->s++ = c;
                     87:     return 0;
                     88:   }
                     89: }
                     90: 
                     91: static int
                     92: as_reserve (struct state *state, size_t n)
                     93: {
                     94:   if (state->s + n > state->theend) {
                     95:     int off = state->s - state->str;
                     96:     unsigned char *tmp;
                     97: 
                     98:     if (state->max_sz && state->sz >= state->max_sz)
                     99:       return 1;
                    100: 
                    101:     state->sz = max(state->sz * 2, state->sz + n);
                    102:     if (state->max_sz)
                    103:       state->sz = min(state->sz, state->max_sz);
                    104:     tmp = realloc (state->str, state->sz);
                    105:     if (tmp == NULL)
                    106:       return 1;
                    107:     state->str = tmp;
                    108:     state->s = state->str + off;
                    109:     state->theend = state->str + state->sz - 1;
                    110:   }
                    111:   return 0;
                    112: }
                    113: 
                    114: static int
                    115: as_append_char (struct state *state, unsigned char c)
                    116: {
                    117:   if(as_reserve (state, 1))
                    118:     return 1;
                    119:   else {
                    120:     *state->s++ = c;
                    121:     return 0;
                    122:   }
                    123: }
                    124: 
                    125: static int
                    126: append_number(struct state *state,
                    127:              unsigned long num, unsigned base, char *rep,
                    128:              int width, int prec, int flags, int minusp)
                    129: {
                    130:   int len = 0;
                    131:   int i;
                    132: 
                    133:   /* given precision, ignore zero flag */
                    134:   if(prec != -1)
                    135:     flags &= ~zero_flag;
                    136:   else
                    137:     prec = 1;
                    138:   /* zero value with zero precision -> "" */
                    139:   if(prec == 0 && num == 0)
                    140:     return 0;
                    141:   do{
                    142:     if((*state->append_char)(state, rep[num % base]))
                    143:       return 1;
                    144:     len++;
                    145:     num /= base;
                    146:   }while(num);
                    147:   prec -= len;
                    148:   /* pad with prec zeros */
                    149:   while(prec-- > 0){
                    150:     if((*state->append_char)(state, '0'))
                    151:       return 1;
                    152:     len++;
                    153:   }
                    154:   /* add length of alternate prefix (added later) to len */
                    155:   if(flags & alternate_flag && (base == 16 || base == 8))
                    156:     len += base / 8;
                    157:   /* pad with zeros */
                    158:   if(flags & zero_flag){
                    159:     width -= len;
                    160:     if(minusp || (flags & space_flag) || (flags & plus_flag))
                    161:       width--;
                    162:     while(width-- > 0){
                    163:       if((*state->append_char)(state, '0'))
                    164:        return 1;
                    165:       len++;
                    166:     }
                    167:   }
                    168:   /* add alternate prefix */
                    169:   if(flags & alternate_flag && (base == 16 || base == 8)){
                    170:     if(base == 16)
                    171:       if((*state->append_char)(state, rep[10] + 23)) /* XXX */
                    172:        return 1;
                    173:     if((*state->append_char)(state, '0'))
                    174:       return 1;
                    175:   }
                    176:   /* add sign */
                    177:   if(minusp){
                    178:     if((*state->append_char)(state, '-'))
                    179:       return 1;
                    180:     len++;
                    181:   } else if(flags & plus_flag) {
                    182:     if((*state->append_char)(state, '+'))
                    183:       return 1;
                    184:     len++;
                    185:   } else if(flags & space_flag) {
                    186:     if((*state->append_char)(state, ' '))
                    187:       return 1;
                    188:     len++;
                    189:   }
                    190:   if(flags & minus_flag)
                    191:     /* swap before padding with spaces */
                    192:     for(i = 0; i < len / 2; i++){
                    193:       char c = state->s[-i-1];
                    194:       state->s[-i-1] = state->s[-len+i];
                    195:       state->s[-len+i] = c;
                    196:     }
                    197:   width -= len;
                    198:   while(width-- > 0){
                    199:     if((*state->append_char)(state,  ' '))
                    200:       return 1;
                    201:     len++;
                    202:   }
                    203:   if(!(flags & minus_flag))
                    204:     /* swap after padding with spaces */
                    205:     for(i = 0; i < len / 2; i++){
                    206:       char c = state->s[-i-1];
                    207:       state->s[-i-1] = state->s[-len+i];
                    208:       state->s[-len+i] = c;
                    209:     }
                    210:     
                    211:   return 0;
                    212: }
                    213: 
                    214: static int
                    215: append_string (struct state *state,
                    216:               unsigned char *arg,
                    217:               int width,
                    218:               int prec,
                    219:               int flags)
                    220: {
                    221:   if(prec != -1)
                    222:     width -= prec;
                    223:   else
                    224:     width -= strlen((char *)arg);
                    225:   if(!(flags & minus_flag))
                    226:     while(width-- > 0)
                    227:       if((*state->append_char) (state, ' '))
                    228:        return 1;
                    229:   if (prec != -1) {
                    230:     while (*arg && prec--)
                    231:       if ((*state->append_char) (state, *arg++))
                    232:        return 1;
                    233:   } else {
                    234:     while (*arg)
                    235:       if ((*state->append_char) (state, *arg++))
                    236:        return 1;
                    237:   }
                    238:   if(flags & minus_flag)
                    239:     while(width-- > 0)
                    240:       if((*state->append_char) (state, ' '))
                    241:        return 1;
                    242:   return 0;
                    243: }
                    244: 
                    245: static int
                    246: append_char(struct state *state,
                    247:            unsigned char arg,
                    248:            int width,
                    249:            int flags)
                    250: {
                    251:   while(!(flags & minus_flag) && --width > 0)
                    252:     if((*state->append_char) (state, ' '))
                    253:       return 1;
                    254:     
                    255:   if((*state->append_char) (state, arg))
                    256:     return 1;
                    257:   while((flags & minus_flag) && --width > 0)
                    258:     if((*state->append_char) (state, ' '))
                    259:       return 1;
                    260:     
                    261:   return 0;
                    262: }
                    263: 
                    264: /*
                    265:  * This can't be made into a function...
                    266:  */
                    267: 
                    268: #define PARSE_INT_FORMAT(res, arg, unsig) \
                    269: if (long_flag) \
                    270:      res = (unsig long)va_arg(arg, unsig long); \
                    271: else if (short_flag) \
                    272:      res = (unsig short)va_arg(arg, unsig int); \
                    273: else \
                    274:      res = (unsig int)va_arg(arg, unsig int)
                    275: 
                    276: /*
                    277:  * zyxprintf - return 0 or -1
                    278:  */
                    279: 
                    280: static int
                    281: xyzprintf (struct state *state, const char *char_format, va_list ap)
                    282: {
                    283:   const unsigned char *format = (const unsigned char *)char_format;
                    284:   unsigned char c;
                    285: 
                    286:   while((c = *format++)) {
                    287:     if (c == '%') {
                    288:       int flags      = 0;
                    289:       int width      = 0;
                    290:       int prec       = -1;
                    291:       int long_flag  = 0;
                    292:       int short_flag = 0;
                    293: 
                    294:       /* flags */
                    295:       while((c = *format++)){
                    296:        if(c == '-')
                    297:          flags |= minus_flag;
                    298:        else if(c == '+')
                    299:          flags |= plus_flag;
                    300:        else if(c == ' ')
                    301:          flags |= space_flag;
                    302:        else if(c == '#')
                    303:          flags |= alternate_flag;
                    304:        else if(c == '0')
                    305:          flags |= zero_flag;
                    306:        else
                    307:          break;
                    308:       }
                    309:       
                    310:       if((flags & space_flag) && (flags & plus_flag))
                    311:        flags ^= space_flag;
                    312: 
                    313:       if((flags & minus_flag) && (flags & zero_flag))
                    314:        flags ^= zero_flag;
                    315: 
                    316:       /* width */
                    317:       if (isdigit(c))
                    318:        do {
                    319:          width = width * 10 + c - '0';
                    320:          c = *format++;
                    321:        } while(isdigit(c));
                    322:       else if(c == '*') {
                    323:        width = va_arg(ap, int);
                    324:        c = *format++;
                    325:       }
                    326: 
                    327:       /* precision */
                    328:       if (c == '.') {
                    329:        prec = 0;
                    330:        c = *format++;
                    331:        if (isdigit(c))
                    332:          do {
                    333:            prec = prec * 10 + c - '0';
                    334:            c = *format++;
                    335:          } while(isdigit(c));
                    336:        else if (c == '*') {
                    337:          prec = va_arg(ap, int);
                    338:          c = *format++;
                    339:        }
                    340:       }
                    341: 
                    342:       /* size */
                    343: 
                    344:       if (c == 'h') {
                    345:        short_flag = 1;
                    346:        c = *format++;
                    347:       } else if (c == 'l') {
                    348:        long_flag = 1;
                    349:        c = *format++;
                    350:       }
                    351: 
                    352:       switch (c) {
                    353:       case 'c' :
                    354:        if(append_char(state, va_arg(ap, int), width, flags))
                    355:          return -1;
                    356:        break;
                    357:       case 's' :
                    358:        if (append_string(state,
                    359:                          va_arg(ap, unsigned char*),
                    360:                          width,
                    361:                          prec, 
                    362:                          flags))
                    363:          return -1;
                    364:        break;
                    365:       case 'd' :
                    366:       case 'i' : {
                    367:        long arg;
                    368:        unsigned long num;
                    369:        int minusp = 0;
                    370: 
                    371:        PARSE_INT_FORMAT(arg, ap, signed);
                    372: 
                    373:        if (arg < 0) {
                    374:          minusp = 1;
                    375:          num = -arg;
                    376:        } else
                    377:          num = arg;
                    378: 
                    379:        if (append_number (state, num, 10, "0123456789",
                    380:                           width, prec, flags, minusp))
                    381:          return -1;
                    382:        break;
                    383:       }
                    384:       case 'u' : {
                    385:        unsigned long arg;
                    386: 
                    387:        PARSE_INT_FORMAT(arg, ap, unsigned);
                    388: 
                    389:        if (append_number (state, arg, 10, "0123456789",
                    390:                           width, prec, flags, 0))
                    391:          return -1;
                    392:        break;
                    393:       }
                    394:       case 'o' : {
                    395:        unsigned long arg;
                    396: 
                    397:        PARSE_INT_FORMAT(arg, ap, unsigned);
                    398: 
                    399:        if (append_number (state, arg, 010, "01234567",
                    400:                           width, prec, flags, 0))
                    401:          return -1;
                    402:        break;
                    403:       }
                    404:       case 'x' : {
                    405:        unsigned long arg;
                    406: 
                    407:        PARSE_INT_FORMAT(arg, ap, unsigned);
                    408: 
                    409:        if (append_number (state, arg, 0x10, "0123456789abcdef",
                    410:                           width, prec, flags, 0))
                    411:          return -1;
                    412:        break;
                    413:       }
                    414:       case 'X' :{
                    415:        unsigned long arg;
                    416: 
                    417:        PARSE_INT_FORMAT(arg, ap, unsigned);
                    418: 
                    419:        if (append_number (state, arg, 0x10, "0123456789ABCDEF",
                    420:                           width, prec, flags, 0))
                    421:          return -1;
                    422:        break;
                    423:       }
                    424:       case 'p' : {
                    425:        unsigned long arg = (unsigned long)va_arg(ap, void*);
                    426: 
                    427:        if (append_number (state, arg, 0x10, "0123456789ABCDEF",
                    428:                           width, prec, flags, 0))
                    429:          return -1;
                    430:        break;
                    431:       }
                    432:       case 'n' : {
                    433:        int *arg = va_arg(ap, int*);
                    434:        *arg = state->s - state->str;
                    435:        break;
                    436:       }
                    437:       case '\0' :
                    438:          --format;
                    439:          /* FALLTHROUGH */
                    440:       case '%' :
                    441:        if ((*state->append_char)(state, c))
                    442:          return -1;
                    443:        break;
                    444:       default :
                    445:        if (   (*state->append_char)(state, '%')
                    446:            || (*state->append_char)(state, c))
                    447:          return -1;
                    448:        break;
                    449:       }
                    450:     } else
                    451:       if ((*state->append_char) (state, c))
                    452:        return -1;
                    453:   }
                    454:   return 0;
                    455: }
                    456: 
                    457: int snprintf (char *str, size_t sz, const char *format, ...)
                    458: {
                    459:   va_list args;
                    460:   int ret;
                    461: 
                    462:   va_start(args, format);
                    463:   ret = vsnprintf (str, sz, format, args);
                    464:   va_end(args);
                    465:   return ret;
                    466: }
                    467: 
                    468: int vasprintf (char **ret, const char *format, va_list args)
                    469: {
                    470:   return vasnprintf (ret, 0, format, args);
                    471: }
                    472: 
                    473: int vasnprintf (char **ret, size_t max_sz, const char *format, va_list args)
                    474: {
                    475:   int st;
                    476:   size_t len;
                    477:   struct state state;
                    478: 
                    479:   state.max_sz = max_sz;
                    480:   state.sz     = 1;
                    481:   state.str    = malloc(state.sz);
                    482:   if (state.str == NULL) {
                    483:     *ret = NULL;
                    484:     return -1;
                    485:   }
                    486:   state.s = state.str;
                    487:   state.theend = state.s + state.sz - 1;
                    488:   state.append_char = as_append_char;
                    489:   state.reserve     = as_reserve;
                    490: 
                    491:   st = xyzprintf (&state, format, args);
                    492:   if (st) {
                    493:     free (state.str);
                    494:     *ret = NULL;
                    495:     return -1;
                    496:   } else {
                    497:     char *tmp;
                    498: 
                    499:     *state.s = '\0';
                    500:     len = state.s - state.str;
                    501:     tmp = realloc (state.str, len+1);
                    502:     if (tmp == NULL) {
                    503:       free (state.str);
                    504:       *ret = NULL;
                    505:       return -1;
                    506:     }
                    507:     *ret = tmp;
                    508:     return len;
                    509:   }
                    510: }
                    511: 
                    512: int vsnprintf (char *str, size_t sz, const char *format, va_list args)
                    513: {
                    514:   struct state state;
                    515:   int ret;
                    516:   unsigned char *ustr = (unsigned char *)str;
                    517: 
                    518:   state.max_sz = 0;
                    519:   state.sz     = sz;
                    520:   state.str    = ustr;
                    521:   state.s      = ustr;
                    522:   state.theend = ustr + sz - 1;
                    523:   state.append_char = sn_append_char;
                    524:   state.reserve     = sn_reserve;
                    525: 
                    526:   ret = xyzprintf (&state, format, args);
                    527:   *state.s = '\0';
                    528:   if (ret)
                    529:     return sz;
                    530:   else
                    531:     return state.s - state.str;
                    532: }
                    533: 
                    534: #endif /* SNPRINTF_C */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>