| File: | subcmd/unitools/format.c |
| Warning: | line 54, column 2 Value stored to 'cc' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /***************************************************************************** |
| 2 | * |
| 3 | * format.c: Printf-style formatting with general desination. |
| 4 | * |
| 5 | * Copyright (c) 1990-2007 Aldor Software Organization Ltd (Aldor.org). |
| 6 | * |
| 7 | ****************************************************************************/ |
| 8 | |
| 9 | /* |
| 10 | * This uses sprintf to do the actual formatting into stack allocated buffer. |
| 11 | */ |
| 12 | |
| 13 | #include "axlgen.h" |
| 14 | #include "format.h" |
| 15 | #include "list.h" |
| 16 | #include "store.h" |
| 17 | #include "strops.h" |
| 18 | #include "util.h" |
| 19 | |
| 20 | /* |
| 21 | * fnewline(fout) prints a newline and indents next line by amount findent. |
| 22 | */ |
| 23 | int findent = 0; |
| 24 | localstatic int fmtPPrint(Format format, int width, char *fmt, OStream stream, Pointer ptr); |
| 25 | localstatic int fmtIPrint(Format format, int width, char *fmt, OStream stream, int n); |
| 26 | |
| 27 | int |
| 28 | fnewline(FILE *fout) |
| 29 | { |
| 30 | int i; |
| 31 | fputc('\n', fout); |
| 32 | for (i = 0; i < findent; i++) fputc(' ', fout); |
| 33 | return findent + 1; |
| 34 | } |
| 35 | |
| 36 | String |
| 37 | aStrPrintf(const char *fmt, ...) |
| 38 | { |
| 39 | String str; |
| 40 | va_list argp; |
| 41 | va_start(argp, fmt)__builtin_va_start(argp, fmt); |
| 42 | str = vaStrPrintf(fmt, argp); |
| 43 | va_end(argp)__builtin_va_end(argp); |
| 44 | return str; |
| 45 | } |
| 46 | |
| 47 | String |
| 48 | vaStrPrintf(const char *fmt, va_list argp) |
| 49 | { |
| 50 | int cc; |
| 51 | Buffer buf = bufNew(); |
| 52 | OStream ostream = ostreamNewFrBuffer(buf); |
| 53 | |
| 54 | cc = ostreamVPrintf(ostream, fmt, argp); |
Value stored to 'cc' is never read | |
| 55 | ostreamClose(ostream); |
| 56 | ostreamFree(ostream); |
| 57 | |
| 58 | return bufLiberate(buf); |
| 59 | } |
| 60 | |
| 61 | int |
| 62 | afprintf(FILE *fout, const char *fmt, ...) |
| 63 | { |
| 64 | int cc; |
| 65 | va_list argp; |
| 66 | va_start(argp, fmt)__builtin_va_start(argp, fmt); |
| 67 | cc = afvprintf(fout, fmt, argp); |
| 68 | va_end(argp)__builtin_va_end(argp); |
| 69 | return cc; |
| 70 | } |
| 71 | |
| 72 | int aprintf(const char *fmt, ...) |
| 73 | { |
| 74 | int cc; |
| 75 | va_list argp; |
| 76 | va_start(argp, fmt)__builtin_va_start(argp, fmt); |
| 77 | cc = avprintf(fmt, argp); |
| 78 | va_end(argp)__builtin_va_end(argp); |
| 79 | return cc; |
| 80 | } |
| 81 | |
| 82 | int |
| 83 | avprintf(const char *fmt, va_list argp) |
| 84 | { |
| 85 | return afvprintf(stdoutstdout, fmt, argp); |
| 86 | } |
| 87 | |
| 88 | int |
| 89 | afvprintf(FILE *fout, const char *fmt, va_list argp) |
| 90 | { |
| 91 | struct ostream os; |
| 92 | int cc; |
| 93 | |
| 94 | ostreamInitFrFile(&os, fout); |
| 95 | cc = ostreamVPrintf(&os, fmt, argp); |
| 96 | ostreamClose(&os); |
| 97 | return cc; |
| 98 | } |
| 99 | |
| 100 | |
| 101 | /* |
| 102 | * xprintf is like printf but takes a function to actually put the characters. |
| 103 | * |
| 104 | * Given a null function pointer, xprintf computes the number of characters |
| 105 | * without doing output. |
| 106 | * The XPutFun consumes a string and returns the count of emitted characters. |
| 107 | */ |
| 108 | |
| 109 | int |
| 110 | xprintf(XPutFun putfun, const char *fmt, ...) |
| 111 | { |
| 112 | int cc; |
| 113 | va_list argp; |
| 114 | va_start(argp, fmt)__builtin_va_start(argp, fmt); |
| 115 | cc = vxprintf(putfun, fmt, argp); |
| 116 | va_end(argp)__builtin_va_end(argp); |
| 117 | return cc; |
| 118 | } |
| 119 | |
| 120 | |
| 121 | struct fbuf { |
| 122 | int width, prec; /* -1 if none */ |
| 123 | char size, conv; /* 0 if none */ |
| 124 | char fmt[100]; /* A string containing it. */ |
| 125 | int len; /* Current length of buf. */ |
| 126 | }; |
| 127 | |
| 128 | |
| 129 | localstatic void |
| 130 | xputFunWriteChar(OStream o, char c) |
| 131 | { |
| 132 | if (o->data.fun) |
| 133 | o->data.fun (&c, 1); |
| 134 | } |
| 135 | |
| 136 | localstatic int |
| 137 | xputFunWriteString(OStream o, const char *str, int n) |
| 138 | { |
| 139 | if (o->data.fun) |
| 140 | return o->data.fun (str, n); |
| 141 | else |
| 142 | return n == -1 ? strlen(str): n; |
| 143 | } |
| 144 | |
| 145 | localstatic void |
| 146 | xputFunClose(OStream o) |
| 147 | { |
| 148 | } |
| 149 | |
| 150 | struct ostreamOps ostreamXPutFunOps = { |
| 151 | xputFunWriteChar, |
| 152 | xputFunWriteString, |
| 153 | xputFunClose, |
| 154 | }; |
| 155 | |
| 156 | int |
| 157 | vxprintf(XPutFun putfun, const char *fmt, va_list argp) |
| 158 | { |
| 159 | struct ostream os; |
| 160 | int cc; |
| 161 | |
| 162 | os.ops = &ostreamXPutFunOps; |
| 163 | os.data.fun = putfun; |
| 164 | cc = ostreamVPrintf(&os, fmt, argp); |
| 165 | |
| 166 | return cc; |
| 167 | } |
| 168 | |
| 169 | int |
| 170 | ostreamPrintf(OStream ostream, const char *fmt, ...) |
| 171 | { |
| 172 | va_list argp; |
| 173 | int cc; |
| 174 | |
| 175 | va_start(argp, fmt)__builtin_va_start(argp, fmt); |
| 176 | cc = ostreamVPrintf(ostream, fmt, argp); |
| 177 | va_end(argp)__builtin_va_end(argp); |
| 178 | |
| 179 | return cc; |
| 180 | } |
| 181 | |
| 182 | int |
| 183 | ostreamVPrintf(OStream ostream, const char *fmt, va_list argp) |
| 184 | { |
| 185 | int c, r, w, cc; |
| 186 | struct fbuf fb; |
| 187 | char *f, arg_buf[256]; |
| 188 | |
| 189 | for (cc = 0; *fmt; ) { |
| 190 | |
| 191 | if (*fmt != '%') { |
| 192 | int i; |
| 193 | for (i = 0; fmt[i] && fmt[i] != '%'; i++) ; |
| 194 | if (ostream) i = ostreamWrite(ostream, fmt, i); |
| 195 | cc += i; |
| 196 | fmt += i; |
| 197 | continue; |
| 198 | } |
| 199 | /************************************************************ |
| 200 | * Parse according to ANSI Standard X3.159-1989: |
| 201 | * %[flags][width][.prec][szmod]conv |
| 202 | ************************************************************/ |
| 203 | fb.len = 0; |
| 204 | |
| 205 | /* % */ |
| 206 | fb.fmt[fb.len++] = *fmt++; |
| 207 | |
| 208 | /* Flags */ |
| 209 | while ((c = *fmt)=='-'||c=='+'||c==' '||c=='#'||c=='0') |
| 210 | fb.fmt[fb.len++] = *fmt++; |
| 211 | |
| 212 | /* Width */ |
| 213 | r = -1; |
| 214 | if (*fmt == '*') { |
| 215 | r = va_arg(argp, int)__builtin_va_arg(argp, int); |
| 216 | if (r < 0) { r = -r; fb.fmt[fb.len++] = '-'; } |
| 217 | fmt++; |
| 218 | fb.len += sprintf(fb.fmt + fb.len, "%d", r); |
| 219 | } |
| 220 | else if (isdigit(*fmt)((*__ctype_b_loc ())[(int) ((*fmt))] & (unsigned short int ) _ISdigit)) |
| 221 | for (r = 0; isdigit(c = *fmt)((*__ctype_b_loc ())[(int) ((c = *fmt))] & (unsigned short int) _ISdigit); fmt++) { |
| 222 | r = 10*r + c - '0'; |
| 223 | fb.fmt[fb.len++] = c; |
| 224 | } |
| 225 | fb.width = r; |
| 226 | |
| 227 | /* Precision */ |
| 228 | if (*fmt == '.') fb.fmt[fb.len++] = *fmt++; |
| 229 | |
| 230 | r = -1; |
| 231 | if (*fmt == '*') { |
| 232 | r = va_arg(argp, int)__builtin_va_arg(argp, int); |
| 233 | if (r < 0) { r = -r; fb.fmt[fb.len++] = '-'; } |
| 234 | fmt++; |
| 235 | fb.len += sprintf(fb.fmt + fb.len, "%d", r); |
| 236 | } |
| 237 | else if (isdigit(*fmt)((*__ctype_b_loc ())[(int) ((*fmt))] & (unsigned short int ) _ISdigit)) |
| 238 | for (r = 0; isdigit(c = *fmt)((*__ctype_b_loc ())[(int) ((c = *fmt))] & (unsigned short int) _ISdigit); fmt++) { |
| 239 | r = 10*r + c - '0'; |
| 240 | fb.fmt[fb.len++] = c; |
| 241 | } |
| 242 | fb.prec = r; |
| 243 | |
| 244 | /* Size modifier */ |
| 245 | if ((c = *fmt) == 'h' || c == 'l' || c == 'L' || c == 'z') |
| 246 | fb.fmt[fb.len++] = fb.size = *fmt++; |
| 247 | else |
| 248 | fb.size = 0; |
| 249 | |
| 250 | /* Conversion character */ |
| 251 | fb.fmt[fb.len++] = fb.conv = *fmt++; |
| 252 | fb.fmt[fb.len] = 0; |
| 253 | |
| 254 | /************************************************************ |
| 255 | * Perform the formatting on the indicated parameter |
| 256 | * and increment the character count. |
| 257 | ************************************************************/ |
| 258 | /* n format requires the parameter to be assigned cc */ |
| 259 | if (fb.conv == 'n') { |
| 260 | switch (fb.size) { |
| 261 | case 'h': *va_arg(argp, short *)__builtin_va_arg(argp, short *) = cc; break; |
| 262 | case 'l': *va_arg(argp, long *)__builtin_va_arg(argp, long *) = cc; break; |
| 263 | case 'z': *va_arg(argp, Length *)__builtin_va_arg(argp, Length *) = cc; break; |
| 264 | default: *va_arg(argp, int *)__builtin_va_arg(argp, int *) = cc; break; |
| 265 | } |
| 266 | continue; |
| 267 | } |
| 268 | /* s format could point to arbitrarily long string */ |
| 269 | if (fb.conv == 's') { |
| 270 | char *s = va_arg(argp, char *)__builtin_va_arg(argp, char *); |
| 271 | if (ostream) { |
| 272 | int l = strlen(s), w = fb.width; |
| 273 | int pad = w-l > 0 ? w-l : 0; |
| 274 | while (pad > 0) { |
| 275 | ostreamWriteChar(ostream, ' '); |
| 276 | cc++; |
| 277 | pad--; |
| 278 | } |
| 279 | cc += ostreamWrite(ostream, s, -1); |
| 280 | } |
| 281 | else { |
| 282 | int l = strlen(s), w = fb.width; |
| 283 | cc += (w != -1 && w < l) ? w : l; |
| 284 | } |
| 285 | continue; |
| 286 | } |
| 287 | if (fb.conv == 'o'){ |
| 288 | Format format = fmtMatch(fmt); |
| 289 | if (format == NULL((void*)0)) { |
| 290 | w = fb.width + fb.prec + 30; /* over estimate */ |
| 291 | f = (w < sizeof(arg_buf)) ? fb.fmt : "<too wide to format>"; |
| 292 | sprintf(arg_buf, f, va_arg(argp, int)__builtin_va_arg(argp, int)); |
| 293 | cc += ostreamWrite(ostream, arg_buf, -1); |
| 294 | } |
| 295 | else { |
| 296 | cc += fmtIPrint(format, fb.width, fb.fmt, ostream, va_arg(argp, int)__builtin_va_arg(argp, int)); |
| 297 | fmt += strlen(format->name); |
| 298 | } |
| 299 | continue; |
| 300 | } |
| 301 | if (fb.conv == 'p') { |
| 302 | Format format = fmtMatch(fmt); |
| 303 | if (format == NULL((void*)0)) { |
| 304 | w = fb.width + fb.prec + 30; /* over estimate */ |
| 305 | f = (w < sizeof(arg_buf)) ? fb.fmt : "<too wide to format>"; |
| 306 | sprintf(arg_buf, f, va_arg(argp, Pointer)__builtin_va_arg(argp, Pointer)); |
| 307 | cc += ostreamWrite(ostream, arg_buf, -1); |
| 308 | } |
| 309 | else { |
| 310 | cc += fmtPPrint(format, fb.width, fb.fmt, ostream, va_arg(argp, Pointer)__builtin_va_arg(argp, Pointer)); |
| 311 | fmt += strlen(format->name); |
| 312 | } |
| 313 | continue; |
| 314 | } |
| 315 | /* Remaining formats are short unless width or prec is given */ |
| 316 | |
| 317 | w = fb.width + fb.prec + 30; /* over estimate */ |
| 318 | f = (w < sizeof(arg_buf)) ? fb.fmt : "<too wide to format>"; |
| 319 | |
| 320 | switch (fb.conv) { |
| 321 | case '%': |
| 322 | sprintf(arg_buf, "%s", f); |
| 323 | break; |
| 324 | case 'c': |
| 325 | case 'd': case 'i': case 'u': |
| 326 | case 'o': case 'x': case 'X': |
| 327 | if (fb.size == 'l') |
| 328 | sprintf(arg_buf,f,va_arg(argp, long)__builtin_va_arg(argp, long)); |
| 329 | else if (fb.size == 'z') |
| 330 | sprintf(arg_buf,f,va_arg(argp, Length)__builtin_va_arg(argp, Length)); |
| 331 | else |
| 332 | sprintf(arg_buf,f,va_arg(argp, int)__builtin_va_arg(argp, int)); |
| 333 | break; |
| 334 | case 'e': case 'E': case 'f': case 'g': case 'G': |
| 335 | if (fb.size == 'L') |
| 336 | sprintf(arg_buf,f,va_arg(argp, long double)__builtin_va_arg(argp, long double)); |
| 337 | else |
| 338 | sprintf(arg_buf,f,va_arg(argp, double)__builtin_va_arg(argp, double)); |
| 339 | break; |
| 340 | } |
| 341 | if (ostream) |
| 342 | cc += ostreamWrite(ostream, arg_buf, -1); |
| 343 | else |
| 344 | cc += strlen(arg_buf); |
| 345 | } |
| 346 | return cc; |
| 347 | } |
| 348 | |
| 349 | /* |
| 350 | * :: User defined formats |
| 351 | */ |
| 352 | |
| 353 | DECLARE_LIST(Format)typedef struct FormatListCons { Format first; struct FormatListCons *rest; } *FormatList; struct Format_listOpsStruct { FormatList (*Cons) (Format, FormatList); FormatList (*Singleton) (Format ); FormatList (*List) (int n, ...); FormatList (*Listv) (va_list argp); FormatList (*ListNull) (Format, ...); Bool (*Equal) ( FormatList, FormatList, Bool (*f) (Format, Format)); Format ( *Find) (FormatList, Format, Bool(*eq)(Format,Format) , int *) ; Format (*Match) (FormatList, void *, Bool(*match)(Format, void *), int *); FormatList (*MatchAll) (FormatList, void *, Bool (*match)(Format, void *)); FormatList (*FreeCons) (FormatList ); void (*Free) (FormatList); FormatList (*FreeTo) (FormatList , FormatList); void (*FreeDeeply) (FormatList, void (*f)(Format )); FormatList (*FreeDeeplyTo) (FormatList, FormatList, void ( *f) (Format) ); FormatList (*FreeIfSat) (FormatList, void (*f )(Format), Bool (*s)(Format)); Format (*Elt) (FormatList, Length ); FormatList (*Drop) (FormatList, Length); FormatList (*LastCons ) (FormatList); Length (*_Length) (FormatList); Bool (*IsLength ) (FormatList, Length); Bool (*IsShorter) (FormatList, Length ); Bool (*IsLonger) (FormatList, Length); FormatList (*Copy) ( FormatList); FormatList (*CopyTo) (FormatList, FormatList); FormatList (*CopyDeeply) (FormatList, Format (*)(Format)); FormatList ( *CopyDeeplyTo) (FormatList, FormatList, Format (*)(Format)); FormatList (*Map) (Format (*f)(Format), FormatList); FormatList (*NMap) (Format (*f)(Format), FormatList); FormatList (*Reverse) (FormatList ); FormatList (*NReverse) (FormatList); FormatList (*Concat) ( FormatList, FormatList); FormatList (*NConcat) (FormatList, FormatList ); Bool (*Memq) (FormatList, Format); Bool (*Member) (FormatList , Format, Bool(*eq)(Format,Format) ); Bool (*ContainsAllq) (FormatList , FormatList); Bool (*ContainsAnyq) (FormatList, FormatList); Bool (*ContainsAll) (FormatList, FormatList, Bool (*eq)(Format , Format)); Bool (*ContainsAny) (FormatList, FormatList, Bool (*eq)(Format, Format)); int (*Posq) (FormatList, Format); int (*Position) (FormatList, Format, Bool(*eq)(Format,Format) ); FormatList (*NRemove) (FormatList, Format, Bool(*eq)(Format, Format) ); void (*FillVector) (Format *, FormatList); int (*Print ) (FILE *, FormatList, int (*pr)(FILE *, Format) ); int (*GPrint ) (FILE *, FormatList, int (*pr)(FILE *, Format), char *l,char *m,char *r); int (*Format) (OStream, CString, FormatList); } ; extern struct Format_listOpsStruct const *Format_listPointer; |
| 354 | CREATE_LIST(Format)struct Format_listOpsStruct const *Format_listPointer = (struct Format_listOpsStruct const *) &ptrlistOps; |
| 355 | |
| 356 | static FormatList fmtRegisteredFormats = listNil(Format)((FormatList) 0); |
| 357 | |
| 358 | void |
| 359 | fmtRegister(const char *name, PFormatFn fn) |
| 360 | { |
| 361 | fmtRegisterFull(name, fn, true1); |
| 362 | } |
| 363 | |
| 364 | void |
| 365 | fmtRegisterFull(const char *name, PFormatFn fn, Bool nullOk) |
| 366 | { |
| 367 | Format format = (Format) stoAlloc(OB_Other0, sizeof(*format)); |
| 368 | assert(name[0] != '\0')do { if (!(name[0] != '\0')) _do_assert(("name[0] != '\\0'"), "format.c",368); } while (0); |
| 369 | format->name = strCopy(name); |
| 370 | format->pfn = fn; |
| 371 | format->ifn = NULL((void*)0); |
| 372 | format->nullOk = nullOk; |
| 373 | format->apfn = NULL((void*)0); |
| 374 | format->aifn = NULL((void*)0); |
| 375 | fmtRegisteredFormats = listCons(Format)(Format_listPointer->Cons)(format, fmtRegisteredFormats); |
| 376 | } |
| 377 | |
| 378 | void fmtRegisterI(const char *name, IFormatFn ifn) |
| 379 | { |
| 380 | Format format = (Format) stoAlloc(OB_Other0, sizeof(*format)); |
| 381 | assert(name[0] != '\0')do { if (!(name[0] != '\0')) _do_assert(("name[0] != '\\0'"), "format.c",381); } while (0); |
| 382 | format->name = strCopy(name); |
| 383 | format->ifn = ifn; |
| 384 | format->nullOk = false((int) 0); |
| 385 | format->apfn = NULL((void*)0); |
| 386 | format->aifn = NULL((void*)0); |
| 387 | fmtRegisteredFormats = listCons(Format)(Format_listPointer->Cons)(format, fmtRegisteredFormats); |
| 388 | } |
| 389 | |
| 390 | void fmtRegisterAlt(const char *name, AltPFormatFn fn) |
| 391 | { |
| 392 | Format f = fmtMatch(name); |
| 393 | if (f == NULL((void*)0)) |
| 394 | bug("Missing format"); |
| 395 | |
| 396 | f->apfn = fn; |
| 397 | } |
| 398 | |
| 399 | |
| 400 | Format |
| 401 | fmtMatch(const char *fmtTxt) |
| 402 | { |
| 403 | size_t longestMatch = 0; |
| 404 | Format match = NULL((void*)0); |
| 405 | FormatList list; |
| 406 | |
| 407 | if (fmtTxt[0] == '\0') |
| 408 | return NULL((void*)0); |
| 409 | |
| 410 | list = fmtRegisteredFormats; |
| 411 | while (list != listNil(Format)((FormatList) 0)) { |
| 412 | Format format = car(list)((list)->first); |
| 413 | list = cdr(list)((list)->rest); |
| 414 | if (strIsPrefix(format->name, fmtTxt) |
| 415 | && (size_t) strlen(format->name) > longestMatch) { |
| 416 | match = format; |
| 417 | longestMatch = strlen(match->name); |
| 418 | } |
| 419 | } |
| 420 | |
| 421 | return match; |
| 422 | } |
| 423 | |
| 424 | static int |
| 425 | fmtPPrint(Format format, int width, char *fmt, OStream stream, Pointer ptr) |
| 426 | { |
| 427 | int outlvl = 0; |
| 428 | int c; |
| 429 | assert(format != NULL)do { if (!(format != ((void*)0))) _do_assert(("format != NULL" ),"format.c",429); } while (0); |
| 430 | |
| 431 | if (!format->nullOk && ptr == NULL((void*)0)) { |
| 432 | return ostreamPrintf(stream, "(nil)"); |
| 433 | } |
| 434 | while (*fmt != '\0') { |
| 435 | if (*fmt == '#') outlvl++; |
| 436 | fmt++; |
| 437 | } |
| 438 | if (outlvl == 0 || format->apfn == NULL((void*)0)) |
| 439 | c = format->pfn(stream, ptr); |
| 440 | else |
| 441 | c = format->apfn(stream, outlvl, ptr); |
| 442 | |
| 443 | return c; |
| 444 | } |
| 445 | |
| 446 | static int |
| 447 | fmtIPrint(Format format, int width, char *fmt, OStream stream, int n) |
| 448 | { |
| 449 | assert(format != NULL)do { if (!(format != ((void*)0))) _do_assert(("format != NULL" ),"format.c",449); } while (0); |
| 450 | return format->ifn(stream, n); |
| 451 | } |