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