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

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

E-mail: