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