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