1 /* Formatted output to strings. 2 Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 2, or (at your option) 7 any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with this program; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ 17 18 #ifdef HAVE_CONFIG_H 19 # include <config.h> 20 #endif 21 22 /* Specification. */ 23 #if WIDE_CHAR_VERSION 24 # include "wprintf-parse.h" 25 #else 26 # include "printf-parse.h" 27 #endif 28 29 /* Get size_t, NULL. */ 30 #include <stddef.h> 31 32 /* Get intmax_t. */ 33 #if HAVE_STDINT_H_WITH_UINTMAX 34 # include <stdint.h> 35 #endif 36 #if HAVE_INTTYPES_H_WITH_UINTMAX 37 # include <inttypes.h> 38 #endif 39 40 /* malloc(), realloc(), free(). */ 41 #include <stdlib.h> 42 43 /* Checked size_t computations. */ 44 #include "xsize.h" 45 46 #if WIDE_CHAR_VERSION 47 # define PRINTF_PARSE wprintf_parse 48 # define CHAR_T wchar_t 49 # define DIRECTIVE wchar_t_directive 50 # define DIRECTIVES wchar_t_directives 51 #else 52 # define PRINTF_PARSE printf_parse 53 # define CHAR_T char 54 # define DIRECTIVE char_directive 55 # define DIRECTIVES char_directives 56 #endif 57 58 #ifdef STATIC 59 STATIC 60 #endif 61 int 62 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a) 63 { 64 const CHAR_T *cp = format; /* pointer into format */ 65 size_t arg_posn = 0; /* number of regular arguments consumed */ 66 size_t d_allocated; /* allocated elements of d->dir */ 67 size_t a_allocated; /* allocated elements of a->arg */ 68 size_t max_width_length = 0; 69 size_t max_precision_length = 0; 70 71 d->count = 0; 72 d_allocated = 1; 73 d->dir = malloc (d_allocated * sizeof (DIRECTIVE)); 74 if (d->dir == NULL) 75 /* Out of memory. */ 76 return -1; 77 78 a->count = 0; 79 a_allocated = 0; 80 a->arg = NULL; 81 82 #define REGISTER_ARG(_index_,_type_) \ 83 { \ 84 size_t n = (_index_); \ 85 if (n >= a_allocated) \ 86 { \ 87 size_t memory_size; \ 88 argument *memory; \ 89 \ 90 a_allocated = xtimes (a_allocated, 2); \ 91 if (a_allocated <= n) \ 92 a_allocated = xsum (n, 1); \ 93 memory_size = xtimes (a_allocated, sizeof (argument)); \ 94 if (size_overflow_p (memory_size)) \ 95 /* Overflow, would lead to out of memory. */ \ 96 goto error; \ 97 memory = (a->arg \ 98 ? realloc (a->arg, memory_size) \ 99 : malloc (memory_size)); \ 100 if (memory == NULL) \ 101 /* Out of memory. */ \ 102 goto error; \ 103 a->arg = memory; \ 104 } \ 105 while (a->count <= n) \ 106 a->arg[a->count++].type = TYPE_NONE; \ 107 if (a->arg[n].type == TYPE_NONE) \ 108 a->arg[n].type = (_type_); \ 109 else if (a->arg[n].type != (_type_)) \ 110 /* Ambiguous type for positional argument. */ \ 111 goto error; \ 112 } 113 114 while (*cp != '\0') 115 { 116 CHAR_T c = *cp++; 117 if (c == '%') 118 { 119 size_t arg_index = ARG_NONE; 120 DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */ 121 122 /* Initialize the next directive. */ 123 dp->dir_start = cp - 1; 124 dp->flags = 0; 125 dp->width_start = NULL; 126 dp->width_end = NULL; 127 dp->width_arg_index = ARG_NONE; 128 dp->precision_start = NULL; 129 dp->precision_end = NULL; 130 dp->precision_arg_index = ARG_NONE; 131 dp->arg_index = ARG_NONE; 132 133 /* Test for positional argument. */ 134 if (*cp >= '0' && *cp <= '9') 135 { 136 const CHAR_T *np; 137 138 for (np = cp; *np >= '0' && *np <= '9'; np++) 139 ; 140 if (*np == '$') 141 { 142 size_t n = 0; 143 144 for (np = cp; *np >= '0' && *np <= '9'; np++) 145 n = xsum (xtimes (n, 10), *np - '0'); 146 if (n == 0) 147 /* Positional argument 0. */ 148 goto error; 149 if (size_overflow_p (n)) 150 /* n too large, would lead to out of memory later. */ 151 goto error; 152 arg_index = n - 1; 153 cp = np + 1; 154 } 155 } 156 157 /* Read the flags. */ 158 for (;;) 159 { 160 if (*cp == '\'') 161 { 162 dp->flags |= FLAG_GROUP; 163 cp++; 164 } 165 else if (*cp == '-') 166 { 167 dp->flags |= FLAG_LEFT; 168 cp++; 169 } 170 else if (*cp == '+') 171 { 172 dp->flags |= FLAG_SHOWSIGN; 173 cp++; 174 } 175 else if (*cp == ' ') 176 { 177 dp->flags |= FLAG_SPACE; 178 cp++; 179 } 180 else if (*cp == '#') 181 { 182 dp->flags |= FLAG_ALT; 183 cp++; 184 } 185 else if (*cp == '0') 186 { 187 dp->flags |= FLAG_ZERO; 188 cp++; 189 } 190 else 191 break; 192 } 193 194 /* Parse the field width. */ 195 if (*cp == '*') 196 { 197 dp->width_start = cp; 198 cp++; 199 dp->width_end = cp; 200 if (max_width_length < 1) 201 max_width_length = 1; 202 203 /* Test for positional argument. */ 204 if (*cp >= '0' && *cp <= '9') 205 { 206 const CHAR_T *np; 207 208 for (np = cp; *np >= '0' && *np <= '9'; np++) 209 ; 210 if (*np == '$') 211 { 212 size_t n = 0; 213 214 for (np = cp; *np >= '0' && *np <= '9'; np++) 215 n = xsum (xtimes (n, 10), *np - '0'); 216 if (n == 0) 217 /* Positional argument 0. */ 218 goto error; 219 if (size_overflow_p (n)) 220 /* n too large, would lead to out of memory later. */ 221 goto error; 222 dp->width_arg_index = n - 1; 223 cp = np + 1; 224 } 225 } 226 if (dp->width_arg_index == ARG_NONE) 227 { 228 dp->width_arg_index = arg_posn++; 229 if (dp->width_arg_index == ARG_NONE) 230 /* arg_posn wrapped around. */ 231 goto error; 232 } 233 REGISTER_ARG (dp->width_arg_index, TYPE_INT); 234 } 235 else if (*cp >= '0' && *cp <= '9') 236 { 237 size_t width_length; 238 239 dp->width_start = cp; 240 for (; *cp >= '0' && *cp <= '9'; cp++) 241 ; 242 dp->width_end = cp; 243 width_length = dp->width_end - dp->width_start; 244 if (max_width_length < width_length) 245 max_width_length = width_length; 246 } 247 248 /* Parse the precision. */ 249 if (*cp == '.') 250 { 251 cp++; 252 if (*cp == '*') 253 { 254 dp->precision_start = cp - 1; 255 cp++; 256 dp->precision_end = cp; 257 if (max_precision_length < 2) 258 max_precision_length = 2; 259 260 /* Test for positional argument. */ 261 if (*cp >= '0' && *cp <= '9') 262 { 263 const CHAR_T *np; 264 265 for (np = cp; *np >= '0' && *np <= '9'; np++) 266 ; 267 if (*np == '$') 268 { 269 size_t n = 0; 270 271 for (np = cp; *np >= '0' && *np <= '9'; np++) 272 n = xsum (xtimes (n, 10), *np - '0'); 273 if (n == 0) 274 /* Positional argument 0. */ 275 goto error; 276 if (size_overflow_p (n)) 277 /* n too large, would lead to out of memory 278 later. */ 279 goto error; 280 dp->precision_arg_index = n - 1; 281 cp = np + 1; 282 } 283 } 284 if (dp->precision_arg_index == ARG_NONE) 285 { 286 dp->precision_arg_index = arg_posn++; 287 if (dp->precision_arg_index == ARG_NONE) 288 /* arg_posn wrapped around. */ 289 goto error; 290 } 291 REGISTER_ARG (dp->precision_arg_index, TYPE_INT); 292 } 293 else 294 { 295 size_t precision_length; 296 297 dp->precision_start = cp - 1; 298 for (; *cp >= '0' && *cp <= '9'; cp++) 299 ; 300 dp->precision_end = cp; 301 precision_length = dp->precision_end - dp->precision_start; 302 if (max_precision_length < precision_length) 303 max_precision_length = precision_length; 304 } 305 } 306 307 { 308 arg_type type; 309 310 /* Parse argument type/size specifiers. */ 311 { 312 int flags = 0; 313 314 for (;;) 315 { 316 if (*cp == 'h') 317 { 318 flags |= (1 << (flags & 1)); 319 cp++; 320 } 321 else if (*cp == 'L') 322 { 323 flags |= 4; 324 cp++; 325 } 326 else if (*cp == 'l') 327 { 328 flags += 8; 329 cp++; 330 } 331 #ifdef HAVE_INTMAX_T 332 else if (*cp == 'j') 333 { 334 if (sizeof (intmax_t) > sizeof (long)) 335 { 336 /* intmax_t = long long */ 337 flags += 16; 338 } 339 else if (sizeof (intmax_t) > sizeof (int)) 340 { 341 /* intmax_t = long */ 342 flags += 8; 343 } 344 cp++; 345 } 346 #endif 347 else if (*cp == 'z' || *cp == 'Z') 348 { 349 /* 'z' is standardized in ISO C 99, but glibc uses 'Z' 350 because the warning facility in gcc-2.95.2 understands 351 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */ 352 if (sizeof (size_t) > sizeof (long)) 353 { 354 /* size_t = long long */ 355 flags += 16; 356 } 357 else if (sizeof (size_t) > sizeof (int)) 358 { 359 /* size_t = long */ 360 flags += 8; 361 } 362 cp++; 363 } 364 else if (*cp == 't') 365 { 366 if (sizeof (ptrdiff_t) > sizeof (long)) 367 { 368 /* ptrdiff_t = long long */ 369 flags += 16; 370 } 371 else if (sizeof (ptrdiff_t) > sizeof (int)) 372 { 373 /* ptrdiff_t = long */ 374 flags += 8; 375 } 376 cp++; 377 } 378 else 379 break; 380 } 381 382 /* Read the conversion character. */ 383 c = *cp++; 384 switch (c) 385 { 386 case 'd': case 'i': 387 #ifdef HAVE_LONG_LONG 388 if (flags >= 16 || (flags & 4)) 389 type = TYPE_LONGLONGINT; 390 else 391 #endif 392 if (flags >= 8) 393 type = TYPE_LONGINT; 394 else if (flags & 2) 395 type = TYPE_SCHAR; 396 else if (flags & 1) 397 type = TYPE_SHORT; 398 else 399 type = TYPE_INT; 400 break; 401 case 'o': case 'u': case 'x': case 'X': 402 #ifdef HAVE_LONG_LONG 403 if (flags >= 16 || (flags & 4)) 404 type = TYPE_ULONGLONGINT; 405 else 406 #endif 407 if (flags >= 8) 408 type = TYPE_ULONGINT; 409 else if (flags & 2) 410 type = TYPE_UCHAR; 411 else if (flags & 1) 412 type = TYPE_USHORT; 413 else 414 type = TYPE_UINT; 415 break; 416 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': 417 case 'a': case 'A': 418 #ifdef HAVE_LONG_DOUBLE 419 if (flags >= 16 || (flags & 4)) 420 type = TYPE_LONGDOUBLE; 421 else 422 #endif 423 type = TYPE_DOUBLE; 424 break; 425 case 'c': 426 if (flags >= 8) 427 #ifdef HAVE_WINT_T 428 type = TYPE_WIDE_CHAR; 429 #else 430 goto error; 431 #endif 432 else 433 type = TYPE_CHAR; 434 break; 435 #ifdef HAVE_WINT_T 436 case 'C': 437 type = TYPE_WIDE_CHAR; 438 c = 'c'; 439 break; 440 #endif 441 case 's': 442 if (flags >= 8) 443 #ifdef HAVE_WCHAR_T 444 type = TYPE_WIDE_STRING; 445 #else 446 goto error; 447 #endif 448 else 449 type = TYPE_STRING; 450 break; 451 #ifdef HAVE_WCHAR_T 452 case 'S': 453 type = TYPE_WIDE_STRING; 454 c = 's'; 455 break; 456 #endif 457 case 'p': 458 type = TYPE_POINTER; 459 break; 460 case 'n': 461 #ifdef HAVE_LONG_LONG 462 if (flags >= 16 || (flags & 4)) 463 type = TYPE_COUNT_LONGLONGINT_POINTER; 464 else 465 #endif 466 if (flags >= 8) 467 type = TYPE_COUNT_LONGINT_POINTER; 468 else if (flags & 2) 469 type = TYPE_COUNT_SCHAR_POINTER; 470 else if (flags & 1) 471 type = TYPE_COUNT_SHORT_POINTER; 472 else 473 type = TYPE_COUNT_INT_POINTER; 474 break; 475 case '%': 476 type = TYPE_NONE; 477 break; 478 default: 479 /* Unknown conversion character. */ 480 goto error; 481 } 482 } 483 484 if (type != TYPE_NONE) 485 { 486 dp->arg_index = arg_index; 487 if (dp->arg_index == ARG_NONE) 488 { 489 dp->arg_index = arg_posn++; 490 if (dp->arg_index == ARG_NONE) 491 /* arg_posn wrapped around. */ 492 goto error; 493 } 494 REGISTER_ARG (dp->arg_index, type); 495 } 496 dp->conversion = c; 497 dp->dir_end = cp; 498 } 499 500 d->count++; 501 if (d->count >= d_allocated) 502 { 503 size_t memory_size; 504 DIRECTIVE *memory; 505 506 d_allocated = xtimes (d_allocated, 2); 507 memory_size = xtimes (d_allocated, sizeof (DIRECTIVE)); 508 if (size_overflow_p (memory_size)) 509 /* Overflow, would lead to out of memory. */ 510 goto error; 511 memory = realloc (d->dir, memory_size); 512 if (memory == NULL) 513 /* Out of memory. */ 514 goto error; 515 d->dir = memory; 516 } 517 } 518 } 519 d->dir[d->count].dir_start = cp; 520 521 d->max_width_length = max_width_length; 522 d->max_precision_length = max_precision_length; 523 return 0; 524 525 error: 526 if (a->arg) 527 free (a->arg); 528 if (d->dir) 529 free (d->dir); 530 return -1; 531 } 532 533 #undef DIRECTIVES 534 #undef DIRECTIVE 535 #undef CHAR_T 536 #undef PRINTF_PARSE 537