Annotation of embedaddon/trafshow/snprintf.c, revision 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>