PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/snprintfv/snprintfv/printf.c

https://github.com/indeyets/smalltalk
C | 1526 lines | 800 code | 210 blank | 516 comment | 96 complexity | 3b8675047719955494d474a2ebef90a0 MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-4.0, LGPL-2.1, CC-BY-SA-3.0
  1. /* -*- Mode: C -*- */
  2. /* printf.c --- printf clone for argv arrays
  3. * Copyright (C) 1998, 1999, 2000, 2002 Gary V. Vaughan
  4. * Originally by Gary V. Vaughan, 1998
  5. * This file is part of Snprintfv
  6. *
  7. * Snprintfv is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * Snprintfv program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. *
  21. * As a special exception to the GNU General Public License, if you
  22. * distribute this file as part of a program that also links with and
  23. * uses the libopts library from AutoGen, you may include it under
  24. * the same distribution terms used by the libopts library.
  25. */
  26. /* Code: */
  27. #ifdef HAVE_CONFIG_H
  28. # include <config.h>
  29. #endif
  30. #include <unistd.h> /* for the write(2) call */
  31. #define COMPILING_PRINTF_C
  32. #include "printf.h"
  33. #ifdef WITH_DMALLOC
  34. #include <dmalloc.h>
  35. #endif
  36. #include "filament.h"
  37. #include "stream.h"
  38. #include "mem.h"
  39. #define EOS '\0'
  40. #define SNV_CHAR_SPEC '%'
  41. #define SNV_ESC_SPEC '\\'
  42. /* Functions to manage mapping of spec chars to handlers. */
  43. SNV_INLINE unsigned spec_hash (unsigned spec);
  44. SNV_INLINE void spec_init (void);
  45. SNV_INLINE spec_entry *spec_lookup (unsigned spec);
  46. static void spec_insert (spec_entry * pentry);
  47. static int do_printfv (STREAM *stream, const char *format, union printf_arg const args[]);
  48. /* FIXME: We are assuming an ASCII character set where all the
  49. printable characters are between SPACE and DEL. */
  50. #define ASCII_DEL (int)'\177'
  51. #define ASCII_SPACE (int)' '
  52. #define IS_MODIFIER(spec) (!((spec)->fmt))
  53. /* TODO: This is not thread-safe. Change the API to pass the spec_table
  54. in as the first parameter to the functions which use it? */
  55. static spec_entry *spec_table[ASCII_DEL - ASCII_SPACE];
  56. /* TODO: This is not thread-safe as well. */
  57. static char *printf_last_error;
  58. SNV_INLINE unsigned
  59. spec_hash (unsigned spec)
  60. {
  61. return (spec & ASCII_DEL) - ASCII_SPACE;
  62. }
  63. /* Register all of the functions in INIT_SPEC_TABLE. */
  64. static void
  65. spec_init (void)
  66. {
  67. static boolean is_init = FALSE;
  68. if (!is_init)
  69. {
  70. extern spec_entry snv_default_spec_table[];
  71. unsigned index = 0;
  72. memset (spec_table, 0, sizeof (spec_table));
  73. while (snv_default_spec_table[index].spec != EOS)
  74. {
  75. unsigned hash = spec_hash (snv_default_spec_table[index].spec);
  76. spec_table[hash] = snv_default_spec_table + index;
  77. index++;
  78. }
  79. is_init = TRUE;
  80. }
  81. }
  82. /* Insert PENTRY, a new handler, into SPEC_TABLE. */
  83. SNV_INLINE void
  84. spec_insert (spec_entry *pentry)
  85. {
  86. unsigned hash = spec_hash (pentry->spec);
  87. spec_init ();
  88. spec_table[hash] = pentry;
  89. }
  90. /* Lookup and return the SPEC_TABLE entry for SPEC. */
  91. SNV_INLINE spec_entry *
  92. spec_lookup (unsigned spec)
  93. {
  94. unsigned hash = spec_hash (spec);
  95. spec_init ();
  96. return spec_table[hash];
  97. }
  98. /**
  99. * register_printf_function: printf.h
  100. * @spec: the character which will trigger @func, cast to an unsigned int.
  101. * @fmt: the handler function to actually print the arguments to the specifier
  102. * @arg: the handler function to tell %printf about the types of the arguments to the specifier
  103. *
  104. * Register the pair made of @fmt and @arg, so that it is called
  105. * when @spec is encountered in a format string.
  106. *
  107. * Return value:
  108. * Returns %NULL if @func was not successfully registered, a
  109. * %spec_entry with the information on the function if it was.
  110. **/
  111. spec_entry *
  112. register_printf_function (unsigned spec, printf_function *fmt, printf_arginfo_function *arg)
  113. {
  114. spec_entry *new, *old;
  115. old = spec_lookup (spec);
  116. if (old && IS_MODIFIER (old))
  117. return NULL;
  118. if (!fmt || !spec)
  119. return NULL;
  120. new = snv_new (spec_entry, 1);
  121. new->spec = spec;
  122. new->fmt = fmt;
  123. new->arg = arg;
  124. new->user = NULL;
  125. spec_insert (new);
  126. return new;
  127. }
  128. static int
  129. call_argtype_function (struct printf_info *const pinfo, int **argtypes, spec_entry *spec)
  130. {
  131. int n;
  132. int argindex = (pinfo->dollar && !IS_MODIFIER (spec))
  133. ? pinfo->dollar - 1
  134. : pinfo->argindex;
  135. int save_argindex = pinfo->argindex;
  136. int save_state = pinfo->state;
  137. char const *save_format = pinfo->format;
  138. if (!spec->arg)
  139. {
  140. n = 1;
  141. if (pinfo->argc <= argindex)
  142. {
  143. /*
  144. * "argtypes" points to a pointer of an array of int values.
  145. * Here, we ensure that there are "argindex + 1" entries in
  146. * that array.
  147. */
  148. *argtypes = snv_renew (int, *argtypes, argindex + 1);
  149. /*
  150. * IF there are more entries that follow the current argument
  151. * index, then we will clobber all the entries that follow.
  152. * The size of these entries is the size of the array elements,
  153. * not the size of the pointer to the array elements.
  154. */
  155. if (pinfo->argc < argindex)
  156. memset(*argtypes + pinfo->argc, PA_UNKNOWN,
  157. (argindex - pinfo->argc) * sizeof(**argtypes));
  158. pinfo->argc = argindex + 1;
  159. }
  160. (*argtypes) [argindex] = spec->type;
  161. }
  162. else
  163. {
  164. pinfo->spec = *pinfo->format;
  165. pinfo->extra = spec->user;
  166. pinfo->type = spec->type;
  167. if (pinfo->argc > argindex)
  168. n = spec->arg(pinfo, (size_t) (pinfo->argc - argindex),
  169. *argtypes + argindex);
  170. else
  171. n = spec->arg(pinfo, (size_t) 0, NULL);
  172. if (n < 0)
  173. return n;
  174. if (argindex + n > pinfo->argc)
  175. {
  176. int new_ct = argindex + n;
  177. *argtypes = snv_renew (int, *argtypes, new_ct);
  178. memset(*argtypes + pinfo->argc, PA_UNKNOWN,
  179. (new_ct - pinfo->argc) * sizeof(**argtypes));
  180. pinfo->argc = argindex + n;
  181. /* Call again... */
  182. pinfo->argindex = save_argindex;
  183. pinfo->format = save_format;
  184. pinfo->state = save_state;
  185. pinfo->spec = *pinfo->format;
  186. pinfo->extra = spec->user;
  187. pinfo->type = spec->type;
  188. n = spec->arg(pinfo, (size_t)n, *argtypes + argindex);
  189. }
  190. }
  191. if (!pinfo->dollar && !IS_MODIFIER (spec))
  192. pinfo->argindex += n;
  193. return n;
  194. }
  195. /**
  196. * printf_strerror: printf.h
  197. *
  198. * Communicate information on the last error in a printf
  199. * format string.
  200. *
  201. * Return value:
  202. * A string describing the last error which occurred during the
  203. * parsing of a printf format string. It is the responsibility
  204. * of the caller to free the string.
  205. */
  206. char *
  207. printf_strerror (void)
  208. {
  209. return snv_strdup(printf_last_error);
  210. }
  211. /* (re)initialise the memory used by PPARSER. */
  212. static inline void
  213. parser_init (struct printf_info *pinfo, const char *format, const union printf_arg *args)
  214. {
  215. memset (pinfo, 0, sizeof (struct printf_info));
  216. pinfo->format = format;
  217. pinfo->args = args;
  218. }
  219. static inline struct printf_info *
  220. parser_reset (struct printf_info *pinfo)
  221. {
  222. pinfo->is_long_double = pinfo->is_char = pinfo->is_short =
  223. pinfo->is_long = pinfo->alt = pinfo->space = pinfo->left =
  224. pinfo->showsign = pinfo->group = pinfo->wide =
  225. pinfo->width = pinfo->spec = 0;
  226. pinfo->state = SNV_STATE_BEGIN;
  227. pinfo->prec = -1;
  228. pinfo->dollar = 0;
  229. pinfo->pad = ' ';
  230. return pinfo;
  231. }
  232. /**
  233. * printf_error: printf.h
  234. * @pinfo: pointer to the current parser state.
  235. * @file: file where error was detected.
  236. * @line: line where error was detected.
  237. * @func1: " (" if function is supplied by compiler.
  238. * @func2: function where error was detected, if supplied by compiler.
  239. * @func3: ")" if function is supplied by compiler.
  240. * @error_message: new error message to append to @pinfo.
  241. *
  242. * The contents of @error_message are appended to the @pinfo internal
  243. * error string, so it is safe to pass static strings or recycle the
  244. * original when this function returns.
  245. *
  246. * Return value:
  247. * The address of the full accumulated error message in @pinfo is
  248. * returned.
  249. **/
  250. char *
  251. printf_error (struct printf_info *pinfo, const char *file, int line, const char *func1, const char *func2, const char *func3, const char *error_message)
  252. {
  253. int i;
  254. char *result;
  255. if (pinfo->error == NULL)
  256. pinfo->error = filnew (NULL, 0);
  257. else
  258. filccat (pinfo->error, '\n');
  259. /* Cannot use printf because a bug in it might trigger another
  260. printf_error! */
  261. result = filcat (pinfo->error, "file ");
  262. filcat (pinfo->error, file);
  263. filcat (pinfo->error, ": line ");
  264. for (i = 10; i <= line; i *= 10);
  265. for (i /= 10; i >= 1; i /= 10)
  266. filccat (pinfo->error, '0' + (line / i) % 10);
  267. filcat (pinfo->error, func1);
  268. filcat (pinfo->error, func2);
  269. filcat (pinfo->error, func3);
  270. filcat (pinfo->error, ": ");
  271. filcat (pinfo->error, error_message);
  272. return result;
  273. }
  274. /**
  275. * parse_printf_format: printf.h
  276. * @format: a % delimited format string.
  277. * @n: the size of the @argtypes vector
  278. * @argtypes: a vector of ints, to be filled with the argument types from @format
  279. *
  280. * Returns information about the number and types of
  281. * arguments expected by the template string @format.
  282. * The argument @n specifies the number of elements in the array
  283. * @argtypes. This is the maximum number of elements that
  284. * the function will try to write.
  285. *
  286. * Return value:
  287. * The total number of arguments required by @format. If this
  288. * number is greater than @n, then the information returned
  289. * describes only the first @n arguments. If you want information
  290. * about additional arguments, allocate a bigger array and call
  291. * this function again. If there is an error, then %SNV_ERROR
  292. * is returned instead.
  293. **/
  294. size_t
  295. parse_printf_format (const char *format, int n, int *argtypes)
  296. {
  297. struct printf_info info;
  298. return_val_if_fail (format != NULL, -1);
  299. parser_init (&info, format, NULL);
  300. while (*info.format != EOS)
  301. {
  302. int ch = (int) *info.format++;
  303. switch (ch)
  304. {
  305. case SNV_CHAR_SPEC:
  306. if (*info.format != SNV_CHAR_SPEC)
  307. {
  308. /* We found the start of a format specifier! */
  309. spec_entry *spec;
  310. int status;
  311. int argindex;
  312. parser_reset (&info);
  313. do
  314. {
  315. /* Until we fill the stream (or get some other
  316. exception) or one of the handlers tells us
  317. we have reached the end of the specifier... */
  318. /* ...lookup the handler associated with the char
  319. we are looking at in the format string... */
  320. spec = spec_lookup (*info.format);
  321. if (spec == NULL)
  322. {
  323. PRINTF_ERROR (&info, "unregistered specifier");
  324. goto error;
  325. }
  326. if (!IS_MODIFIER (spec) &&
  327. !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
  328. {
  329. PRINTF_ERROR (&info, "invalid combination of flags");
  330. goto error;
  331. }
  332. argindex = info.dollar && !IS_MODIFIER (spec)
  333. ? info.dollar - 1 : info.argindex;
  334. /* ...and call the relevant handler. */
  335. if (spec->arg)
  336. {
  337. info.spec = *info.format;
  338. info.extra = spec->user;
  339. info.type = spec->type;
  340. status = (*spec->arg) (&info, (size_t) (n - argindex),
  341. argtypes + argindex);
  342. }
  343. else
  344. {
  345. status = 1;
  346. if (n > argindex)
  347. argtypes[argindex] = spec->type;
  348. }
  349. if (status < 0)
  350. goto error;
  351. info.argc = MAX (info.argc, argindex + status);
  352. if (!info.dollar && !IS_MODIFIER (spec))
  353. info.argindex += status;
  354. info.format++;
  355. }
  356. while (IS_MODIFIER (spec));
  357. continue;
  358. }
  359. /* An escaped CHAR_SPEC: ignore it (by falling through). */
  360. ++info.format;
  361. /*NOBREAK*/
  362. default: /* Just a character: ignore it. */
  363. continue;
  364. }
  365. error:
  366. /* Get here on error */
  367. info.argc = -1;
  368. break;
  369. }
  370. if (printf_last_error)
  371. snv_delete (printf_last_error);
  372. if (info.error)
  373. printf_last_error = fildelete (info.error);
  374. else
  375. printf_last_error = NULL;
  376. return info.argc;
  377. }
  378. int
  379. do_printfv (STREAM *stream, const char *format, union printf_arg const args[])
  380. {
  381. struct printf_info info;
  382. /* This is the parser driver.
  383. Here we scan through the format string and move bytes into the
  384. stream and call handlers based on the parser state. */
  385. parser_init (&info, format, args);
  386. /* Keep going until the format string runs out! */
  387. while (*info.format != EOS)
  388. {
  389. int ch = (int) *info.format++;
  390. switch (ch)
  391. {
  392. case SNV_CHAR_SPEC:
  393. if (*info.format != SNV_CHAR_SPEC)
  394. {
  395. /* We found the start of a format specifier! */
  396. spec_entry *spec;
  397. int status, argindex;
  398. parser_reset (&info);
  399. do
  400. {
  401. /* Until we fill the stream (or get some other
  402. exception) or one of the handlers tells us
  403. we have reached the end of the specifier... */
  404. /* ...lookup the handler associated with the char
  405. we are looking at in the format string... */
  406. spec = spec_lookup (*info.format);
  407. if (spec == NULL)
  408. {
  409. PRINTF_ERROR (&info, "unregistered specifier");
  410. goto error;
  411. }
  412. if (!IS_MODIFIER (spec) &&
  413. !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
  414. {
  415. PRINTF_ERROR (&info, "invalid combination of flags");
  416. goto error;
  417. }
  418. /* ...and call the relevant handler. */
  419. info.spec = *info.format;
  420. info.extra = spec->user;
  421. info.type = spec->type;
  422. status = spec->arg ? (*spec->arg) (&info, (size_t)0, NULL) : 1;
  423. if (status < 0)
  424. goto error;
  425. argindex = info.dollar && !IS_MODIFIER (spec)
  426. ? info.dollar - 1 : info.argindex;
  427. info.format++;
  428. info.argc = MAX (info.argc, argindex + status);
  429. if (!info.dollar && !IS_MODIFIER (spec))
  430. info.argindex += status;
  431. }
  432. while (info.count >= 0 && IS_MODIFIER (spec));
  433. status = (*spec->fmt) (stream, &info, args + argindex);
  434. if (status < 0)
  435. goto error;
  436. info.count += status;
  437. continue;
  438. }
  439. /* An escaped CHAR_SPEC: ignore it (by falling through). */
  440. ++info.format;
  441. /*NOBREAK*/
  442. default: /* Just a character: ignore it. */
  443. /* Just a character: copy it. */
  444. SNV_EMIT (ch, stream, info.count);
  445. continue;
  446. }
  447. error:
  448. /* Get here on error */
  449. info.count = -1;
  450. break;
  451. }
  452. if (printf_last_error)
  453. snv_delete (printf_last_error);
  454. if (info.error)
  455. printf_last_error = fildelete (info.error);
  456. else
  457. printf_last_error = NULL;
  458. return info.count;
  459. }
  460. /**
  461. * stream_printfv: printf.h
  462. * @stream: an initialised stream structure.
  463. * @format: a % delimited format string.
  464. * @args: a vector of argument addresses to match @format.
  465. *
  466. * Format the elements of @args according to @format, and write
  467. * the results to @stream. If @stream is %NULL, only count the
  468. * number of characters needed to output the format.
  469. *
  470. * Return value:
  471. * The number of characters written is returned, unless there is
  472. * an error, when %SNV_ERROR is returned.
  473. **/
  474. int
  475. stream_printfv (STREAM *stream, const char *format, snv_constpointer const *ap)
  476. {
  477. union printf_arg *args;
  478. struct printf_info info;
  479. int count_or_errorcode;
  480. int *argtypes = NULL;
  481. return_val_if_fail (format != NULL, SNV_ERROR);
  482. parser_init (&info, format, NULL);
  483. while (*info.format != EOS)
  484. {
  485. int ch = (int) *info.format++;
  486. switch (ch)
  487. {
  488. case SNV_CHAR_SPEC:
  489. if (*info.format != SNV_CHAR_SPEC)
  490. {
  491. /* We found the start of a format specifier! */
  492. spec_entry *spec;
  493. parser_reset (&info);
  494. do
  495. {
  496. /* Until we fill the stream (or get some other
  497. exception) or one of the handlers tells us
  498. we have reached the end of the specifier... */
  499. /* ...lookup the handler associated with the char
  500. we are looking at in the format string... */
  501. spec = spec_lookup (*info.format);
  502. if (spec == NULL)
  503. {
  504. PRINTF_ERROR (&info, "unregistered specifier");
  505. goto error;
  506. }
  507. if (!IS_MODIFIER (spec) &&
  508. !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
  509. {
  510. PRINTF_ERROR (&info, "invalid combination of flags");
  511. goto error;
  512. }
  513. /* ...and call the relevant handler. */
  514. if (call_argtype_function (&info, &argtypes, spec) < 0)
  515. goto error;
  516. info.format++;
  517. }
  518. while (info.count >= 0 && IS_MODIFIER (spec));
  519. continue;
  520. }
  521. /* An escaped CHAR_SPEC: ignore it (by falling through). */
  522. ++info.format;
  523. /*NOBREAK*/
  524. default: /* Just a character: ignore it. */
  525. continue;
  526. }
  527. error:
  528. /* Get here on error */
  529. info.argc = -1;
  530. break;
  531. }
  532. if (info.argc > 0)
  533. {
  534. int index;
  535. args = snv_new (union printf_arg, info.argc);
  536. /* We scanned the format string to find the type of the arguments,
  537. so we can now cast it and store it correctly. */
  538. for (index = 0; index < info.argc; index++)
  539. {
  540. int tp = argtypes[index];
  541. if ((tp & PA_TYPE_MASK) == PA_TYPE_MASK)
  542. {
  543. if (index + 1 == info.argc)
  544. info.argc--;
  545. else
  546. continue;
  547. }
  548. switch (tp & ~PA_FLAG_UNSIGNED)
  549. {
  550. case PA_CHAR:
  551. args[index].pa_char = (char) *(const long int *)(ap + index);
  552. break;
  553. case PA_WCHAR:
  554. args[index].pa_wchar =
  555. (snv_wchar_t) *(const long int *)(ap + index);
  556. break;
  557. case PA_INT|PA_FLAG_SHORT:
  558. args[index].pa_short_int =
  559. (short int) *(const long int *)(ap + index);
  560. break;
  561. case PA_INT:
  562. args[index].pa_int = (int) *(const long int *)(ap + index);
  563. break;
  564. case PA_INT|PA_FLAG_LONG:
  565. args[index].pa_long_int = *(const long int *)(ap + index);
  566. break;
  567. case PA_INT|PA_FLAG_LONG_LONG:
  568. args[index].pa_long_long_int = **(const intmax_t **)(ap + index);
  569. break;
  570. case PA_FLOAT:
  571. args[index].pa_float = **(const float **)(ap + index);
  572. break;
  573. case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
  574. #ifdef HAVE_LONG_DOUBLE
  575. args[index].pa_long_double = **(const long double **)(ap + index);
  576. break;
  577. #endif
  578. /* else fall through */
  579. case PA_DOUBLE:
  580. args[index].pa_double = **(const double **)(ap + index);
  581. break;
  582. /* Note that pointer types are dereferenced just once! */
  583. case PA_STRING:
  584. args[index].pa_string = *(const char **)(ap + index);
  585. break;
  586. case PA_WSTRING:
  587. args[index].pa_wstring = *(const snv_wchar_t **)(ap + index);
  588. break;
  589. case PA_POINTER:
  590. args[index].pa_pointer = *(snv_constpointer *)(ap + index);
  591. break;
  592. default:
  593. if (argtypes[index] & PA_FLAG_PTR)
  594. args[index].pa_pointer = *(snv_constpointer *)(ap + index);
  595. else
  596. args[index].pa_long_double = 0.0;
  597. break;
  598. }
  599. }
  600. }
  601. if (printf_last_error)
  602. snv_delete (printf_last_error);
  603. if (info.error)
  604. printf_last_error = fildelete (info.error);
  605. else
  606. printf_last_error = NULL;
  607. count_or_errorcode = do_printfv (stream, format, args);
  608. snv_delete (argtypes);
  609. if (info.argc > 0)
  610. snv_delete (args);
  611. return count_or_errorcode;
  612. }
  613. /**
  614. * stream_vprintf: printf.h
  615. * @stream: an initialised stream structure.
  616. * @format: a % delimited format string.
  617. * @ap: a varargs/stdargs va_list.
  618. *
  619. * Format the elements of @ap according to @format, and write
  620. * the results to @stream. If @stream is %NULL, only count the
  621. * number of characters needed to output the format.
  622. *
  623. * Return value:
  624. * The number of characters written is returned, unless there is
  625. * an error, when %SNV_ERROR is returned.
  626. **/
  627. int
  628. stream_vprintf (STREAM *stream, const char *format, va_list ap)
  629. {
  630. union printf_arg *args = NULL;
  631. struct printf_info info;
  632. int count_or_errorcode;
  633. int *argtypes = NULL;
  634. return_val_if_fail (format != NULL, SNV_ERROR);
  635. parser_init (&info, format, NULL);
  636. while (*info.format != EOS)
  637. {
  638. int ch = (int) *info.format++;
  639. switch (ch)
  640. {
  641. case SNV_CHAR_SPEC:
  642. if (*info.format != SNV_CHAR_SPEC)
  643. {
  644. /* We found the start of a format specifier! */
  645. spec_entry *spec;
  646. parser_reset (&info);
  647. do
  648. {
  649. /* Until we fill the stream (or get some other
  650. exception) or one of the handlers tells us
  651. we have reached the end of the specifier... */
  652. /* ...lookup the handler associated with the char
  653. we are looking at in the format string... */
  654. spec = spec_lookup (*info.format);
  655. if (spec == NULL)
  656. {
  657. PRINTF_ERROR (&info, "unregistered specifier");
  658. goto error;
  659. }
  660. if (!IS_MODIFIER (spec) &&
  661. !(info.state & (SNV_STATE_BEGIN | SNV_STATE_SPECIFIER)))
  662. {
  663. PRINTF_ERROR (&info, "invalid combination of flags");
  664. goto error;
  665. }
  666. /* ...and call the relevant handler. */
  667. if (call_argtype_function (&info, &argtypes, spec) < 0)
  668. goto error;
  669. info.format++;
  670. }
  671. while (info.count >= 0 && IS_MODIFIER (spec));
  672. continue;
  673. }
  674. /* An escaped CHAR_SPEC: ignore it (by falling through). */
  675. ++info.format;
  676. /*NOBREAK*/
  677. default: /* Just a character: ignore it. */
  678. continue;
  679. }
  680. error:
  681. /* Get here on error */
  682. info.argc = -1;
  683. break;
  684. }
  685. if (info.argc > 0)
  686. {
  687. int index;
  688. args = snv_new (union printf_arg, info.argc);
  689. /* Scan the format string to find the type of the argument
  690. so we can cast it and store it correctly.
  691. Note that according to the ISO C standards, standard
  692. type promotion takes place on any variadic arguments as
  693. they are aligned on the call stack, and so it is these
  694. promoted types that we must extract with the va_arg()
  695. macro, or the alignment gets all messed up.
  696. Thanks to Robert Lipe <robertlipe@usa.net> for explaining all
  697. this to me. */
  698. for (index = 0; index < info.argc; index++)
  699. switch (argtypes[index] & ~PA_FLAG_UNSIGNED)
  700. {
  701. case PA_CHAR:
  702. args[index].pa_char = va_arg (ap, int); /* Promoted. */
  703. break;
  704. case PA_WCHAR:
  705. args[index].pa_wchar = va_arg (ap, snv_wint_t); /* Promoted. */
  706. break;
  707. case PA_INT|PA_FLAG_SHORT:
  708. args[index].pa_short_int = va_arg (ap, int); /* Promoted. */
  709. break;
  710. case PA_INT:
  711. args[index].pa_int = va_arg (ap, int);
  712. break;
  713. case PA_INT|PA_FLAG_LONG:
  714. args[index].pa_long_int = va_arg (ap, long int);
  715. break;
  716. case PA_INT|PA_FLAG_LONG_LONG:
  717. args[index].pa_long_long_int = va_arg (ap, intmax_t);
  718. break;
  719. case PA_FLOAT:
  720. args[index].pa_float = va_arg (ap, double); /* Promoted. */
  721. break;
  722. case PA_DOUBLE|PA_FLAG_LONG_DOUBLE:
  723. args[index].pa_long_double = va_arg (ap, long double);
  724. break;
  725. case PA_DOUBLE:
  726. args[index].pa_double = va_arg (ap, double);
  727. break;
  728. case PA_STRING:
  729. args[index].pa_string = va_arg (ap, const char *);
  730. break;
  731. case PA_WSTRING:
  732. args[index].pa_wstring = va_arg (ap, const snv_wchar_t *);
  733. break;
  734. case PA_POINTER:
  735. args[index].pa_pointer = va_arg (ap, void *);
  736. break;
  737. default:
  738. if (argtypes[index] & PA_FLAG_PTR)
  739. args[index].pa_pointer = va_arg (ap, void *);
  740. else
  741. args[index].pa_long_double = 0.0;
  742. break;
  743. }
  744. }
  745. if (printf_last_error)
  746. snv_delete (printf_last_error);
  747. if (info.error)
  748. printf_last_error = fildelete (info.error);
  749. else
  750. printf_last_error = NULL;
  751. count_or_errorcode = do_printfv (stream, format, args);
  752. snv_delete (argtypes);
  753. snv_delete (args);
  754. return count_or_errorcode;
  755. }
  756. /**
  757. * stream_printf: printf.h
  758. * @stream: an initialised stream structure.
  759. * @format: a % delimited format string.
  760. * @va_alist: a varargs/stdargs va_list.
  761. *
  762. * Format the elements of @va_alist according to @format, and write
  763. * the results to @stream. If @stream is %NULL, only count the
  764. * number of characters needed to output the format.
  765. *
  766. * Return value:
  767. * The number of characters written is returned, unless there is
  768. * an error, when %SNV_ERROR is returned.
  769. **/
  770. int
  771. stream_printf (STREAM * stream, const char *format, ...)
  772. {
  773. int count_or_errorcode;
  774. va_list ap;
  775. va_start (ap, format);
  776. count_or_errorcode = stream_vprintf (stream, format, ap);
  777. va_end (ap);
  778. return count_or_errorcode;
  779. }
  780. /* Finally... the main API implementation: */
  781. /**
  782. * snv_fdputc: printf.h
  783. * @ch: A single character to be added to @stream.
  784. * @stream: The stream in which to write @ch.
  785. *
  786. * A StreamPut function for use in putting characters
  787. * into STREAMs holding a file descriptor.
  788. *
  789. * Return value:
  790. * The value of @ch that has been put in @stream, or -1 in case of
  791. * an error (errno will be set to indicate the type of error).
  792. **/
  793. int
  794. snv_fdputc (int ch, STREAM *stream)
  795. {
  796. static char buf[1] = { 0 };
  797. buf[0] = (char) ch;
  798. return write ((int) SNV_POINTER_TO_INT (stream_details (stream)), buf, 1)
  799. ? ch : -1;
  800. }
  801. /**
  802. * snv_dprintf: printf.h
  803. * @fd: an open file descriptor.
  804. * @format: a % delimited format string.
  805. * @va_alist: a varargs/stdargs va_list.
  806. *
  807. * Format the elements of @va_alist according to @format, and write
  808. * the results to the file descriptor @fd.
  809. *
  810. * Return value:
  811. * The number of characters written is returned, unless there is
  812. * an error, when %SNV_ERROR is returned.
  813. **/
  814. int
  815. snv_dprintf (int fd, const char *format, ...)
  816. {
  817. int count_or_errorcode;
  818. va_list ap;
  819. va_start (ap, format);
  820. count_or_errorcode = snv_vdprintf (fd, format, ap);
  821. va_end (ap);
  822. return count_or_errorcode;
  823. }
  824. /**
  825. * snv_vdprintf: printf.h
  826. * @fd: an open file descriptor.
  827. * @format: a % delimited format string.
  828. * @ap: a varargs/stdargs va_list.
  829. *
  830. * Format the elements of @ap according to @format, and write
  831. * the results to the file descriptor @fd.
  832. *
  833. * Return value:
  834. * The number of characters written is returned, unless there is
  835. * an error, when %SNV_ERROR is returned.
  836. **/
  837. int
  838. snv_vdprintf (int fd, const char *format, va_list ap)
  839. {
  840. int result;
  841. STREAM *out = stream_new (SNV_INT_TO_POINTER (fd),
  842. SNV_UNLIMITED, NULL, snv_fdputc);
  843. result = stream_vprintf (out, format, ap);
  844. stream_delete (out);
  845. return result;
  846. }
  847. /**
  848. * snv_dprintfv: printf.h
  849. * @fd: an open file descriptor.
  850. * @format: a % delimited format string.
  851. * @args: a vector of argument addresses to match @format.
  852. *
  853. * Format the elements of @args according to @format, and write
  854. * the results to file descriptor @fd.
  855. *
  856. * Return value:
  857. * The number of characters written is returned, unless there is
  858. * an error, when %SNV_ERROR is returned.
  859. **/
  860. int
  861. snv_dprintfv (int fd, const char *format, snv_constpointer const args[])
  862. {
  863. int result;
  864. STREAM *out = stream_new (SNV_INT_TO_POINTER (fd),
  865. SNV_UNLIMITED, NULL, snv_fdputc);
  866. result = stream_printfv (out, format, args);
  867. stream_delete (out);
  868. return result;
  869. }
  870. /**
  871. * snv_fileputc: printf.h
  872. * @ch: A single character to be added to @stream.
  873. * @stream: The stream in which to write @ch.
  874. *
  875. * A StreamPut function for use in putting characters
  876. * into STREAMs holding a FILE*.
  877. *
  878. * Return value:
  879. * The value of @ch that has been put in @stream.
  880. **/
  881. int
  882. snv_fileputc (int ch, STREAM *stream)
  883. {
  884. FILE *fp = (FILE *) stream_details (stream);
  885. return putc (ch, fp);
  886. }
  887. static int
  888. snv_fileputc_unlocked (int ch, STREAM *stream)
  889. {
  890. FILE *fp = (FILE *) stream_details (stream);
  891. return SNV_PUTC_UNLOCKED (ch, fp);
  892. }
  893. /**
  894. * snv_printf: printf.h
  895. * @format: a % delimited format string.
  896. * @va_alist: a varargs/stdargs va_list.
  897. *
  898. * Format the elements of @va_alist according to @format, and write
  899. * the results to the standard output stream.
  900. *
  901. * Return value:
  902. * The number of characters written is returned, unless there is
  903. * an error, when %SNV_ERROR is returned.
  904. **/
  905. int
  906. snv_printf (const char *format, ...)
  907. {
  908. int count_or_errorcode;
  909. va_list ap;
  910. va_start (ap, format);
  911. count_or_errorcode = snv_vprintf (format, ap);
  912. va_end (ap);
  913. return count_or_errorcode;
  914. }
  915. /**
  916. * snv_vprintf: printf.h
  917. * @format: a % delimited format string.
  918. * @ap: a varargs/stdargs va_list.
  919. *
  920. * Format the elements of @ap according to @format, and write
  921. * the results to the standard output stream.
  922. *
  923. * Return value:
  924. * The number of characters written is returned, unless there is
  925. * an error, when %SNV_ERROR is returned.
  926. **/
  927. int
  928. snv_vprintf (const char *format, va_list ap)
  929. {
  930. int result;
  931. STREAM *out = stream_new (stdout, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
  932. int tmp;
  933. SNV_WITH_LOCKED_FP (stdout, tmp)
  934. result = stream_vprintf (out, format, ap);
  935. stream_delete (out);
  936. return result;
  937. }
  938. /**
  939. * snv_printfv: printf.h
  940. * @format: a % delimited format string.
  941. * @args: a vector of argument addresses to match @format.
  942. *
  943. * Format the elements of @args according to the string @format,
  944. * and write the result to the standard output stream.
  945. *
  946. * Return value:
  947. * The number of characters written is returned, unless there is
  948. * an error, when %SNV_ERROR is returned.
  949. **/
  950. int
  951. snv_printfv (const char *format, snv_constpointer const args[])
  952. {
  953. int result;
  954. STREAM *out = stream_new (stdout, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
  955. int tmp;
  956. SNV_WITH_LOCKED_FP (stdout, tmp)
  957. result = stream_printfv (out, format, args);
  958. stream_delete (out);
  959. return result;
  960. }
  961. /**
  962. * snv_fprintf: printf.h
  963. * @file: a stdio.h FILE* stream.
  964. * @format: a % delimited format string.
  965. * @va_alist: a varargs/stdargs va_list.
  966. *
  967. * Format the elements of @va_alist according to @format, and write
  968. * the results to the @file stream.
  969. *
  970. * Return value:
  971. * The number of characters written is returned, unless there is
  972. * an error, when %SNV_ERROR is returned.
  973. **/
  974. int
  975. snv_fprintf (FILE * file, const char *format, ...)
  976. {
  977. int count_or_errorcode;
  978. va_list ap;
  979. va_start (ap, format);
  980. count_or_errorcode = snv_vfprintf (file, format, ap);
  981. va_end (ap);
  982. return count_or_errorcode;
  983. }
  984. /**
  985. * snv_vfprintf: printf.h
  986. * @file: a stdio.h FILE* stream.
  987. * @format: a % delimited format string.
  988. * @ap: a varargs/stdargs va_list.
  989. *
  990. * Format the elements of @ap according to @format, and write
  991. * the results to the @file stream.
  992. *
  993. * Return value:
  994. * The number of characters written is returned, unless there is
  995. * an error, when %SNV_ERROR is returned.
  996. **/
  997. int
  998. snv_vfprintf (FILE *file, const char *format, va_list ap)
  999. {
  1000. int result;
  1001. STREAM *out = stream_new (file, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
  1002. int tmp;
  1003. SNV_WITH_LOCKED_FP (file, tmp)
  1004. result = stream_vprintf (out, format, ap);
  1005. stream_delete (out);
  1006. return result;
  1007. }
  1008. /**
  1009. * snv_fprintfv: printf.h
  1010. * @file: a stdio.h FILE* stream.
  1011. * @format: a % delimited format string.
  1012. * @args: a vector of argument addresses to match @format.
  1013. *
  1014. * Format the elements of @args according to @format, and write
  1015. * the results to @file.
  1016. *
  1017. * Return value:
  1018. * The number of characters written is returned, unless there is
  1019. * an error, when %SNV_ERROR is returned.
  1020. **/
  1021. int
  1022. snv_fprintfv (FILE *file, const char *format, snv_constpointer const args[])
  1023. {
  1024. int result;
  1025. STREAM *out = stream_new (file, SNV_UNLIMITED, NULL, snv_fileputc_unlocked);
  1026. int tmp;
  1027. SNV_WITH_LOCKED_FP (file, tmp)
  1028. result = stream_printfv (out, format, args);
  1029. stream_delete (out);
  1030. return result;
  1031. }
  1032. /**
  1033. * snv_bufputc: printf.h
  1034. * @ch: A single character to be added to @stream.
  1035. * @stream: The stream in which to write @ch.
  1036. *
  1037. * A StreamPut function for use in putting characters
  1038. * into STREAMs holding a char buffer.
  1039. *
  1040. * Return value:
  1041. * The value of @ch that has been put in @stream.
  1042. **/
  1043. int
  1044. snv_bufputc (ch, stream)
  1045. int ch;
  1046. STREAM *stream;
  1047. {
  1048. char **ppbuffer = (char **) stream_details (stream);
  1049. **ppbuffer = (char) ch;
  1050. (*ppbuffer)++;
  1051. return ch;
  1052. }
  1053. /**
  1054. * snv_sprintf: printf.h
  1055. * @buffer: a preallocated char* buffer.
  1056. * @format: a % delimited format string.
  1057. * @va_alist: a varargs/stdargs va_list.
  1058. *
  1059. * Format the elements of @va_alist according to @format, and write
  1060. * the results to the string @buffer.
  1061. *
  1062. * Return value:
  1063. * The number of characters written is returned, unless there is
  1064. * an error, when %SNV_ERROR is returned.
  1065. **/
  1066. int
  1067. snv_sprintf (char buffer[], const char *format, ...)
  1068. {
  1069. int count_or_errorcode;
  1070. va_list ap;
  1071. va_start (ap, format);
  1072. count_or_errorcode = snv_vsprintf (buffer, format, ap);
  1073. va_end (ap);
  1074. return count_or_errorcode;
  1075. }
  1076. /**
  1077. * snv_vsprintf: printf.h
  1078. * @buffer: a preallocated char* buffer.
  1079. * @format: a % delimited format string.
  1080. * @ap: a varargs/stdargs va_list.
  1081. *
  1082. * Format the elements of @ap according to @format, and write
  1083. * the results to the string @buffer.
  1084. *
  1085. * Return value:
  1086. * The number of characters written is returned, unless there is
  1087. * an error, when %SNV_ERROR is returned.
  1088. **/
  1089. int
  1090. snv_vsprintf (char buffer[], const char *format, va_list ap)
  1091. {
  1092. int count_or_errorcode;
  1093. STREAM *out = stream_new (&buffer, SNV_UNLIMITED, NULL, snv_bufputc);
  1094. count_or_errorcode = stream_vprintf (out, format, ap);
  1095. /* Terminate with an EOS without incrementing the counter. */
  1096. stream_put (EOS, out);
  1097. stream_delete (out);
  1098. return count_or_errorcode;
  1099. }
  1100. /**
  1101. * snv_sprintfv: printf.h
  1102. * @buffer: a preallocated char* buffer.
  1103. * @format: a % delimited format string.
  1104. * @args: a vector of argument addresses to match @format.
  1105. *
  1106. * Format the elements of @args according to @format, and write
  1107. * the results to the string @buffer.
  1108. *
  1109. * Return value:
  1110. * The number of characters written is returned, unless there is
  1111. * an error, when %SNV_ERROR is returned.
  1112. **/
  1113. int
  1114. snv_sprintfv (char buffer[], const char *format, snv_constpointer const args[])
  1115. {
  1116. int count_or_errorcode;
  1117. STREAM *out = stream_new (&buffer, SNV_UNLIMITED, NULL, snv_bufputc);
  1118. count_or_errorcode = stream_printfv (out, format, args);
  1119. /* Terminate with an EOS without incrementing the counter. */
  1120. stream_put (EOS, out);
  1121. stream_delete (out);
  1122. return count_or_errorcode;
  1123. }
  1124. /**
  1125. * snv_snprintf: printf.h
  1126. * @buffer: a preallocated char* buffer.
  1127. * @limit: the maximum number of characters to write into @buffer.
  1128. * @format: a % delimited format string.
  1129. * @va_alist: a varargs/stdargs va_list.
  1130. *
  1131. * Format the elements of @va_alist according to @format, and write
  1132. * the results to the string @buffer, truncating the formatted string
  1133. * if it reaches @limit characters in length.
  1134. *
  1135. * Return value:
  1136. * The number of characters written is returned, unless there is
  1137. * an error, when %SNV_ERROR is returned.
  1138. **/
  1139. int
  1140. snv_snprintf (char buffer[], unsigned long limit, const char *format, ...)
  1141. {
  1142. int count_or_errorcode;
  1143. va_list ap;
  1144. va_start (ap, format);
  1145. count_or_errorcode = snv_vsnprintf (buffer, limit, format, ap);
  1146. va_end (ap);
  1147. return count_or_errorcode;
  1148. }
  1149. /**
  1150. * snv_vsnprintf: printf.h
  1151. * @buffer: a preallocated char* buffer.
  1152. * @limit: the maximum number of characters to write into @buffer.
  1153. * @format: a % delimited format string.
  1154. * @ap: a varargs/stdargs va_list.
  1155. *
  1156. * Format the elements of @ap according to @format, and write
  1157. * the results to the string @buffer, truncating the formatted string
  1158. * if it reaches @limit characters in length.
  1159. *
  1160. * Return value:
  1161. * The number of characters written is returned, unless there is
  1162. * an error, when %SNV_ERROR is returned.
  1163. **/
  1164. int
  1165. snv_vsnprintf (char buffer[], unsigned long limit, const char *format, va_list ap)
  1166. {
  1167. int count_or_errorcode;
  1168. STREAM *out = stream_new (&buffer, limit - 1, NULL, snv_bufputc);
  1169. count_or_errorcode = stream_vprintf (out, format, ap);
  1170. *buffer = EOS;
  1171. stream_delete (out);
  1172. return count_or_errorcode;
  1173. }
  1174. /**
  1175. * snv_snprintfv: printf.h
  1176. * @buffer: a preallocated char* buffer.
  1177. * @limit: the maximum number of characters to write into @buffer.
  1178. * @format: a % delimited format string.
  1179. * @args: a vector of argument addresses to match @format.
  1180. *
  1181. * Format the elements of @args according to @format, and write
  1182. * the results to the string @buffer, truncating the formatted string
  1183. * if it reaches @limit characters in length.
  1184. *
  1185. * Return value:
  1186. * The number of characters written is returned, unless there is
  1187. * an error, when %SNV_ERROR is returned.
  1188. **/
  1189. int
  1190. snv_snprintfv (char buffer[], unsigned long limit, const char *format, snv_constpointer const args[])
  1191. {
  1192. int count_or_errorcode;
  1193. STREAM *out = stream_new (&buffer, limit - 1, NULL, snv_bufputc);
  1194. count_or_errorcode = stream_printfv (out, format, args);
  1195. *buffer = EOS;
  1196. stream_delete (out);
  1197. return count_or_errorcode;
  1198. }
  1199. /**
  1200. * snv_filputc: printf.h
  1201. * @ch: A single character to be added to @stream.
  1202. * @stream: The stream in which to write @ch.
  1203. *
  1204. * A StreamPut function for use in putting characters
  1205. * into STREAMs holding a Filament*.
  1206. *
  1207. * Return value:
  1208. * The value of @ch that has been put in @stream.
  1209. **/
  1210. int
  1211. snv_filputc (ch, stream)
  1212. int ch;
  1213. STREAM *stream;
  1214. {
  1215. return filccat ((Filament *) stream_details (stream), ch), ch;
  1216. }
  1217. /**
  1218. * snv_asprintf: printf.h
  1219. * @result: the address of a char * variable.
  1220. * @format: a % delimited format string.
  1221. * @va_alist: a varargs/stdargs va_list.
  1222. *
  1223. * Format the elements of @va_alist according to @format, and write
  1224. * the results to an internally allocated buffer whose address is
  1225. * stored in @result (and should be freed by the caller) unless
  1226. * there is an error.
  1227. *
  1228. * Yes, this interface is cumbersome and totally useless. It would
  1229. * have been better to simply return the allocated address, but
  1230. * it turns out that somebody wasn't thinking much when adding
  1231. * asprintf to libiberty a few years ago.
  1232. *
  1233. * Return value:
  1234. * The number of characters written is returned, unless there is
  1235. * an error, when %SNV_ERROR is returned.
  1236. **/
  1237. int
  1238. snv_asprintf (char **result, const char *format, ...)
  1239. {
  1240. int count;
  1241. va_list ap;
  1242. va_start (ap, format);
  1243. count = snv_vasprintf (result, format, ap);
  1244. va_end (ap);
  1245. return count;
  1246. }
  1247. /**
  1248. * snv_vasprintf: printf.h
  1249. * @result: the address of a char * variable.
  1250. * @format: a % delimited format string.
  1251. * @ap: a varargs/stdargs va_list.
  1252. *
  1253. * Format the elements of @ap according to @format, and write
  1254. * the results to an internally allocated buffer whose address is
  1255. * stored in @result (and should be freed by the caller) unless
  1256. * there is an error.
  1257. *
  1258. * Above moaning for asprintf applies here too.
  1259. *
  1260. * Return value:
  1261. * The number of characters written is returned, unless there is
  1262. * an error, when %SNV_ERROR is returned.
  1263. **/
  1264. int
  1265. snv_vasprintf (char **result, const char *format, va_list ap)
  1266. {
  1267. int count_or_errorcode;
  1268. char *base;
  1269. Filament *fil = filnew (NULL, 0);
  1270. STREAM *out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc);
  1271. count_or_errorcode = stream_vprintf (out, format, ap);
  1272. base = fildelete (fil);
  1273. stream_delete (out);
  1274. *result = (count_or_errorcode < 0) ? NULL : base;
  1275. return count_or_errorcode;
  1276. }
  1277. /**
  1278. * snv_asprintfv: printf.h
  1279. * @result: the address of a char * variable.
  1280. * @format: a % delimited format string.
  1281. * @args: a vector of argument addresses to match @format.
  1282. *
  1283. * Format the elements of @args according to @format, and write
  1284. * the results to an internally allocated buffer whose address is
  1285. * stored in @result (and should be freed by the caller) unless
  1286. * there is an error.
  1287. *
  1288. * Above moaning for asprintf applies here too.
  1289. *
  1290. * Return value:
  1291. * The number of characters written is returned, unless there is
  1292. * an error, when %SNV_ERROR is returned.
  1293. **/
  1294. int
  1295. snv_asprintfv (char **result, const char *format, snv_constpointer const args[])
  1296. {
  1297. int count_or_errorcode;
  1298. char *base;
  1299. Filament *fil = filnew (NULL, 0);
  1300. STREAM *out = stream_new (fil, SNV_UNLIMITED, NULL, snv_filputc);
  1301. count_or_errorcode = stream_printfv (out, format, args);
  1302. base = fildelete (fil);
  1303. stream_delete (out);
  1304. *result = (count_or_errorcode < 0) ? NULL : base;
  1305. return count_or_errorcode;
  1306. }
  1307. /* snprintfv.c ends here */