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