Annotation of parser3/src/lib/cord/cordprnt.c, revision 1.7

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 "gc.h"
                     29: 
                     30: #define CONV_SPEC_LEN 50       /* Maximum length of a single   */
                     31:                                /* conversion specification.    */
                     32: #define CONV_RESULT_LEN 50     /* Maximum length of any        */
                     33:                                /* conversion with default      */
                     34:                                /* width and prec.              */
                     35: 
                     36: 
                     37: static int ec_len(CORD_ec x)
                     38: {
                     39:     return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
                     40: }
                     41: 
                     42: /* Possible nonumeric precision values.        */
                     43: # define NONE -1
                     44: # define VARIABLE -2
                     45: /* Copy the conversion specification from CORD_pos into the buffer buf */
                     46: /* Return negative on error.                                           */
                     47: /* Source initially points one past the leading %.                     */
                     48: /* It is left pointing at the conversion type.                         */
                     49: /* Assign field width and precision to *width and *prec.               */
                     50: /* If width or prec is *, VARIABLE is assigned.                                */
                     51: /* Set *left to 1 if left adjustment flag is present.                  */
                     52: /* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to      */
                     53: /* -1 if 'h' is present.                                               */
                     54: static int extract_conv_spec(CORD_pos source, char *buf,
                     55:                             int * width, int *prec, int *left, int * long_arg)
                     56: {
                     57:     register int result = 0;
                     58:     register int current_number = 0;
                     59:     register int saw_period = 0;
                     60:     register int saw_number;
                     61:     register int chars_so_far = 0;
                     62:     register char current;
                     63:     
                     64:     *width = NONE;
                     65:     buf[chars_so_far++] = '%';
                     66:     while(CORD_pos_valid(source)) {
                     67:         if (chars_so_far >= CONV_SPEC_LEN) return(-1);
                     68:         current = CORD_pos_fetch(source);
                     69:         buf[chars_so_far++] = current;
                     70:         switch(current) {
                     71:          case '*':
                     72:            saw_number = 1;
                     73:            current_number = VARIABLE;
                     74:            break;
                     75:           case '0':
                     76:             if (!saw_number) {
                     77:                 /* Zero fill flag; ignore */
                     78:                 break;
                     79:             } /* otherwise fall through: */
                     80:           case '1':
                     81:          case '2':
                     82:          case '3':
                     83:          case '4':
                     84:          case '5':
                     85:           case '6':
                     86:          case '7':
                     87:          case '8':
                     88:          case '9':
                     89:            saw_number = 1;
                     90:            current_number *= 10;
                     91:            current_number += current - '0';
                     92:            break;
                     93:          case '.':
                     94:            saw_period = 1;
                     95:            if(saw_number) {
                     96:                *width = current_number;
                     97:                saw_number = 0;
                     98:            }
                     99:            current_number = 0;
                    100:            break;
                    101:          case 'l':
                    102:          case 'L':
                    103:            *long_arg = 1;
                    104:            current_number = 0;
                    105:            break;
                    106:          case 'h':
                    107:            *long_arg = -1;
                    108:            current_number = 0;
                    109:            break;
                    110:          case ' ':
                    111:          case '+':
                    112:          case '#':
                    113:            current_number = 0;
                    114:            break;
                    115:          case '-':
                    116:            *left = 1;
                    117:            current_number = 0;
                    118:            break;
                    119:          case 'd':
                    120:          case 'i':
                    121:          case 'o':
                    122:          case 'u':
                    123:          case 'x':
                    124:          case 'X':
                    125:          case 'f':
                    126:          case 'e':
                    127:          case 'E':
                    128:          case 'g':
                    129:          case 'G':
                    130:          case 'c':
                    131:          case 'C':
                    132:          case 's':
                    133:          case 'S':
                    134:          case 'p':
                    135:          case 'n':
                    136:          case 'r':
                    137:            goto done;          
                    138:           default:
                    139:             return(-1);
                    140:         }
                    141:         CORD_next(source);
                    142:     }
                    143:     return(-1);
                    144:   done:
                    145:     if (saw_number) {
                    146:        if (saw_period) {
                    147:            *prec = current_number;
                    148:        } else {
                    149:            *prec = NONE;
                    150:            *width = current_number;
                    151:        }
                    152:     } else {
                    153:        *prec = NONE;
                    154:     }
                    155:     buf[chars_so_far] = '\0';
                    156:     return(result);
                    157: }
                    158: 
                    159: int CORD_vsprintf(CORD * out, CORD format, va_list args)
                    160: {
                    161:     CORD_ec result;
                    162:     register int count;
                    163:     register char current;
                    164:     CORD_pos pos;
                    165:     char conv_spec[CONV_SPEC_LEN + 1];
                    166:     
                    167:     CORD_ec_init(result);
                    168:     for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
                    169:                current = CORD_pos_fetch(pos);
                    170:                if (current == '%') {
                    171:             CORD_next(pos);
                    172:             if (!CORD_pos_valid(pos)) return(-1);
                    173:             current = CORD_pos_fetch(pos);
                    174:             if (current == '%') {
                    175:                        CORD_ec_append(result, current);
                    176:             } else {
                    177:                int width, prec;
                    178:                int left_adj = 0;
                    179:                int long_arg = 0;
                    180:                CORD arg;
                    181:                size_t len;
                    182:                
                    183:                if (extract_conv_spec(pos, conv_spec,
                    184:                                      &width, &prec,
                    185:                                      &left_adj, &long_arg) < 0) {
                    186:                    return(-1);
                    187:                }
                    188:                current = CORD_pos_fetch(pos);
                    189:                switch(current) {
                    190:                    case 'n':
                    191:                        /* Assign length to next arg */
                    192:                        if (long_arg == 0) {
                    193:                            int * pos_ptr;
                    194:                            pos_ptr = va_arg(args, int *);
                    195:                            *pos_ptr = ec_len(result);
                    196:                        } else if (long_arg > 0) {
                    197:                            long * pos_ptr;
                    198:                            pos_ptr = va_arg(args, long *);
                    199:                            *pos_ptr = ec_len(result);
                    200:                        } else {
                    201:                            short * pos_ptr;
                    202:                            pos_ptr = va_arg(args, short *);
                    203:                            *pos_ptr = ec_len(result);
                    204:                        }
                    205:                        goto done;
                    206:                    case 'r':
                    207:                        /* Append cord and any padding  */
                    208:                        if (width == VARIABLE) width = va_arg(args, int);
                    209:                        if (prec == VARIABLE) prec = va_arg(args, int);
                    210:                        arg = va_arg(args, CORD);
                    211:                        len = CORD_len(arg);
                    212:                        if (prec != NONE && len > (size_t)prec) {
                    213:                          if (prec < 0) return(-1);
                    214:                          arg = CORD_substr(arg, 0, prec, 0);
                    215:                          len = prec;
                    216:                        }
                    217:                        if (width != NONE && len < (size_t)width) {
                    218:                          char * blanks = GC_MALLOC_ATOMIC(width-len+1);
                    219: 
                    220:                          memset(blanks, ' ', width-len);
                    221:                          blanks[width-len] = '\0';
                    222:                          if (left_adj) {
                    223:                            arg = CORD_cat(arg, blanks);
                    224:                          } else {
                    225:                            arg = CORD_cat(blanks, arg);
                    226:                          }
                    227:                        }
                    228:                        CORD_ec_append_cord(result, arg);
                    229:                        goto done;
                    230:                    case 'c':
                    231:                        if (width == NONE && prec == NONE) {
                    232:                            register char c;
                    233: 
                    234:                            c = (char)va_arg(args, int);
                    235:                            CORD_ec_append(result, c);
                    236:                            goto done;
                    237:                        }
                    238:                        break;
                    239:                    case 's':
                    240:                        if (width == NONE && prec == NONE) {
                    241:                            char * str = va_arg(args, char *);
                    242:                            register char c;
                    243: 
                    244:                            while (c = *str++) {
                    245:                                CORD_ec_append(result, c);
                    246:                            }
                    247:                            goto done;
                    248:                        }
                    249:                        break;
                    250:                    default:
                    251:                        break;
                    252:                }
                    253:                /* Use standard sprintf to perform conversion */
                    254:                {
                    255:                    register char * buf;
                    256:                    va_list vsprintf_args;
                    257:                    int max_size = 0;
                    258:                    int res;
                    259: #                  ifdef __va_copy
                    260:                       __va_copy(vsprintf_args, args);
                    261: #                  else
                    262: #                    if defined(__GNUC__) /* and probably in other cases */
                    263:                         va_copy(vsprintf_args, args);
                    264: #                    else
                    265:                        vsprintf_args = args;
                    266: #                    endif
                    267: #                  endif
                    268:                    if (width == VARIABLE) width = va_arg(args, int);
                    269:                    if (prec == VARIABLE) prec = va_arg(args, int);
                    270:                    if (width != NONE) max_size = width;
                    271:                    if (prec != NONE && prec > max_size) max_size = prec;
                    272:                    max_size += CONV_RESULT_LEN;
                    273:                    if (max_size >= CORD_BUFSZ) {
                    274:                        buf = GC_MALLOC_ATOMIC(max_size + 1);
                    275:                    } else {
                    276:                        if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
                    277:                            < max_size) {
                    278:                            CORD_ec_flush_buf(result);
                    279:                        }
                    280:                        buf = result[0].ec_bufptr;
                    281:                    }
                    282:                    switch(current) {
                    283:                        case 'd':
                    284:                        case 'i':
                    285:                        case 'o':
                    286:                        case 'u':
                    287:                        case 'x':
                    288:                        case 'X':
                    289:                        case 'c':
                    290:                            if (long_arg <= 0) {
                    291:                              (void) va_arg(args, int);
                    292:                            } else if (long_arg > 0) {
                    293:                              (void) va_arg(args, long);
                    294:                            }
                    295:                            break;
                    296:                        case 's':
                    297:                        case 'p':
                    298:                            (void) va_arg(args, char *);
                    299:                            break;
                    300:                        case 'f':
                    301:                        case 'e':
                    302:                        case 'E':
                    303:                        case 'g':
                    304:                        case 'G':
                    305:                            (void) va_arg(args, double);
                    306:                            break;
                    307:                        default:
                    308:                            return(-1);
                    309:                    }
                    310:                    res = vsprintf(buf, conv_spec, vsprintf_args);
                    311:                    len = (size_t)res;
                    312:                    if ((char *)(GC_word)res == buf) {
                    313:                        /* old style vsprintf */
                    314:                        len = strlen(buf);
                    315:                    } else if (res < 0) {
                    316:                        return(-1);
                    317:                    }
                    318:                    if (buf != result[0].ec_bufptr) {
                    319:                        register char c;
                    320: 
                    321:                        while (c = *buf++) {
                    322:                            CORD_ec_append(result, c);
                    323:                        }
                    324:                    } else {
                    325:                        result[0].ec_bufptr = buf + len;
                    326:                    }
                    327:                }
                    328:               done:;
                    329:             }
                    330:         } else {
                    331:             CORD_ec_append(result, current);
                    332:         }
                    333:     }
                    334:     count = ec_len(result);
                    335:     *out = CORD_balance(CORD_ec_to_cord(result));
                    336:     return(count);
                    337: }
                    338: 
                    339: int CORD_sprintf(CORD * out, CORD format, ...)
                    340: {
                    341:     va_list args;
                    342:     int result;
                    343:     
                    344:     va_start(args, format);
                    345:     result = CORD_vsprintf(out, format, args);
                    346:     va_end(args);
                    347:     return(result);
                    348: }
                    349: 
                    350: int CORD_fprintf(FILE * f, CORD format, ...)
                    351: {
                    352:     va_list args;
                    353:     int result;
                    354:     CORD out;
                    355:     
                    356:     va_start(args, format);
                    357:     result = CORD_vsprintf(&out, format, args);
                    358:     va_end(args);
                    359:     if (result > 0) CORD_put(out, f);
                    360:     return(result);
                    361: }
                    362: 
                    363: int CORD_vfprintf(FILE * f, CORD format, va_list args)
                    364: {
                    365:     int result;
                    366:     CORD out;
                    367:     
                    368:     result = CORD_vsprintf(&out, format, args);
                    369:     if (result > 0) CORD_put(out, f);
                    370:     return(result);
                    371: }
                    372: 
                    373: int CORD_printf(CORD format, ...)
                    374: {
                    375:     va_list args;
                    376:     int result;
                    377:     CORD out;
                    378:     
                    379:     va_start(args, format);
                    380:     result = CORD_vsprintf(&out, format, args);
                    381:     va_end(args);
                    382:     if (result > 0) CORD_put(out, stdout);
                    383:     return(result);
                    384: }
                    385: 
                    386: int CORD_vprintf(CORD format, va_list args)
                    387: {
                    388:     int result;
                    389:     CORD out;
                    390:     
                    391:     result = CORD_vsprintf(&out, format, args);
                    392:     if (result > 0) CORD_put(out, stdout);
                    393:     return(result);
                    394: }

E-mail: