root/gc/cord/cordprnt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ec_len
  2. extract_conv_spec
  3. CORD_vsprintf
  4. CORD_sprintf
  5. CORD_fprintf
  6. CORD_vfprintf
  7. CORD_printf
  8. CORD_vprintf

   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 = 0;
  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__) && !defined(__DJGPP__) /* 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 }

/* [<][>][^][v][top][bottom][index][help] */