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

1.2       paf         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: 
1.4     ! paf        25: #include "pa_config_includes.h"
1.2       paf        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);
1.3       paf       215:                        if (prec != NONE && len > (size_t)prec) {
1.2       paf       216:                          if (prec < 0) return(-1);
                    217:                          arg = CORD_substr(arg, 0, prec);
                    218:                          len = prec;
                    219:                        }
1.3       paf       220:                        if (width != NONE && len < (size_t)width) {
1.2       paf       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: