Annotation of parser3/src/lib/cord/cordprnt.c, revision 1.6
1.6 ! misha 1: /*
! 2: * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
! 3: *
! 4: * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
! 5: * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
! 6: *
! 7: * Permission is hereby granted to use or copy this program
! 8: * for any purpose, provided the above notices are retained on all copies.
! 9: * Permission to modify the code and to distribute modified code is granted,
! 10: * provided the above notices are retained, and a notice that the code was
! 11: * modified is included with the above copyright notice.
! 12: */
! 13: /* An sprintf implementation that understands cords. This is probably */
! 14: /* not terribly portable. It assumes an ANSI stdarg.h. It further */
! 15: /* assumes that I can make copies of va_list variables, and read */
! 16: /* arguments repeatedly by applyting va_arg to the copies. This */
! 17: /* could be avoided at some performance cost. */
! 18: /* We also assume that unsigned and signed integers of various kinds */
! 19: /* have the same sizes, and can be cast back and forth. */
! 20: /* We assume that void * and char * have the same size. */
! 21: /* All this cruft is needed because we want to rely on the underlying */
! 22: /* sprintf implementation whenever possible. */
! 23: /* Boehm, September 21, 1995 6:00 pm PDT */
! 24:
! 25: #include "pa_config_includes.h"
! 26: #include "cord.h"
! 27: #include "ec.h"
! 28: #include <stdio.h>
! 29: #include <stdarg.h>
! 30: #include <string.h>
! 31: #include "gc.h"
! 32:
! 33: #define CONV_SPEC_LEN 50 /* Maximum length of a single */
! 34: /* conversion specification. */
! 35: #define CONV_RESULT_LEN 50 /* Maximum length of any */
! 36: /* conversion with default */
! 37: /* width and prec. */
! 38:
! 39:
! 40: static int ec_len(CORD_ec x)
! 41: {
! 42: return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
! 43: }
! 44:
! 45: /* Possible nonumeric precision values. */
! 46: # define NONE -1
! 47: # define VARIABLE -2
! 48: /* Copy the conversion specification from CORD_pos into the buffer buf */
! 49: /* Return negative on error. */
! 50: /* Source initially points one past the leading %. */
! 51: /* It is left pointing at the conversion type. */
! 52: /* Assign field width and precision to *width and *prec. */
! 53: /* If width or prec is *, VARIABLE is assigned. */
! 54: /* Set *left to 1 if left adjustment flag is present. */
! 55: /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
! 56: /* -1 if 'h' is present. */
! 57: static int extract_conv_spec(CORD_pos source, char *buf,
! 58: int * width, int *prec, int *left, int * long_arg)
! 59: {
! 60: register int result = 0;
! 61: register int current_number = 0;
! 62: register int saw_period = 0;
! 63: register int saw_number;
! 64: register int chars_so_far = 0;
! 65: register char current;
! 66:
! 67: *width = NONE;
! 68: buf[chars_so_far++] = '%';
! 69: while(CORD_pos_valid(source)) {
! 70: if (chars_so_far >= CONV_SPEC_LEN) return(-1);
! 71: current = CORD_pos_fetch(source);
! 72: buf[chars_so_far++] = current;
! 73: switch(current) {
! 74: case '*':
! 75: saw_number = 1;
! 76: current_number = VARIABLE;
! 77: break;
! 78: case '0':
! 79: if (!saw_number) {
! 80: /* Zero fill flag; ignore */
! 81: break;
! 82: } /* otherwise fall through: */
! 83: case '1':
! 84: case '2':
! 85: case '3':
! 86: case '4':
! 87: case '5':
! 88: case '6':
! 89: case '7':
! 90: case '8':
! 91: case '9':
! 92: saw_number = 1;
! 93: current_number *= 10;
! 94: current_number += current - '0';
! 95: break;
! 96: case '.':
! 97: saw_period = 1;
! 98: if(saw_number) {
! 99: *width = current_number;
! 100: saw_number = 0;
! 101: }
! 102: current_number = 0;
! 103: break;
! 104: case 'l':
! 105: case 'L':
! 106: *long_arg = 1;
! 107: current_number = 0;
! 108: break;
! 109: case 'h':
! 110: *long_arg = -1;
! 111: current_number = 0;
! 112: break;
! 113: case ' ':
! 114: case '+':
! 115: case '#':
! 116: current_number = 0;
! 117: break;
! 118: case '-':
! 119: *left = 1;
! 120: current_number = 0;
! 121: break;
! 122: case 'd':
! 123: case 'i':
! 124: case 'o':
! 125: case 'u':
! 126: case 'x':
! 127: case 'X':
! 128: case 'f':
! 129: case 'e':
! 130: case 'E':
! 131: case 'g':
! 132: case 'G':
! 133: case 'c':
! 134: case 'C':
! 135: case 's':
! 136: case 'S':
! 137: case 'p':
! 138: case 'n':
! 139: case 'r':
! 140: goto done;
! 141: default:
! 142: return(-1);
! 143: }
! 144: CORD_next(source);
! 145: }
! 146: return(-1);
! 147: done:
! 148: if (saw_number) {
! 149: if (saw_period) {
! 150: *prec = current_number;
! 151: } else {
! 152: *prec = NONE;
! 153: *width = current_number;
! 154: }
! 155: } else {
! 156: *prec = NONE;
! 157: }
! 158: buf[chars_so_far] = '\0';
! 159: return(result);
! 160: }
! 161:
! 162: int CORD_vsprintf(CORD * out, CORD format, va_list args)
! 163: {
! 164: CORD_ec result;
! 165: register int count;
! 166: register char current;
! 167: CORD_pos pos;
! 168: char conv_spec[CONV_SPEC_LEN + 1];
! 169:
! 170: CORD_ec_init(result);
! 171: for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
! 172: current = CORD_pos_fetch(pos);
! 173: if (current == '%') {
! 174: CORD_next(pos);
! 175: if (!CORD_pos_valid(pos)) return(-1);
! 176: current = CORD_pos_fetch(pos);
! 177: if (current == '%') {
! 178: CORD_ec_append(result, current);
! 179: } else {
! 180: int width, prec;
! 181: int left_adj = 0;
! 182: int long_arg = 0;
! 183: CORD arg;
! 184: size_t len;
! 185:
! 186: if (extract_conv_spec(pos, conv_spec,
! 187: &width, &prec,
! 188: &left_adj, &long_arg) < 0) {
! 189: return(-1);
! 190: }
! 191: current = CORD_pos_fetch(pos);
! 192: switch(current) {
! 193: case 'n':
! 194: /* Assign length to next arg */
! 195: if (long_arg == 0) {
! 196: int * pos_ptr;
! 197: pos_ptr = va_arg(args, int *);
! 198: *pos_ptr = ec_len(result);
! 199: } else if (long_arg > 0) {
! 200: long * pos_ptr;
! 201: pos_ptr = va_arg(args, long *);
! 202: *pos_ptr = ec_len(result);
! 203: } else {
! 204: short * pos_ptr;
! 205: pos_ptr = va_arg(args, short *);
! 206: *pos_ptr = ec_len(result);
! 207: }
! 208: goto done;
! 209: case 'r':
! 210: /* Append cord and any padding */
! 211: if (width == VARIABLE) width = va_arg(args, int);
! 212: if (prec == VARIABLE) prec = va_arg(args, int);
! 213: arg = va_arg(args, CORD);
! 214: len = CORD_len(arg);
! 215: if (prec != NONE && len > (size_t)prec) {
! 216: if (prec < 0) return(-1);
! 217: arg = CORD_substr(arg, 0, prec, 0);
! 218: len = prec;
! 219: }
! 220: if (width != NONE && len < (size_t)width) {
! 221: char * blanks = GC_MALLOC_ATOMIC(width-len+1);
! 222:
! 223: memset(blanks, ' ', width-len);
! 224: blanks[width-len] = '\0';
! 225: if (left_adj) {
! 226: arg = CORD_cat(arg, blanks);
! 227: } else {
! 228: arg = CORD_cat(blanks, arg);
! 229: }
! 230: }
! 231: CORD_ec_append_cord(result, arg);
! 232: goto done;
! 233: case 'c':
! 234: if (width == NONE && prec == NONE) {
! 235: register char c;
! 236:
! 237: c = (char)va_arg(args, int);
! 238: CORD_ec_append(result, c);
! 239: goto done;
! 240: }
! 241: break;
! 242: case 's':
! 243: if (width == NONE && prec == NONE) {
! 244: char * str = va_arg(args, char *);
! 245: register char c;
! 246:
! 247: while (c = *str++) {
! 248: CORD_ec_append(result, c);
! 249: }
! 250: goto done;
! 251: }
! 252: break;
! 253: default:
! 254: break;
! 255: }
! 256: /* Use standard sprintf to perform conversion */
! 257: {
! 258: register char * buf;
! 259: va_list vsprintf_args;
! 260: int max_size = 0;
! 261: int res;
! 262: # ifdef __va_copy
! 263: __va_copy(vsprintf_args, args);
! 264: # else
! 265: # if defined(__GNUC__) /* and probably in other cases */
! 266: va_copy(vsprintf_args, args);
! 267: # else
! 268: vsprintf_args = args;
! 269: # endif
! 270: # endif
! 271: if (width == VARIABLE) width = va_arg(args, int);
! 272: if (prec == VARIABLE) prec = va_arg(args, int);
! 273: if (width != NONE) max_size = width;
! 274: if (prec != NONE && prec > max_size) max_size = prec;
! 275: max_size += CONV_RESULT_LEN;
! 276: if (max_size >= CORD_BUFSZ) {
! 277: buf = GC_MALLOC_ATOMIC(max_size + 1);
! 278: } else {
! 279: if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
! 280: < max_size) {
! 281: CORD_ec_flush_buf(result);
! 282: }
! 283: buf = result[0].ec_bufptr;
! 284: }
! 285: switch(current) {
! 286: case 'd':
! 287: case 'i':
! 288: case 'o':
! 289: case 'u':
! 290: case 'x':
! 291: case 'X':
! 292: case 'c':
! 293: if (long_arg <= 0) {
! 294: (void) va_arg(args, int);
! 295: } else if (long_arg > 0) {
! 296: (void) va_arg(args, long);
! 297: }
! 298: break;
! 299: case 's':
! 300: case 'p':
! 301: (void) va_arg(args, char *);
! 302: break;
! 303: case 'f':
! 304: case 'e':
! 305: case 'E':
! 306: case 'g':
! 307: case 'G':
! 308: (void) va_arg(args, double);
! 309: break;
! 310: default:
! 311: return(-1);
! 312: }
! 313: res = vsprintf(buf, conv_spec, vsprintf_args);
! 314: len = (size_t)res;
! 315: if ((char *)(GC_word)res == buf) {
! 316: /* old style vsprintf */
! 317: len = strlen(buf);
! 318: } else if (res < 0) {
! 319: return(-1);
! 320: }
! 321: if (buf != result[0].ec_bufptr) {
! 322: register char c;
! 323:
! 324: while (c = *buf++) {
! 325: CORD_ec_append(result, c);
! 326: }
! 327: } else {
! 328: result[0].ec_bufptr = buf + len;
! 329: }
! 330: }
! 331: done:;
! 332: }
! 333: } else {
! 334: CORD_ec_append(result, current);
! 335: }
! 336: }
! 337: count = ec_len(result);
! 338: *out = CORD_balance(CORD_ec_to_cord(result));
! 339: return(count);
! 340: }
! 341:
! 342: int CORD_sprintf(CORD * out, CORD format, ...)
! 343: {
! 344: va_list args;
! 345: int result;
! 346:
! 347: va_start(args, format);
! 348: result = CORD_vsprintf(out, format, args);
! 349: va_end(args);
! 350: return(result);
! 351: }
! 352:
! 353: int CORD_fprintf(FILE * f, CORD format, ...)
! 354: {
! 355: va_list args;
! 356: int result;
! 357: CORD out;
! 358:
! 359: va_start(args, format);
! 360: result = CORD_vsprintf(&out, format, args);
! 361: va_end(args);
! 362: if (result > 0) CORD_put(out, f);
! 363: return(result);
! 364: }
! 365:
! 366: int CORD_vfprintf(FILE * f, CORD format, va_list args)
! 367: {
! 368: int result;
! 369: CORD out;
! 370:
! 371: result = CORD_vsprintf(&out, format, args);
! 372: if (result > 0) CORD_put(out, f);
! 373: return(result);
! 374: }
! 375:
! 376: int CORD_printf(CORD format, ...)
! 377: {
! 378: va_list args;
! 379: int result;
! 380: CORD out;
! 381:
! 382: va_start(args, format);
! 383: result = CORD_vsprintf(&out, format, args);
! 384: va_end(args);
! 385: if (result > 0) CORD_put(out, stdout);
! 386: return(result);
! 387: }
! 388:
! 389: int CORD_vprintf(CORD format, va_list args)
! 390: {
! 391: int result;
! 392: CORD out;
! 393:
! 394: result = CORD_vsprintf(&out, format, args);
! 395: if (result > 0) CORD_put(out, stdout);
! 396: return(result);
! 397: }
E-mail: