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