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>