1 /*************************************************************************
2 *
3 * $Id: trio.c,v 1.1.1.1 2000/11/13 02:42:50 holsta Exp $
4 *
5 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 *************************************************************************
17 *
18 * 1999/07/23 - breese
19 *
20 * Fixed the internal representation of numbers from signed to
21 * unsigned. Signed numbers posed a problem for large unsigned
22 * numbers (reported by Tero)
23 *
24 * Fixed a tiny bug in trio_vsprintfcat
25 *
26 * 1999/05/16 - breese
27 *
28 * Added size_t support (just waiting for a C9X compliant compiler
29 * to add ptrdiff_t and intmax_t)
30 *
31 * Rewrote TrioOutStreamDouble so it does not use the libc sprintf
32 * to emulate floating-point anylonger.
33 *
34 * Fixed width, precision, and adjustment for numbers and doubles.
35 *
36 * 1999/05/06 - breese
37 *
38 * Fixed zero padding for %d. Now %d will only zero pad if explicitly
39 * requested to do so with the 0 flag.
40 *
41 * Fixed an incorrect while() condition in TrioGetString
42 * (both errors were reported by Tero.)
43 *
44 * 1999/04/19 - breese
45 *
46 * Fixed incorrect zero padding of pointers
47 *
48 * 1999/03/25 - Daniel & breese
49 *
50 * Made it compile under cygwin
51 *
52 * Fixed a bug were TrioPreprocess would return an error if no
53 * formatting chars were found (reported by Tero.)
54 *
55 * 1999/03/19 - breese
56 *
57 * Added trio_strerror and TRIO_ERROR_NAME.
58 *
59 * Changed the error codes to be positive (as errno)
60 *
61 * Fixed two reads of uninitialized memory reported by Purify
62 *
63 * Added binary specifiers 'b' and 'B' (like SCO.) ThousandSeparator
64 * can be used to separate nibbles (4 bit)
65 *
66 * Renamed all Internal* functions to Trio*, which seems like a
67 * better namespace (even though it is of no practical interest
68 * because these functions are not visible beyond the scope of
69 * this file.)
70 *
71 * 1999/03/11 - breese
72 *
73 * Double references and gaps in the arguments are not allowed (for
74 * the %n$ format) and in both cases an error code is returned.
75 *
76 * 1999/03/08 - breese
77 *
78 * Added InStream and OutStream to the trio_T structure.
79 *
80 * Started work on TrioScan.
81 *
82 * Return values for errors changed. Two macros to unpack the error
83 * code has been added to the header.
84 *
85 * Shortshort (hh) flag added.
86 *
87 * %#s also quotes the quote-char now.
88 *
89 * Removed the 'errorInFormat' boolean, which isn't used anymore
90 * after the functions bail out with an error instead.
91 *
92 * 1999/03/04 - Daniel
93 *
94 * More than MAX_PARAMETERS parametes will now cause the
95 * TrioPreprocess() function to return error.
96 *
97 * Unknown flags and/or specifiers cause errors too.
98 *
99 * 1999/03/01 - Daniel
100 *
101 * Added trio_snprintfcat and trio_vsnprintfcat and the defined
102 * name StrFormatAppendMax. They append a formatted string to the end
103 * of a string.
104 *
105 * Define MAX_PARAMETERS to 128 at all times instead of using NL_ARGMAX
106 * when that exists.
107 *
108 * 1999/02/24 - Daniel
109 *
110 * Added platform fixes for Amiga as suggested by Tero J�nk� <tesaja@utu.fi>
111 *
112 * 1999/01/31 - Daniel
113 *
114 * vaprintf did add a zero byte even when it had failed.
115 *
116 * 1999/01/31 - breese
117 *
118 * Cleaned up the code for locale handling and thousand separator
119 *
120 * 1999/01/28 - Daniel Stenberg
121 *
122 * Added trio_aprintf() and trio_vaprintf(). They return an allocated
123 * string.
124 *
125 * 1999/01/21 - breese
126 *
127 * Added thousands separator for numbers
128 *
129 * 1999/01/09 - breese
130 *
131 * Added floating point support for *printf
132 *
133 * 1998/10/01 - breese
134 *
135 * Rewrote the implementation of *printf and *scanf and put all
136 * the code in this file. Extended qualifiers and qualifiers from other
137 * standards were added.
138 *
139 ************************************************************************/
140
141 /*
142 * FIXME:
143 * scan
144 * complex numbers? (C9X _Complex)
145 * boolean values? (C9X _Bool)
146 * widechar
147 * j, z, t are quantifiers, not specifiers!!
148 * dprintf [GNU] works as fprintf except it uses a file descriptor
149 * instead of a FILE pointer
150 * trio_printf("%u\n", UINT_MAX) gives a different result than
151 * the system printf() (I am not sure which is most correct)
152 */
153
154 static const char rcsid[] = "@(#)$Id: trio.c,v 1.1.1.1 2000/11/13 02:42:50 holsta Exp $";
155
156 #if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
157 # define TRIO_C9X
158 #endif
159
160 #undef TRIO_C9X /* Not fully done yet */
161 #define TRIO_BSD
162 #define TRIO_GNU
163 #define TRIO_SUN
164 #define TRIO_UNIX98
165 #define TRIO_EXTENSION
166
167 /* Use __STDC_ISO_10646__ to determine if widechars are used */
168
169
170 #if defined(unix) || defined(__xlC__) /* AIX xlC workaround */
171 # define PLATFORM_UNIX
172 #elif defined(AMIGA) && defined(__GNUC__)
173 # define PLATFORM_UNIX
174 #endif
175
176 #include "trio.h"
177 #include "strio.h"
178 #include <ctype.h>
179 #include <math.h>
180 #include <limits.h>
181 #include <float.h>
182 #include <stdarg.h>
183 #include <errno.h>
184 #if defined(TRIO_C9X)
185 # include <stdint.h>
186 #endif
187 #if defined(PLATFORM_UNIX)
188 # include <locale.h>
189 # define USE_LOCALE
190 #endif
191 #ifndef DEBUG
192 # define NDEBUG
193 #endif
194 #include <assert.h>
195
196 #ifndef NULL
197 # define NULL 0
198 #endif
199 #define NIL ((char)0)
200 #ifndef FALSE
201 # define FALSE (1 == 0)
202 # define TRUE (! FALSE)
203 #endif
204
205 /* mincore() can be used for debugging purposes */
206 #define VALID(x) (NULL != (x))
207
208
209 /*************************************************************************
210 * Internal definitions
211 */
212
213 /* Pack the error code and the position. This is unpacked
214 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
215 */
216 #define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
217
218 #if defined(STANDALONE)
219 # undef printf
220 #endif
221
222 #if !defined(USE_LONGLONG)
223 # if defined(__GNUC__) && !defined(__STRICT_ANSI__)
224 # define USE_LONGLONG
225 # elif defined(__SUNPRO_C)
226 # define USE_LONGLONG
227 # endif
228 #endif
229
230 #if defined(USE_LONGLONG)
231 # define LONGLONG long long
232 # define ULONGLONG unsigned long long
233 # define LONGDOUBLE long double
234 #else
235 # define LONGLONG long
236 # define ULONGLONG unsigned long
237 # define LONGDOUBLE double
238 #endif
239
240 #if defined(TRIO_C9X)
241 # define LONGEST uintmax_t
242 # define SLONGEST intmax_t
243 #else
244 # define LONGEST ULONGLONG
245 # define SLONGEST LONGLONG
246 #endif
247
248 /*
249 * The maximal number of digits are for base 2.
250 */
251 #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT + 1)
252
253 enum {
254 TYPE_PRINT = 1,
255 TYPE_SCAN = 2,
256
257 FLAGS_NEW = 0,
258 FLAGS_PARAMETER = 1,
259 FLAGS_SPACE = 2 * FLAGS_PARAMETER,
260 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
261 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
262 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
263 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
264 FLAGS_LONG = 2 * FLAGS_SHORT,
265 FLAGS_QUAD = 2 * FLAGS_LONG,
266 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
267 FLAGS_NILPADDING = 2 * FLAGS_LONGDOUBLE,
268 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
269 FLAGS_OCTAL = 2 * FLAGS_UNSIGNED,
270 FLAGS_HEX = 2 * FLAGS_OCTAL,
271 FLAGS_UPPER = 2 * FLAGS_HEX,
272 FLAGS_WIDTH = 2 * FLAGS_UPPER,
273 FLAGS_PRECISION = 2 * FLAGS_WIDTH,
274 FLAGS_FLOAT_E = 2 * FLAGS_PRECISION,
275 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
276 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
277 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
278 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
279 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
280 FLAGS_SHORTSHORT = 2 * FLAGS_IGNORE,
281 FLAGS_BINARY = 2 * FLAGS_SHORTSHORT,
282 FLAGS_SIZE_T = 2 * FLAGS_BINARY,
283 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
284 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
285
286 NO_POSITION = -1,
287 NO_PRECISION = 0,
288
289 NO_BASE = 0,
290 MAX_BASE = 36,
291 BASE_BINARY = 2,
292 BASE_OCTAL = 8,
293 BASE_DECIMAL = 10,
294 BASE_HEX = 16,
295 };
296
297 #define MAX_PARAMETERS 64
298
299 #define FORMAT_UNKNOWN 0
300 #define FORMAT_INT 1
301 #define FORMAT_DOUBLE 2
302 #define FORMAT_CHAR 3
303 #define FORMAT_STRING 4
304 #define FORMAT_POINTER 5
305 #define FORMAT_COUNT 6
306 #define FORMAT_WIDTH 7
307 #define FORMAT_GROUP 8
308 #if defined(TRIO_GNU)
309 # define FORMAT_ERRNO 10
310 #endif
311
312 #define CHAR_IDENTIFIER '%'
313 #define CHAR_BACKSLASH '\\'
314
315 /* Specifiers */
316
317 /*
318 * a Hex-float
319 * A Hex-float
320 * c Character
321 * C Widechar character (wint_t)
322 * d Decimal
323 * e float
324 * E -
325 * f -
326 * F -
327 * g -
328 * G -
329 * i Integer
330 * j intmax_t
331 * m Error message
332 * n Count
333 * o Octal
334 * p Pointer
335 * s String
336 * S Widechar string (wchar_t)
337 * t prtdiff_t
338 * u Unsigned
339 * x Hex
340 * X Hex
341 * z size_t
342 * [ Group
343 */
344 #define SPECIFIER_CHAR 'c'
345 #define SPECIFIER_STRING 's'
346 #define SPECIFIER_DECIMAL 'd'
347 #define SPECIFIER_INTEGER 'i'
348 #define SPECIFIER_UNSIGNED 'u'
349 #define SPECIFIER_OCTAL 'o'
350 #define SPECIFIER_HEX 'x'
351 #define SPECIFIER_HEX_UPPER 'X'
352 #define SPECIFIER_FLOAT_E 'e'
353 #define SPECIFIER_FLOAT_E_UPPER 'E'
354 #define SPECIFIER_FLOAT_F 'f'
355 #define SPECIFIER_FLOAT_F_UPPER 'F'
356 #define SPECIFIER_FLOAT_G 'g'
357 #define SPECIFIER_FLOAT_G_UPPER 'G'
358 #define SPECIFIER_POINTER 'p'
359 #define SPECIFIER_GROUP '['
360 #define SPECIFIER_COUNT 'n'
361 #if defined(TRIO_UNIX98)
362 # define SPECIFIER_CHAR_UPPER 'C'
363 # define SPECIFIER_STRING_UPPER 'S'
364 #endif
365 #if defined(TRIO_C9X)
366 # define SPECIFIER_HEXFLOAT 'a'
367 # define SPECIFIER_HEXFLOAT_UPPER 'A'
368 #endif
369 #if defined(TRIO_GNU)
370 # define SPECIFIER_ERRNO 'm'
371 #endif
372 #if defined(TRIO_EXTENSION)
373 # define SPECIFIER_BINARY 'b'
374 # define SPECIFIER_BINARY_UPPER 'B'
375 #endif
376
377 /* Qualifiers */
378
379 /*
380 * Numbers = d,i,o,u,x,X
381 * Float = a,A,e,E,f,F,g,G
382 * String = s
383 * Char = c
384 *
385 *
386 * 9$ Position
387 * Use the 9th parameter. 9 can be any number between 1 and
388 * the maximal argument
389 *
390 * 9 Width
391 * Set width to 9. 9 can be any number, but must not be postfixed
392 * by '$'
393 *
394 * h Short
395 * Numbers:
396 * (unsigned) short int
397 *
398 * hh Short short
399 * Numbers:
400 * (unsigned) char
401 *
402 * l Long
403 * Numbers:
404 * (unsigned) long int
405 * String:
406 * as the S specifier
407 * Char:
408 * as the C specifier
409 *
410 * ll Long Long
411 * Numbers:
412 * (unsigned) long long int
413 *
414 * L Long Double
415 * Float
416 * long double
417 *
418 * # Alternative
419 * Float:
420 * Decimal-point is always present
421 * String:
422 * non-printable characters are handled as \number
423 *
424 * Spacing
425 *
426 * + Sign
427 *
428 * - Alignment
429 *
430 * . Precision
431 *
432 * * Parameter
433 * print: use parameter
434 * scan: no paramter (ignore)
435 *
436 * q Quad
437 *
438 * Z size_t
439 *
440 * w Widechar
441 *
442 * ' Thousands/quote
443 * Numbers:
444 * Integer part grouped in thousands
445 * Binary numbers:
446 * Number grouped in nibbles (4 bits)
447 * String:
448 * Quoted string
449 *
450 * Extensions:
451 * <alloc> = GNU 'a' qualifier
452 * <base=n> = sets base to 'n' (int)
453 * <fill=c> = fill with 'c' (char)
454 * <quote> = quote string
455 * <quote=c> = quote string with 'c' (char)
456 */
457 #define QUALIFIER_POSITION '$'
458 #define QUALIFIER_SHORT 'h'
459 #define QUALIFIER_LONG 'l'
460 #define QUALIFIER_LONG_UPPER 'L'
461 #define QUALIFIER_ALTERNATIVE '#'
462 #define QUALIFIER_SPACE ' '
463 #define QUALIFIER_PLUS '+'
464 #define QUALIFIER_MINUS '-'
465 #define QUALIFIER_DOT '.'
466 #define QUALIFIER_STAR '*'
467 #if defined(TRIO_C9X)
468 # define QUALIFIER_SIZE_T 'z'
469 # define QUALIFIER_PTRDIFF_T 't'
470 # define QUALIFIER_INTMAX_T 'j'
471 #endif
472 #if defined(TRIO_BSD) || defined(TRIO_GNU)
473 # define QUALIFIER_QUAD 'q'
474 #endif
475 #if defined(TRIO_GNU)
476 # define QUALIFIER_SIZE_T_UPPER 'Z'
477 #endif
478 #if defined(TRIO_SUN)
479 # define QUALIFIER_WIDECHAR 'w'
480 #endif
481 #if defined(TRIO_EXTENSION)
482 # define QUALIFIER_QUOTE '\''
483 # define QUALIFIER_EXTENSIONBEGIN '<'
484 # define QUALIFIER_EXTENSIONEND '>'
485 # define QUALIFIER_EXTENSIONSEPARATOR ','
486 # define QUALIFIER_EXTENSIONVALUE '='
487 #endif
488
489 typedef struct {
490 int type;
491 int flags;
492 int width;
493 size_t precision;
494 int base;
495 char quote;
496 char adjust;
497 int indexAfterSpecifier;
498 union {
499 char *string;
500 void *pointer;
501 union {
502 SLONGEST asSigned;
503 LONGEST asUnsigned;
504 } num;
505 LONGEST *numPointer;
506 double doubleNumber;
507 double *doublePointer;
508 LONGDOUBLE longdoubleNumber;
509 LONGDOUBLE *longdoublePointer;
510 int errorNumber;
511 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
512 size_t sizet;
513 #endif
514 #if defined(QUALIFIER_PTRDIFF_T)
515 ptrdiff_t ptrdifft
516 #endif
517 #if defined(QUALIFIER_INTMAX_T)
518 intmax_t intmaxt;
519 #endif
520 } data;
521 } parameter_T;
522
523 typedef struct _trio_T {
524 size_t amount;
525 size_t done;
526 size_t max;
527 void *location;
528 int (*OutStream)(struct _trio_T *, int);
529 int (*InStream)(struct _trio_T *, int *);
530 int current;
531 } trio_T;
532
533
534 /*************************************************************************
535 * Package scope variables
536 */
537
538 #if defined(PLATFORM_UNIX)
539 extern int errno;
540 #endif
541
542 static char globalDecimalPoint[64] = ".";
543 static char globalThousandSeparator[64] = ",";
544
545 static const char digitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
546 static const char digitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
547
548 static const char null[] = "(nil)";
549
550 static const char extensionFill[] = "fill";
551 static const size_t extensionFillSize = sizeof(extensionFill) - 1;
552 static const char extensionAlloc[] = "alloc";
553 static const size_t extensionAllocSize = sizeof(extensionAlloc) - 1;
554 static const char extensionBase[] = "base";
555 static const size_t extensionBaseSize = sizeof(extensionBase) - 1;
556 static const char extensionQuote[] = "quote";
557 static const size_t extensionQuoteSize = sizeof(extensionQuote) - 1;
558
559
560 /*************************************************************************
561 * TrioIsQualifier [private]
562 *
563 * Description:
564 * Remember to add all new qualifiers (except QUALIFIER_POSITION) to
565 * this function.
566 */
567 static int
TrioIsQualifier(char ch)568 TrioIsQualifier(char ch)
569 {
570 /* QUALIFIER_POSITION is not included */
571 switch (ch)
572 {
573 case '0': case '1': case '2': case '3': case '4':
574 case '5': case '6': case '7': case '8': case '9':
575 case QUALIFIER_PLUS:
576 case QUALIFIER_MINUS:
577 case QUALIFIER_SPACE:
578 case QUALIFIER_DOT:
579 case QUALIFIER_STAR:
580 case QUALIFIER_ALTERNATIVE:
581 case QUALIFIER_QUOTE:
582 case QUALIFIER_SHORT:
583 case QUALIFIER_LONG:
584 case QUALIFIER_LONG_UPPER:
585 #if defined(QUALIFIER_SIZE_T)
586 case QUALIFIER_SIZE_T:
587 #endif
588 #if defined(QUALIFIER_PTRDIFF_T)
589 case QUALIFIER_PTRDIFF_T:
590 #endif
591 #if defined(QUALIFIER_INTMAX_T)
592 case QUALIFIER_INTMAX_T:
593 #endif
594 #if defined(QUALIFIER_QUAD)
595 case QUALIFIER_QUAD:
596 #endif
597 #if defined(QUALIFIER_SIZE_T_UPPER)
598 case QUALIFIER_SIZE_T_UPPER:
599 #endif
600 #if defined(QUALIFIER_WIDECHAR)
601 case QUALIFIER_WIDECHAR:
602 #endif
603 #if defined(QUALIFIER_EXTENSIONBEGIN)
604 case QUALIFIER_EXTENSIONBEGIN:
605 #endif
606 return TRUE;
607 default:
608 return FALSE;
609 }
610 }
611
612 /*************************************************************************
613 * TrioGetPosition [private]
614 *
615 * Get the %n$ position.
616 */
617 static int
TrioGetPosition(char * format,int * indexPointer)618 TrioGetPosition(char *format, int *indexPointer)
619 {
620 int number = 0;
621 int index = *indexPointer;
622
623 while (isdigit((int)format[index]))
624 {
625 number *= 10;
626 number += (int)(format[index] - '0');
627 index++;
628 }
629 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
630 {
631 *indexPointer = index;
632 return number;
633 }
634 return NO_POSITION;
635 }
636
637 /*************************************************************************
638 *
639 */
640 #if defined(STANDALONE)
641 static void
TrioDumpParameter(parameter_T elem)642 TrioDumpParameter(parameter_T elem)
643 {
644 switch (elem.type)
645 {
646 case FORMAT_STRING:
647 printf("type = string\n");
648 break;
649 case FORMAT_POINTER:
650 printf("type = pointer\n");
651 break;
652 case FORMAT_CHAR:
653 printf("type = char\n");
654 break;
655 case FORMAT_INT:
656 printf("type = int\n");
657 break;
658 case FORMAT_COUNT:
659 printf("type = count\n");
660 break;
661 case FORMAT_DOUBLE:
662 printf("type = double\n");
663 break;
664 case FORMAT_WIDTH:
665 printf("type = width\n");
666 break;
667 #if defined(FORMAT_ERRNO)
668 case FORMAT_ERRNO:
669 printf("type = errno\n");
670 break;
671 #endif
672 default:
673 printf("type = %d\n", elem.type);
674 break;
675 }
676 printf("flags = 0x%08x =", elem.flags);
677 if (elem.flags == FLAGS_NEW)
678 printf(" none");
679 else
680 {
681 if (elem.flags & FLAGS_PARAMETER)
682 printf(" parameter");
683 if (elem.flags & FLAGS_SPACE)
684 printf(" space");
685 if (elem.flags & FLAGS_SHOWSIGN)
686 printf(" showsign");
687 if (elem.flags & FLAGS_LEFTADJUST)
688 printf(" leftadjust");
689 if (elem.flags & FLAGS_ALTERNATIVE)
690 printf(" alternative");
691 if (elem.flags & FLAGS_SHORT)
692 printf(" short");
693 if (elem.flags & FLAGS_SHORTSHORT)
694 printf(" shortshort");
695 if (elem.flags & FLAGS_LONG)
696 printf(" long");
697 if (elem.flags & FLAGS_QUAD)
698 printf(" quad");
699 if (elem.flags & FLAGS_LONGDOUBLE)
700 printf(" longdouble");
701 if (elem.flags & FLAGS_NILPADDING)
702 printf(" nilpadding");
703 if (elem.flags & FLAGS_UNSIGNED)
704 printf(" unsigned");
705 if (elem.flags & FLAGS_OCTAL)
706 printf(" octal");
707 if (elem.flags & FLAGS_HEX)
708 printf(" hex");
709 if (elem.flags & FLAGS_UPPER)
710 printf(" upper");
711 if (elem.flags & FLAGS_WIDTH)
712 printf(" width");
713 if (elem.flags & FLAGS_PRECISION)
714 printf(" precision");
715 if (elem.flags & FLAGS_FLOAT_E)
716 printf(" float_e");
717 if (elem.flags & FLAGS_FLOAT_G)
718 printf(" float_g");
719 if (elem.flags & FLAGS_QUOTE)
720 printf(" quote");
721 if (elem.flags & FLAGS_WIDECHAR)
722 printf(" widechar");
723 if (elem.flags & FLAGS_BINARY)
724 printf(" binary");
725 }
726 printf("\n");
727 if (elem.flags & FLAGS_QUOTE)
728 printf("quote = %c\n", elem.quote);
729 }
730 #endif
731
732 /*************************************************************************
733 * TrioPreprocess [private]
734 *
735 * Description:
736 * Parse the format string
737 */
738 static int
TrioPreprocess(int type,char * format,parameter_T * parameters,va_list arglist)739 TrioPreprocess(int type,
740 char *format,
741 parameter_T *parameters,
742 va_list arglist)
743 {
744 int flags;
745 int parameterPosition = 0;
746 int currentParam;
747 int maxParam = -1;
748 int insideExtension;
749 int width;
750 int precision;
751 char adjust;
752 char quote;
753 char ch;
754 int i = -1;
755 int base;
756 int index;
757 int work;
758 char *tmpformat;
759 unsigned short usedEntries[MAX_PARAMETERS];
760
761 /*
762 * 'parameters' is not initialized, but we need to know
763 * which entries we used.
764 */
765 memset(usedEntries, 0, sizeof(usedEntries));
766
767 index = 0;
768 while (format[index])
769 {
770 if (CHAR_IDENTIFIER == format[index++])
771 {
772 if (CHAR_IDENTIFIER == format[index])
773 {
774 index++;
775 continue; /* while */
776 }
777
778 flags = FLAGS_NEW;
779 insideExtension = FALSE;
780 currentParam = TrioGetPosition(format, &index);
781 if (NO_POSITION == currentParam)
782 {
783 /* We have got no positional, get the next counter */
784 currentParam = parameterPosition;
785 }
786 else
787 {
788 /*
789 * 'currentParam' is decreased by 1, because N$ starts
790 * from 1, whereas the array it is indexing starts from 0.
791 */
792 currentParam--;
793 }
794 if(currentParam >= MAX_PARAMETERS)
795 {
796 /* bail out completely to make the error more obvious */
797 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
798 }
799
800 if (currentParam > maxParam)
801 maxParam = currentParam;
802
803 parameterPosition++;
804
805 /* Default values */
806 width = 0;
807 precision = 0;
808 base = NO_BASE;
809 adjust = NIL;
810 quote = '\"';
811
812 while (TrioIsQualifier(format[index])
813 || insideExtension)
814 {
815 ch = format[index++];
816
817 #if defined(TRIO_EXTENSION)
818 if (insideExtension)
819 {
820 if (QUALIFIER_EXTENSIONSEPARATOR == ch)
821 {
822 ch = QUALIFIER_EXTENSIONBEGIN;
823 }
824 else
825 {
826 insideExtension = FALSE;
827 }
828 }
829 if (QUALIFIER_EXTENSIONBEGIN == ch)
830 {
831 /* Parse extended format */
832 insideExtension = TRUE;
833 work = index;
834
835 switch (format[work])
836 {
837 case 'a':
838 if (StrEqualMax(extensionAlloc, extensionAllocSize,
839 &format[work]))
840 {
841 flags |= FLAGS_ALLOC;
842 work += extensionAllocSize;
843 }
844 break;
845
846 case 'b':
847 if (StrEqualMax(extensionBase, extensionBaseSize,
848 &format[work]))
849 {
850 work += extensionBaseSize;
851 if (QUALIFIER_EXTENSIONVALUE == format[work])
852 {
853 work++;
854 base = StrToLong(&format[work], &tmpformat, 10);
855 work += (int)(tmpformat - &format[work]);
856 if (base > MAX_BASE)
857 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
858 }
859 }
860 break;
861
862 case 'f':
863 if (StrEqualMax(extensionFill, extensionFillSize,
864 &format[work]))
865 {
866 work += extensionFillSize;
867 if (QUALIFIER_EXTENSIONVALUE == format[work])
868 {
869 work++;
870 adjust = format[work++];
871 }
872 }
873
874 case 'q':
875 if (StrEqualMax(extensionQuote, extensionQuoteSize,
876 &format[work]))
877 {
878 flags |= FLAGS_QUOTE;
879 work += extensionQuoteSize;
880 if (QUALIFIER_EXTENSIONVALUE == format[work])
881 {
882 work++;
883 quote = format[work++];
884 }
885 }
886 break;
887
888 default:
889 break;
890 }
891
892 if (QUALIFIER_EXTENSIONEND == work[format])
893 {
894 insideExtension = FALSE;
895 index = ++work;
896 }
897 }
898 #endif /* defined(TRIO_EXTENSION) */
899
900 switch (ch)
901 {
902 #if defined(TRIO_EXTENSION)
903 case QUALIFIER_EXTENSIONBEGIN:
904 case QUALIFIER_EXTENSIONSEPARATOR:
905 /* Everything is fine, but ignore */
906 break;
907 #endif
908 case QUALIFIER_SPACE:
909 flags |= FLAGS_SPACE;
910 break;
911
912 case QUALIFIER_PLUS:
913 flags |= FLAGS_SHOWSIGN;
914 break;
915
916 case QUALIFIER_MINUS:
917 flags |= FLAGS_LEFTADJUST;
918 flags &= ~FLAGS_NILPADDING;
919 adjust = ' ';
920 break;
921
922 case QUALIFIER_ALTERNATIVE:
923 flags |= FLAGS_ALTERNATIVE;
924 break;
925
926 case QUALIFIER_QUOTE:
927 flags |= FLAGS_QUOTE;
928 break;
929
930 case QUALIFIER_DOT:
931 flags |= FLAGS_PRECISION;
932 if (QUALIFIER_STAR == format[index])
933 {
934 flags |= FLAGS_PARAMETER;
935 index++;
936 precision = TrioGetPosition(format, &index);
937 if (NO_POSITION == precision)
938 precision = currentParam;
939 else
940 precision--;
941
942 currentParam = precision + 1;
943 if (currentParam > maxParam)
944 maxParam = currentParam;
945 parameterPosition++;
946 }
947 else
948 {
949 precision = StrToLong(&format[index], &tmpformat, 10);
950 index = (int)(tmpformat - format);
951 }
952 break; /* QUALIFIER_DOT */
953
954 case QUALIFIER_STAR:
955 /* This has different meanings for print and scan */
956 if (TYPE_PRINT == type)
957 {
958 flags |= (FLAGS_WIDTH | FLAGS_PARAMETER);
959
960 width = TrioGetPosition(format, &index);
961 if (NO_POSITION == width)
962 width = currentParam;
963 else
964 width--;
965
966 currentParam = width + 1;
967 if (currentParam > maxParam)
968 maxParam = currentParam;
969 parameterPosition++;
970 }
971 else
972 {
973 flags |= FLAGS_IGNORE;
974 }
975
976 break; /* QUALIFIER_STAR */
977
978 case '0':
979 if (! (flags & FLAGS_LEFTADJUST))
980 flags |= FLAGS_NILPADDING;
981 /* FALLTHROUGH */
982 case '1': case '2': case '3': case '4':
983 case '5': case '6': case '7': case '8': case '9':
984 flags |= FLAGS_WIDTH;
985 /* &format[index - 1] is used to "rewind" the read
986 * character from format
987 */
988 width = StrToLong(&format[index - 1], &tmpformat, 10);
989 index = (int)(tmpformat - format);
990 break;
991
992 case QUALIFIER_SHORT:
993 if (flags & FLAGS_SHORT)
994 flags |= FLAGS_SHORTSHORT;
995 else
996 flags |= FLAGS_SHORT;
997 break;
998
999 case QUALIFIER_LONG:
1000 if (flags & FLAGS_LONG)
1001 flags |= FLAGS_QUAD;
1002 else
1003 flags |= FLAGS_LONG;
1004 break;
1005
1006 case QUALIFIER_LONG_UPPER:
1007 flags |= FLAGS_LONGDOUBLE;
1008 break;
1009
1010 #if defined(QUALIFIER_SIZE_T)
1011 case QUALIFIER_SIZE_T:
1012 break;
1013 #endif
1014
1015 #if defined(QUALIFIER_PTRDIFF_T)
1016 case QUALIFIER_PTRDIFF_T:
1017 break;
1018 #endif
1019
1020 #if defined(QUALIFIER_INTMAX_T)
1021 case QUALIFIER_INTMAX_T:
1022 break;
1023 #endif
1024
1025 #if defined(QUALIFIER_QUAD)
1026 case QUALIFIER_QUAD:
1027 flags |= FLAGS_QUAD;
1028 break;
1029 #endif
1030
1031 #if defined(QUALIFIER_WIDECHAR)
1032 case QUALIFIER_WIDECHAR:
1033 flags |= FLAGS_WIDECHAR;
1034 break;
1035 #endif
1036
1037 #if defined(QUALIFIER_SIZE_T_UPPER)
1038 case QUALIFIER_SIZE_T_UPPER:
1039 break;
1040 #endif
1041
1042 default:
1043 /* bail out completely to make the error more obvious */
1044 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1045 }
1046 } /* while qualifier */
1047
1048 switch (format[index++])
1049 {
1050 #if defined(SPECIFIER_CHAR_UPPER)
1051 case SPECIFIER_CHAR_UPPER:
1052 flags |= FLAGS_LONG;
1053 /* FALLTHROUGH */
1054 #endif
1055 case SPECIFIER_CHAR:
1056 parameters[currentParam].type = FORMAT_CHAR;
1057 break;
1058
1059 #if defined(SPECIFIER_STRING_UPPER)
1060 case SPECIFIER_STRING_UPPER:
1061 flags |= FLAGS_LONG;
1062 /* FALLTHROUGH */
1063 #endif
1064 case SPECIFIER_STRING:
1065 parameters[currentParam].type = FORMAT_STRING;
1066 break;
1067
1068 case SPECIFIER_GROUP:
1069 if (TYPE_SCAN == type)
1070 {
1071 parameters[currentParam].type = FORMAT_GROUP;
1072 /* The rest must be read here */
1073 }
1074 break;
1075
1076 case SPECIFIER_DECIMAL:
1077 case SPECIFIER_INTEGER:
1078 parameters[currentParam].type = FORMAT_INT;
1079 break;
1080
1081 case SPECIFIER_UNSIGNED:
1082 flags |= FLAGS_UNSIGNED;
1083 parameters[currentParam].type = FORMAT_INT;
1084 break;
1085
1086 case SPECIFIER_OCTAL:
1087 flags |= FLAGS_OCTAL;
1088 parameters[currentParam].type = FORMAT_INT;
1089 break;
1090
1091 case SPECIFIER_BINARY_UPPER:
1092 flags |= FLAGS_UPPER;
1093 /* FALLTHROUGH */
1094 case SPECIFIER_BINARY:
1095 flags |= FLAGS_BINARY | FLAGS_NILPADDING;
1096 parameters[currentParam].type = FORMAT_INT;
1097 break;
1098
1099 case SPECIFIER_HEX_UPPER:
1100 flags |= FLAGS_UPPER;
1101 /* FALLTHROUGH */
1102 case SPECIFIER_HEX:
1103 flags |= FLAGS_HEX;
1104 parameters[currentParam].type = FORMAT_INT;
1105 break;
1106
1107 case SPECIFIER_FLOAT_E_UPPER:
1108 flags |= FLAGS_UPPER;
1109 /* FALLTHROUGH */
1110 case SPECIFIER_FLOAT_E:
1111 flags |= FLAGS_FLOAT_E;
1112 parameters[currentParam].type = FORMAT_DOUBLE;
1113 break;
1114
1115 case SPECIFIER_FLOAT_G_UPPER:
1116 flags |= FLAGS_UPPER;
1117 /* FALLTHROUGH */
1118 case SPECIFIER_FLOAT_G:
1119 flags |= FLAGS_FLOAT_G;
1120 parameters[currentParam].type = FORMAT_DOUBLE;
1121 break;
1122
1123 case SPECIFIER_FLOAT_F_UPPER:
1124 flags |= FLAGS_UPPER;
1125 /* FALLTHROUGH */
1126 case SPECIFIER_FLOAT_F:
1127 parameters[currentParam].type = FORMAT_DOUBLE;
1128 break;
1129
1130 case SPECIFIER_POINTER:
1131 parameters[currentParam].type = FORMAT_POINTER;
1132 break;
1133
1134 case SPECIFIER_COUNT:
1135 parameters[currentParam].type = FORMAT_COUNT;
1136 break;
1137
1138 #if defined(SPECIFIER_HEXFLOAT)
1139 # if defined(SPECIFIER_HEXFLOAT_UPPER)
1140 case SPECIFIER_HEXFLOAT_UPPER:
1141 flags |= FLAGS_UPPER;
1142 /* FALLTHROUGH */
1143 # endif
1144 case SPECIFIER_HEXFLOAT:
1145 flags |= FLAGS_HEX;
1146 parameters[currentParam].type = FORMAT_DOUBLE;
1147 break;
1148 #endif
1149
1150 #if defined(FORMAT_ERRNO)
1151 case SPECIFIER_ERRNO:
1152 parameters[currentParam].type = FORMAT_ERRNO;
1153 break;
1154 #endif
1155
1156 default:
1157 /* bail out completely to make the error more obvious */
1158 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1159 }
1160
1161 /* Count the number of times this entry has been used */
1162 usedEntries[currentParam] += 1;
1163
1164 parameters[currentParam].indexAfterSpecifier = index;
1165 parameters[currentParam].flags = flags;
1166 parameters[currentParam].width = width;
1167 parameters[currentParam].base = base;
1168 parameters[currentParam].quote = quote;
1169 parameters[currentParam].adjust = adjust;
1170
1171 if (flags & FLAGS_PARAMETER)
1172 {
1173 if (flags & FLAGS_WIDTH)
1174 i = width;
1175 else if (flags & FLAGS_PRECISION)
1176 i = precision;
1177 else
1178 i = MAX_PARAMETERS; /* Indicate error */
1179
1180 if (MAX_PARAMETERS != i)
1181 {
1182 usedEntries[i] += 1;
1183
1184 parameters[currentParam].width = i;
1185 parameters[i].type = FORMAT_WIDTH;
1186 parameters[i].indexAfterSpecifier = index;
1187 parameters[i].flags = flags;
1188 parameters[i].precision = parameters[i].width = 0;
1189 parameters[i].adjust = NIL;
1190 parameters[i].quote = NIL;
1191 }
1192 }
1193 else
1194 {
1195 parameters[currentParam].width = width;
1196 parameters[currentParam].precision = precision;
1197 }
1198
1199 } /* if identifier */
1200 } /* while format characters left */
1201
1202 for (i = 0; i <= maxParam; i++)
1203 {
1204 if (usedEntries[i] != 1)
1205 {
1206 if (usedEntries[i] == 0) /* gap detected */
1207 return TRIO_ERROR_RETURN(TRIO_EGAP, 0);
1208 else /* double references detected */
1209 return TRIO_ERROR_RETURN(TRIO_EDBLREF, 0);
1210 }
1211 #if defined(STANDALONE)
1212 TrioDumpParameter(parameters[i]);
1213 #endif
1214 if (parameters[i].flags & FLAGS_IGNORE)
1215 continue; /* for all arguments */
1216
1217 /* The stack arguments are read according to ANSI C89
1218 * default argument promotions:
1219 *
1220 * char = int
1221 * short = int
1222 * unsigned char = unsigned int
1223 * unsigned short = unsigned int
1224 * float = double
1225 * FIXME: remember to use unsigned
1226 *
1227 * In addition to the ANSI C89 these types are read (the
1228 * default argument promotions of C9X has not been
1229 * considered yet)
1230 *
1231 * long long
1232 * long double
1233 * size_t
1234 * ptrdiff_t
1235 * intmax_t
1236 */
1237 switch (parameters[i].type)
1238 {
1239 case FORMAT_GROUP:
1240 case FORMAT_STRING:
1241 parameters[i].data.string = va_arg(arglist, char *);
1242 break;
1243
1244 case FORMAT_POINTER:
1245 case FORMAT_COUNT:
1246 case FORMAT_UNKNOWN:
1247 parameters[i].data.pointer = va_arg(arglist, void *);
1248 break;
1249
1250 case FORMAT_CHAR:
1251 case FORMAT_INT:
1252 if (TYPE_SCAN == type)
1253 {
1254 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1255 if (parameters[i].flags & FLAGS_SIZE_T)
1256 parameters[i].data.sizet = va_arg(arglist, size_t);
1257 else
1258 #endif
1259 parameters[i].data.numPointer = (LONGEST *)va_arg(arglist, void *);
1260 #if 0
1261 if (parameters[i].flags & FLAGS_QUAD)
1262 parameters[i].data.numPointer = (LONGEST *)va_arg(arglist, ULONGLONG *);
1263 else if (parameters[i].flags & FLAGS_LONG)
1264 parameters[i].data.numPointer = (LONGEST *)va_arg(arglist, long *);
1265 else
1266 parameters[i].data.numPointer = (LONGEST *)va_arg(arglist, int *);
1267 #endif
1268 }
1269 else
1270 {
1271 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1272 if (parameters[i].flags & FLAGS_SIZE_T)
1273 parameters[i].data.sizet = va_arg(arglist, size_t);
1274 else
1275 #endif
1276 if (parameters[i].flags & FLAGS_QUAD)
1277 parameters[i].data.num.asUnsigned = (LONGEST)va_arg(arglist, ULONGLONG);
1278 else if (parameters[i].flags & FLAGS_LONG)
1279 parameters[i].data.num.asUnsigned = (LONGEST)va_arg(arglist, long);
1280 else
1281 parameters[i].data.num.asUnsigned = (LONGEST)va_arg(arglist, int);
1282 }
1283 break;
1284
1285 case FORMAT_WIDTH:
1286 /* parameters[i].type = FORMAT_INT; */
1287 parameters[i].data.num.asUnsigned = (LONGEST)va_arg(arglist, int);
1288 break;
1289
1290 case FORMAT_DOUBLE:
1291 if (TYPE_SCAN == type)
1292 {
1293 if (parameters[i].flags & FLAGS_LONG)
1294 parameters[i].data.longdoublePointer = va_arg(arglist, LONGDOUBLE *);
1295 else
1296 parameters[i].data.doublePointer = va_arg(arglist, double *);
1297 }
1298 else
1299 {
1300 if (parameters[i].flags & FLAGS_LONG)
1301 parameters[i].data.longdoubleNumber = va_arg(arglist, LONGDOUBLE);
1302 else
1303 parameters[i].data.longdoubleNumber = (LONGDOUBLE)va_arg(arglist, double);
1304 }
1305 break;
1306
1307
1308 #if defined(FORMAT_ERRNO)
1309 case FORMAT_ERRNO:
1310 parameters[i].data.errorNumber = errno;
1311 break;
1312 #endif
1313
1314 default:
1315 break;
1316 }
1317 } /* for all specifiers */
1318 return i;
1319 }
1320
1321 /*************************************************************************
1322 * TrioOutStreamNumber [private]
1323 *
1324 * Description:
1325 * Output a number.
1326 * The complexity of this function is a result of the complexity
1327 * of the dependencies of the flags.
1328 *
1329 * FIXME:
1330 * buffer: what if StrLength(globalThousandSeparator) is zero?
1331 */
1332 static void
TrioOutStreamNumber(trio_T * self,LONGEST number,int flags,int width,int precision,int base)1333 TrioOutStreamNumber(trio_T *self,
1334 LONGEST number,
1335 int flags,
1336 int width,
1337 int precision,
1338 int base)
1339 {
1340 int isNegative;
1341 char buffer[MAX_CHARS_IN(LONGEST) * StrLength(globalThousandSeparator)];
1342 char *bufferend = &buffer[sizeof(buffer) - 1];
1343 char *pointer;
1344 const char *digits;
1345 int i;
1346 int length;
1347 char *p;
1348 int charsPerThousand;
1349
1350 assert(VALID(self));
1351 assert(VALID(self->OutStream));
1352 assert(base > NO_BASE && base <= MAX_BASE);
1353
1354 digits = (flags & FLAGS_UPPER) ? digitsUpper : digitsLower;
1355
1356 /* Binary and hexadecimal numbers are grouped in fours */
1357 charsPerThousand = ((base == BASE_BINARY) || (base == BASE_HEX))
1358 ? 4 : 3;
1359
1360 if (flags & FLAGS_UNSIGNED)
1361 isNegative = FALSE;
1362 else if (isNegative = (((SLONGEST)number) < 0))
1363 number = -number;
1364
1365 if (flags & FLAGS_QUAD)
1366 number &= (ULONGLONG)-1;
1367 else if (flags & FLAGS_LONG)
1368 number &= (unsigned long)-1;
1369 else
1370 number &= (unsigned int)-1;
1371
1372 /* Build number */
1373 pointer = bufferend;
1374 *pointer-- = NIL;
1375 i = 0;
1376 do
1377 {
1378 i++;
1379 *pointer-- = digits[number % base];
1380 number /= base;
1381 if ((number) && (flags & FLAGS_QUOTE) && (i % charsPerThousand == 0))
1382 {
1383 /*
1384 * We are building the number from the least significant
1385 * to the most significant digit, so we have to copy the
1386 * thousand separator backwards
1387 */
1388 length = StrLength(globalThousandSeparator);
1389 if (((int)(pointer - buffer) - length) > 0)
1390 {
1391 p = &globalThousandSeparator[length - 1];
1392 while (length-- > 0)
1393 *pointer-- = *p--;
1394 }
1395 }
1396 }
1397 while (number);
1398
1399 /* Adjust width */
1400 width -= (bufferend - pointer) - 1;
1401
1402 /* Adjust precision */
1403 if (NO_PRECISION != precision)
1404 {
1405 precision -= (bufferend - pointer) - 1;
1406 if ((flags & FLAGS_ALTERNATIVE) || (precision > width))
1407 flags |= FLAGS_NILPADDING;
1408 }
1409
1410 /* Adjust width further */
1411 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
1412 width--;
1413 if (flags & FLAGS_ALTERNATIVE)
1414 {
1415 switch (base)
1416 {
1417 case BASE_BINARY:
1418 case BASE_HEX:
1419 width -= 2;
1420 break;
1421 case BASE_OCTAL:
1422 width--;
1423 break;
1424 default:
1425 break;
1426 }
1427 }
1428
1429 /* Output prefixes spaces if needed */
1430 if (! ((flags & FLAGS_LEFTADJUST) ||
1431 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
1432 {
1433 while (width-- > precision)
1434 self->OutStream(self, ' ');
1435 }
1436
1437 /* width has been adjusted for signs and alternatives */
1438 if (isNegative)
1439 self->OutStream(self, '-');
1440 else if (flags & FLAGS_SHOWSIGN)
1441 self->OutStream(self, '+');
1442 else if (flags & FLAGS_SPACE)
1443 self->OutStream(self, ' ');
1444
1445 if (flags & FLAGS_ALTERNATIVE)
1446 {
1447 switch (base)
1448 {
1449 case BASE_BINARY:
1450 self->OutStream(self, '0');
1451 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
1452 break;
1453
1454 case BASE_OCTAL:
1455 self->OutStream(self, '0');
1456 break;
1457
1458 case BASE_HEX:
1459 self->OutStream(self, '0');
1460 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
1461 break;
1462
1463 default:
1464 break;
1465 } /* switch base */
1466 }
1467
1468 /* Output prefixed zero padding if needed */
1469 if (flags & FLAGS_NILPADDING)
1470 {
1471 if (precision == NO_PRECISION)
1472 precision = width;
1473 while (precision-- > 0)
1474 {
1475 self->OutStream(self, '0');
1476 width--;
1477 }
1478 }
1479
1480 /* Output the number itself */
1481 while (*(++pointer))
1482 {
1483 self->OutStream(self, *pointer);
1484 }
1485
1486 /* Output trailing spaces if needed */
1487 if (flags & FLAGS_LEFTADJUST)
1488 {
1489 while (width-- > 0)
1490 self->OutStream(self, ' ');
1491 }
1492 }
1493
1494 /*************************************************************************
1495 * TrioOutStreamDouble [private]
1496 *
1497 * FIXME:
1498 * INF & NAN
1499 */
1500 static void
TrioOutStreamDouble(trio_T * self,LONGDOUBLE longdoubleNumber,int flags,int width,int precision)1501 TrioOutStreamDouble(trio_T *self,
1502 LONGDOUBLE longdoubleNumber,
1503 int flags,
1504 int width,
1505 int precision)
1506 {
1507 int i;
1508 int charsPerThousand;
1509 int length;
1510 double number = (double)longdoubleNumber;
1511 double integerPart;
1512 double fractionPart;
1513 double precisionPower;
1514 int exponent;
1515 unsigned int uExponent;
1516 int base;
1517 double dblBase;
1518 int isNegative;
1519 int isExponentNegative;
1520 int doFraction;
1521 const char *digits;
1522 char *p;
1523 char integerBuffer[MAX_CHARS_IN(double)];
1524 char *integerBufferEnd = &integerBuffer[sizeof(integerBuffer) - 1];
1525 char *integerPointer;
1526 char fractionBuffer[MAX_CHARS_IN(double)];
1527 char *fractionBufferEnd = &fractionBuffer[sizeof(fractionBuffer) - 1];
1528 char *fractionPointer;
1529 char exponentBuffer[MAX_CHARS_IN(double)];
1530 char *exponentBufferEnd = &exponentBuffer[sizeof(exponentBuffer) - 1];
1531 char *exponentPointer;
1532
1533 assert(VALID(self));
1534 assert(VALID(self->OutStream));
1535
1536 digits = (flags & FLAGS_UPPER) ? digitsUpper : digitsLower;
1537 base = (flags & FLAGS_HEX) ? BASE_HEX : BASE_DECIMAL;
1538 dblBase = (double)base;
1539 charsPerThousand = (base == BASE_HEX) ? 4 : 3;
1540
1541 if (precision == NO_PRECISION)
1542 precision = FLT_DIG;
1543 precisionPower = pow(10.0, (double)precision);
1544
1545 if (flags & (FLAGS_FLOAT_G | FLAGS_HEX))
1546 {
1547 if ((number < 1.0e-4) ||
1548 (number > precisionPower))
1549 flags |= FLAGS_FLOAT_E;
1550 }
1551
1552 if (flags & FLAGS_FLOAT_E)
1553 {
1554 /* Scale the number */
1555 exponent = (int)floor(log10(number));
1556 number /= pow(10.0, (double)exponent);
1557 isExponentNegative = (exponent < 0);
1558 uExponent = (isExponentNegative) ? -exponent : exponent;
1559 /* No thousand separators */
1560 flags &= ~FLAGS_QUOTE;
1561 }
1562
1563 /* Calculate the integer and fraction parts */
1564 fractionPart = modf(number, &integerPart);
1565 fractionPart *= precisionPower;
1566 if (fractionPart - floor(fractionPart) >= 0.5)
1567 fractionPart += 1.0;
1568 fractionPart = floor(fractionPart);
1569
1570 isNegative = (integerPart < 0.0);
1571 if (isNegative)
1572 integerPart = -integerPart;
1573
1574 /*
1575 * LONGLONG cannot hold an arbitrarily sized double integer
1576 * part, so we cannot reuse TrioOutStreamNumber here. Instead
1577 * we build the integer part manually.
1578 */
1579 integerPointer = integerBufferEnd;
1580 *integerPointer-- = NIL;
1581 i = 0;
1582 do {
1583 i++;
1584 *integerPointer-- = digits[(int)fmod(integerPart, dblBase)];
1585 integerPart /= dblBase;
1586 (void)modf(integerPart, &integerPart);
1587 if ( !(flags & FLAGS_FLOAT_E) &&
1588 (integerPart > DBL_EPSILON) &&
1589 (flags & FLAGS_QUOTE) &&
1590 (i % charsPerThousand == 0))
1591 {
1592 /* See comment for TrioOutStreamNumber */
1593 length = StrLength(globalThousandSeparator);
1594 if (((int)(integerPointer - integerBuffer) - length) > 0)
1595 {
1596 p = &globalThousandSeparator[length - 1];
1597 while (length-- > 0)
1598 *integerPointer-- = *p--;
1599 }
1600 }
1601 } while (integerPart > DBL_EPSILON);
1602
1603 width -= (integerBufferEnd - integerPointer) - 1;
1604
1605 fractionPointer = fractionBufferEnd;
1606 *fractionPointer-- = NIL;
1607 while (fractionPart > DBL_EPSILON)
1608 {
1609 *fractionPointer-- = digits[(int)fmod(fractionPart, dblBase)];
1610 fractionPart /= dblBase;
1611 (void)modf(fractionPart, &fractionPart);
1612 }
1613
1614 width -= (fractionBufferEnd - fractionPointer) - 1;
1615 doFraction = ((fractionBufferEnd - fractionPointer) > 1);
1616 if (doFraction || (flags & FLAGS_ALTERNATIVE))
1617 width -= StrLength(globalDecimalPoint);
1618
1619 if (flags & FLAGS_FLOAT_E)
1620 {
1621 exponentPointer = exponentBufferEnd;
1622 *exponentPointer-- = NIL;
1623 do {
1624 *exponentPointer-- = digits[uExponent % base];
1625 uExponent /= base;
1626 } while (uExponent);
1627
1628 /* +2 are the exponent char (e, p) and sign */
1629 width -= (exponentBufferEnd - exponentPointer) - 1 + 2;
1630 }
1631
1632 if (isNegative)
1633 self->OutStream(self, '-');
1634 else if (flags & FLAGS_SHOWSIGN)
1635 self->OutStream(self, '+');
1636 if (flags & FLAGS_HEX)
1637 {
1638 self->OutStream(self, '0');
1639 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
1640 width -= 2;
1641 }
1642
1643 /* Output prefixed spaces or zero padding */
1644 if ((flags & FLAGS_NILPADDING) || !(flags & FLAGS_LEFTADJUST))
1645 {
1646 while (width-- > 0)
1647 self->OutStream(self, (flags & FLAGS_NILPADDING) ? '0' : ' ');
1648 }
1649
1650 /* Output the integer part */
1651 while (*(++integerPointer))
1652 self->OutStream(self, *integerPointer);
1653
1654 /* Output the fraction part */
1655 if (doFraction || (flags & FLAGS_ALTERNATIVE))
1656 {
1657 char *decimalpoint = globalDecimalPoint;
1658 while (*decimalpoint)
1659 self->OutStream(self, *decimalpoint++);
1660
1661 if (doFraction)
1662 {
1663 /* zero padding? */
1664 while (*(++fractionPointer))
1665 self->OutStream(self, *fractionPointer);
1666 }
1667 }
1668
1669 /* Output the exponent */
1670 if (flags & FLAGS_FLOAT_E)
1671 {
1672 self->OutStream(self,
1673 (flags & FLAGS_HEX)
1674 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
1675 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
1676 self->OutStream(self, (isExponentNegative) ? '-' : '+');
1677 while (*(++exponentPointer))
1678 self->OutStream(self, *exponentPointer);
1679 }
1680
1681 /* Output trailing spaces if needed */
1682 if (flags & FLAGS_LEFTADJUST)
1683 {
1684 while (width-- > 0)
1685 self->OutStream(self, ' ');
1686 }
1687 }
1688
1689 /*************************************************************************
1690 * TrioOutStreamString [private]
1691 *
1692 * Description:
1693 * Output a string
1694 */
1695 static void
TrioOutStreamString(trio_T * self,char * string,int flags,int width,int precision,int quote,int adjust)1696 TrioOutStreamString(trio_T *self,
1697 char *string,
1698 int flags,
1699 int width,
1700 int precision,
1701 int quote,
1702 int adjust)
1703 {
1704 int length;
1705 int ch;
1706
1707 assert(VALID(self));
1708 assert(VALID(self->OutStream));
1709
1710 if (string == NULL)
1711 {
1712 string = (char *)null;
1713 length = sizeof(null) - 1;
1714 /* Disable quoting for the null pointer */
1715 flags &= (~FLAGS_QUOTE);
1716 width = 0;
1717 }
1718 else
1719 {
1720 length = StrLength(string);
1721 }
1722 if ((NO_PRECISION != precision) &&
1723 (precision < length))
1724 {
1725 length = precision;
1726 }
1727 width -= length;
1728
1729 if (flags & FLAGS_QUOTE)
1730 self->OutStream(self, quote);
1731
1732 if (! (flags & FLAGS_LEFTADJUST))
1733 {
1734 while (width-- > 0)
1735 self->OutStream(self, adjust);
1736 }
1737
1738 while (length-- > 0)
1739 {
1740 ch = *string++;
1741 if (flags & FLAGS_ALTERNATIVE)
1742 {
1743 if (! (isprint(ch) || isspace(ch)))
1744 {
1745 /* Non-printable characters are converted to \number */
1746 self->OutStream(self, CHAR_BACKSLASH);
1747 TrioOutStreamNumber(self, (ULONGLONG)ch,
1748 FLAGS_UNSIGNED | FLAGS_NILPADDING,
1749 3, 3, BASE_OCTAL);
1750 }
1751 else if (ch == CHAR_BACKSLASH)
1752 {
1753 self->OutStream(self, CHAR_BACKSLASH);
1754 self->OutStream(self, CHAR_BACKSLASH);
1755 }
1756 else
1757 {
1758 self->OutStream(self, ch);
1759 }
1760 }
1761 else
1762 {
1763 self->OutStream(self, ch);
1764 }
1765 }
1766
1767 if (flags & FLAGS_LEFTADJUST)
1768 {
1769 while (width-- > 0)
1770 self->OutStream(self, adjust);
1771 }
1772 if (flags & FLAGS_QUOTE)
1773 self->OutStream(self, quote);
1774 }
1775
1776 /*************************************************************************
1777 * TrioFilePutChar [private]
1778 */
1779 static int
TrioFilePutChar(trio_T * self,int output)1780 TrioFilePutChar(trio_T *self, int output)
1781 {
1782 FILE *fd = (FILE *)self->location;
1783
1784 assert(VALID(self));
1785 assert(VALID(fd));
1786
1787 self->amount++;
1788 self->done++;
1789 return fputc(output, fd);
1790 }
1791
1792 /*************************************************************************
1793 * TrioStoreBuffer [private]
1794 */
1795 static int
TrioStoreBuffer(trio_T * self,int output)1796 TrioStoreBuffer(trio_T *self, int output)
1797 {
1798 char **buffer = (char **)self->location;
1799
1800 assert(VALID(self));
1801 assert(VALID(buffer));
1802
1803 **buffer = (char)output;
1804 (*buffer)++;
1805 self->amount++;
1806 self->done++;
1807 return output; /* act like fputc() ! */
1808 }
1809
1810 /*************************************************************************
1811 * TrioStoreBufferMax [private]
1812 */
1813 static int
TrioStoreBufferMax(trio_T * self,int output)1814 TrioStoreBufferMax(trio_T *self, int output)
1815 {
1816 char **buffer;
1817
1818 assert(VALID(self));
1819 buffer = (char **)self->location;
1820 assert(VALID(buffer));
1821
1822 if (self->amount < self->max)
1823 {
1824 **buffer = (char)output;
1825 (*buffer)++;
1826 self->done++;
1827 }
1828 self->amount++;
1829 return output;
1830 }
1831
1832 /*************************************************************************
1833 * TrioFormat [private]
1834 *
1835 * Description:
1836 * This is the main engine for formatting output
1837 */
1838 static int
TrioFormat(void * destination,size_t destinationSize,int (* OutStream)(trio_T *,int),const char * format,va_list args)1839 TrioFormat(void *destination,
1840 size_t destinationSize,
1841 int (*OutStream)(trio_T *, int),
1842 const char *format,
1843 va_list args)
1844 {
1845 #if defined(USE_LOCALE)
1846 static struct lconv *localeValues = NULL;
1847 #endif
1848 int rc;
1849 parameter_T parameters[MAX_PARAMETERS];
1850 trio_T internalData;
1851 trio_T *data;
1852 int i;
1853 char *string;
1854 void *pointer;
1855 int flags;
1856 int width; /* must be signed */
1857 int precision;
1858 int base;
1859 char adjust;
1860 char quote;
1861 int index;
1862 ULONGLONG number;
1863
1864 assert(VALID(OutStream));
1865 assert(VALID(format));
1866 assert(VALID(args));
1867
1868 memset(&internalData, 0, sizeof(internalData));
1869 data = &internalData;
1870 data->OutStream = OutStream;
1871 data->location = destination;
1872 data->max = destinationSize;
1873
1874 #if defined(USE_LOCALE)
1875 if (NULL == localeValues)
1876 {
1877 localeValues = (struct lconv *)localeconv();
1878 if (StrLength(localeValues->decimal_point) > 0)
1879 {
1880 StrCopyMax(globalDecimalPoint,
1881 sizeof(globalDecimalPoint),
1882 localeValues->decimal_point);
1883 }
1884 if (StrLength(localeValues->thousands_sep) > 0)
1885 {
1886 StrCopyMax(globalThousandSeparator,
1887 sizeof(globalThousandSeparator),
1888 localeValues->thousands_sep);
1889 }
1890 }
1891 #endif
1892
1893 rc = TrioPreprocess(TYPE_PRINT, (char *)format, parameters, args);
1894 if (rc < 0)
1895 return rc;
1896
1897 index = 0;
1898 i = 0;
1899 while (format[index])
1900 {
1901 if (CHAR_IDENTIFIER == format[index])
1902 {
1903 if (CHAR_IDENTIFIER == format[index + 1])
1904 {
1905 OutStream(data, CHAR_IDENTIFIER);
1906 index += 2;
1907 }
1908 else
1909 {
1910 flags = parameters[i].flags;
1911 adjust = parameters[i].adjust;
1912 if (NIL == adjust)
1913 adjust = ' ';
1914 quote = parameters[i].quote;
1915 base = parameters[i].base;
1916
1917 /* Find width */
1918 width = parameters[i].width;
1919 if ((flags & (FLAGS_WIDTH | FLAGS_PARAMETER)) == (FLAGS_WIDTH | FLAGS_PARAMETER))
1920 {
1921 /* Get with as parameter instead */
1922 width = (int)parameters[width].data.num.asSigned;
1923 }
1924 /* Find precision */
1925 if (flags & FLAGS_PRECISION)
1926 {
1927 precision = parameters[i].precision;
1928 if (flags & FLAGS_PARAMETER)
1929 {
1930 precision = (int)parameters[precision].data.num.asSigned;
1931 }
1932 }
1933 else
1934 {
1935 precision = NO_PRECISION;
1936 }
1937 if (flags & FLAGS_PARAMETER)
1938 i++;
1939
1940 switch (parameters[i].type)
1941 {
1942 case FORMAT_CHAR:
1943 if (flags & FLAGS_QUOTE)
1944 OutStream(data, quote);
1945 if (! (flags & FLAGS_LEFTADJUST))
1946 {
1947 while (--width > 0)
1948 OutStream(data, adjust);
1949 }
1950
1951 OutStream(data, (char)parameters[i].data.num.asSigned);
1952
1953 if (flags & FLAGS_LEFTADJUST)
1954 {
1955 while(--width > 0)
1956 OutStream(data, adjust);
1957 }
1958 if (flags & FLAGS_QUOTE)
1959 OutStream(data, quote);
1960
1961 break; /* FORMAT_CHAR */
1962
1963 case FORMAT_INT:
1964 if (0 == base)
1965 {
1966 base = (flags & FLAGS_OCTAL) ? BASE_OCTAL
1967 : ( (flags & FLAGS_HEX) ? BASE_HEX
1968 : ( (flags & FLAGS_BINARY) ? BASE_BINARY
1969 : BASE_DECIMAL) );
1970 }
1971 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1972 if (flags & FLAGS_SIZE_T)
1973 number = parameters[i].data.sizet;
1974 else
1975 #endif
1976 number = parameters[i].data.num.asUnsigned;
1977 #if 0
1978 if (flags & FLAGS_QUAD)
1979 number = (ULONGLONG)parameters[i].data.quadNumber;
1980 else if (flags & FLAGS_LONG)
1981 number = (ULONGLONG)parameters[i].data.longNumber;
1982 else
1983 number = (ULONGLONG)parameters[i].data.number;
1984 #endif
1985 TrioOutStreamNumber(data,
1986 number,
1987 flags,
1988 width,
1989 precision,
1990 base);
1991
1992 break; /* FORMAT_INT */
1993
1994 case FORMAT_DOUBLE:
1995 TrioOutStreamDouble(data,
1996 parameters[i].data.longdoubleNumber,
1997 flags,
1998 width,
1999 precision);
2000 break; /* FORMAT_DOUBLE */
2001
2002 case FORMAT_STRING:
2003 TrioOutStreamString(data,
2004 parameters[i].data.string,
2005 flags,
2006 width,
2007 precision,
2008 quote,
2009 adjust);
2010 break; /* FORMAT_STRING */
2011
2012 case FORMAT_POINTER:
2013 pointer = parameters[i].data.pointer;
2014 if (NULL == pointer)
2015 {
2016 string = (char *)null;
2017 while (*string)
2018 OutStream(data, *string++);
2019 }
2020 else
2021 {
2022 /* The following line may give a compiler warning,
2023 * but it is ok.
2024 * For C9X we could use intptr_t instead.
2025 */
2026 number = (ULONGLONG)(parameters[i].data.pointer);
2027 /* Shrink to size of pointer */
2028 number &= (ULONGLONG)-1;
2029 flags |= (FLAGS_UNSIGNED | FLAGS_HEX |
2030 FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
2031 /* The number of bits in a hex ciffer is 4 */
2032 width = (sizeof("0x") - 1)
2033 + sizeof(void *) * CHAR_BIT / 4;
2034 TrioOutStreamNumber(data,
2035 number,
2036 flags,
2037 width,
2038 precision,
2039 BASE_HEX);
2040 }
2041 break; /* FORMAT_POINTER */
2042
2043 case FORMAT_COUNT:
2044 pointer = parameters[i].data.pointer;
2045 if (NULL != pointer)
2046 {
2047 #if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2048 if (flags & FLAGS_SIZE_T)
2049 *(size_t *)pointer = (size_t)data->done;
2050 else
2051 #endif
2052 if (flags & FLAGS_QUAD)
2053 {
2054 *(ULONGLONG int *)pointer = (ULONGLONG)data->done;
2055 }
2056 else if (flags & FLAGS_LONG)
2057 {
2058 *(long int *)pointer = (long int)data->done;
2059 }
2060 else if (flags & FLAGS_SHORT)
2061 {
2062 *(short int *)pointer = (short int)data->done;
2063 }
2064 else
2065 {
2066 *(int *)pointer = (int)data->done;
2067 }
2068 }
2069 break; /* FORMAT_COUNT */
2070
2071 case FORMAT_WIDTH:
2072 break; /* FORMAT_WIDTH */
2073
2074 #if defined(FORMAT_ERRNO)
2075 case FORMAT_ERRNO:
2076 string = (char *)StrError(parameters[i].data.errorNumber);
2077 if (string)
2078 {
2079 TrioOutStreamString(data,
2080 string,
2081 flags,
2082 width,
2083 precision,
2084 quote,
2085 adjust);
2086 }
2087 else
2088 {
2089 OutStream(data, '#');
2090 TrioOutStreamNumber(data,
2091 parameters[i].data.errorNumber,
2092 flags,
2093 width,
2094 precision,
2095 BASE_DECIMAL);
2096 }
2097 break; /* FORMAT_ERRNO */
2098 #endif
2099
2100 default:
2101 break;
2102 } /* switch parameter type */
2103
2104 /* Prepare for next */
2105 index = parameters[i].indexAfterSpecifier;
2106 #if 0
2107 /* And apply sanity check */
2108 if (NULL == format)
2109 break; /* while */
2110 #endif
2111 i++;
2112 }
2113 }
2114 else /* not identifier */
2115 {
2116 OutStream(data, format[index++]);
2117 }
2118 }
2119
2120 return data->done;
2121 }
2122
2123 /*************************************************************************
2124 * trio_printf
2125 */
2126 int
trio_printf(const char * format,...)2127 trio_printf(const char *format, ...)
2128 {
2129 int rc;
2130 va_list args;
2131
2132 assert(VALID(format));
2133
2134 va_start(args, format);
2135 rc = TrioFormat(stdout, 0, TrioFilePutChar, format, args);
2136 va_end(args);
2137 return rc;
2138 }
2139
2140 /*************************************************************************
2141 * trio_vprintf
2142 */
2143 int
trio_vprintf(const char * format,va_list args)2144 trio_vprintf(const char *format, va_list args)
2145 {
2146 assert(VALID(format));
2147 assert(VALID(args));
2148
2149 return TrioFormat(stdout, 0, TrioFilePutChar, format, args);
2150 }
2151
2152 /*************************************************************************
2153 * trio_fprintf
2154 */
2155 int
trio_fprintf(FILE * fd,const char * format,...)2156 trio_fprintf(FILE *fd, const char *format, ...)
2157 {
2158 int rc;
2159 va_list args;
2160
2161 assert(VALID(fd));
2162 assert(VALID(format));
2163
2164 va_start(args, format);
2165 rc = TrioFormat(fd, 0, TrioFilePutChar, format, args);
2166 va_end(args);
2167 return rc;
2168 }
2169
2170 /*************************************************************************
2171 * trio_fprintf
2172 */
2173 int
trio_vfprintf(FILE * fd,const char * format,va_list args)2174 trio_vfprintf(FILE *fd, const char *format, va_list args)
2175 {
2176 assert(VALID(fd));
2177 assert(VALID(format));
2178 assert(VALID(args));
2179
2180 return TrioFormat(fd, 0, TrioFilePutChar, format, args);
2181 }
2182
2183 /*************************************************************************
2184 * trio_sprintf
2185 */
2186 int
trio_sprintf(char * buffer,const char * format,...)2187 trio_sprintf(char *buffer, const char *format, ...)
2188 {
2189 int rc;
2190 va_list args;
2191
2192 assert(VALID(buffer));
2193 assert(VALID(format));
2194
2195 va_start(args, format);
2196 rc = TrioFormat(&buffer, 0, TrioStoreBuffer, format, args);
2197 *buffer = NIL; /* Terminate with NIL character */
2198 va_end(args);
2199 return rc;
2200 }
2201
2202 /*************************************************************************
2203 * trio_vsprintf
2204 */
2205 int
trio_vsprintf(char * buffer,const char * format,va_list args)2206 trio_vsprintf(char *buffer, const char *format, va_list args)
2207 {
2208 int rc;
2209
2210 assert(VALID(buffer));
2211 assert(VALID(format));
2212 assert(VALID(args));
2213
2214 rc = TrioFormat(&buffer, 0, TrioStoreBuffer, format, args);
2215 *buffer = NIL;
2216 return rc;
2217 }
2218
2219 /*************************************************************************
2220 * trio_snprintf
2221 */
2222 int
trio_snprintf(char * buffer,size_t bufferSize,const char * format,...)2223 trio_snprintf(char *buffer, size_t bufferSize, const char *format, ...)
2224 {
2225 int rc;
2226 va_list args;
2227
2228 assert(VALID(buffer));
2229 assert(bufferSize > 0);
2230 assert(VALID(format));
2231
2232 va_start(args, format);
2233 rc = TrioFormat(&buffer, bufferSize - 1, TrioStoreBufferMax,
2234 format, args);
2235 *buffer = NIL;
2236 va_end(args);
2237 return rc;
2238 }
2239
2240 /*************************************************************************
2241 * trio_vsnprintf
2242 */
2243 int
trio_vsnprintf(char * buffer,size_t bufferSize,const char * format,va_list args)2244 trio_vsnprintf(char *buffer, size_t bufferSize, const char *format,
2245 va_list args)
2246 {
2247 int rc;
2248
2249 assert(VALID(buffer));
2250 assert(VALID(format));
2251 assert(VALID(args));
2252
2253 rc = TrioFormat(&buffer, bufferSize - 1, TrioStoreBufferMax,
2254 format, args);
2255 *buffer = NIL;
2256 return rc;
2257 }
2258
2259 /*************************************************************************
2260 * trio_snprintfcat
2261 * Appends the new string to the dest string overwriting the '\0' character
2262 * at the end of dest.
2263 */
trio_snprintfcat(char * buffer,size_t bufferSize,const char * format,...)2264 int trio_snprintfcat(char *buffer, size_t bufferSize, const char *format, ...)
2265 {
2266 int rc;
2267 va_list args;
2268 size_t buf_len;
2269
2270 va_start(args, format);
2271
2272 assert(VALID(buffer));
2273 assert(VALID(format));
2274
2275 buf_len = strlen(buffer);
2276
2277 buffer = &buffer[buf_len];
2278
2279 rc = TrioFormat(&buffer, bufferSize - 1 - buf_len,
2280 TrioStoreBufferMax, format, args);
2281 va_end(args);
2282 *buffer = NIL;
2283 return rc;
2284 }
2285
2286 /*************************************************************************
2287 * trio_vsnprintfcat
2288 * Appends the new string to the dest string overwriting the '\0' character
2289 * at the end of dest.
2290 */
trio_vsnprintfcat(char * buffer,size_t bufferSize,const char * format,va_list args)2291 int trio_vsnprintfcat(char *buffer, size_t bufferSize, const char *format,
2292 va_list args)
2293 {
2294 int rc;
2295 size_t buf_len;
2296 assert(VALID(buffer));
2297 assert(VALID(format));
2298
2299 buf_len = strlen(buffer);
2300 buffer = &buffer[buf_len];
2301 rc = TrioFormat(&buffer, bufferSize - 1 - buf_len,
2302 TrioStoreBufferMax, format, args);
2303 *buffer = NIL;
2304 return rc;
2305 }
2306
2307 /*************************************************************************
2308 * trio_aprintf
2309 */
2310
2311 struct dynamicBuffer {
2312 char *buffer; /* allocated buffer */
2313 size_t len; /* length of string */
2314 size_t alloc; /* length of alloc */
2315 };
2316
2317 /* fputc() look-alike */
2318 static int
TrioStoreDynamicBuffer(trio_T * self,int output)2319 TrioStoreDynamicBuffer(trio_T *self, int output)
2320 {
2321 struct dynamicBuffer *infop;
2322
2323 assert(VALID(self));
2324 infop = (struct dynamicBuffer *)self->location;
2325 assert(VALID(infop));
2326
2327 if (infop->buffer == NULL) {
2328 infop->buffer=(char *)malloc(32);
2329 if (infop->buffer == NULL)
2330 return -1; /* fail */
2331 infop->alloc = 32;
2332 infop->len =0;
2333 }
2334 else if (infop->len + 1 >= infop->alloc) {
2335 char *newptr;
2336
2337 newptr = (char *)realloc(infop->buffer, infop->alloc * 2);
2338
2339 if (newptr == NULL) {
2340 return -1;
2341 }
2342 infop->buffer = newptr;
2343 infop->alloc *= 2;
2344 }
2345
2346 infop->buffer[ infop->len ] = output;
2347 infop->len++;
2348
2349 return output; /* fputc() returns like this on success */
2350 }
2351
trio_aprintf(const char * format,...)2352 char *trio_aprintf(const char *format, ...)
2353 {
2354 va_list args; /* argument pointer */
2355 int rc;
2356 struct dynamicBuffer info;
2357
2358 assert(VALID(format));
2359
2360 info.buffer = NULL;
2361 info.len = 0;
2362 info.alloc = 0;
2363
2364 va_start(args, format);
2365 rc = TrioFormat(&info, 0, TrioStoreDynamicBuffer, format, args);
2366 va_end(args);
2367 if(info.len) {
2368 info.buffer[info.len] = 0; /* we terminate this with a zero byte */
2369 return info.buffer;
2370 }
2371 else
2372 return NULL;
2373 }
2374
trio_vaprintf(const char * format,va_list args)2375 char *trio_vaprintf(const char *format, va_list args)
2376 {
2377 int rc;
2378 struct dynamicBuffer info;
2379
2380 assert(VALID(format));
2381 assert(VALID(args));
2382
2383 info.buffer = NULL;
2384 info.len = 0;
2385 info.alloc = 0;
2386
2387 rc = TrioFormat(&info, 0, TrioStoreDynamicBuffer, format, args);
2388 if(info.len) {
2389 info.buffer[info.len] = 0; /* we terminate this with a zero byte */
2390 return info.buffer;
2391 }
2392 else
2393 return NULL;
2394 }
2395
2396 /*************************************************************************
2397 * TrioSkipWhitespaces [private]
2398 */
2399 static int
TrioSkipWhitespaces(trio_T * self)2400 TrioSkipWhitespaces(trio_T *self)
2401 {
2402 int ch;
2403
2404 self->InStream(self, &ch);
2405 while (isspace(ch))
2406 {
2407 self->InStream(self, &ch);
2408 }
2409 return ch;
2410 }
2411
2412 /*************************************************************************
2413 * TrioGetNumber [private]
2414 */
2415 static int
TrioGetNumber(trio_T * self,int * target)2416 TrioGetNumber(trio_T *self, int *target)
2417 {
2418 int number = 0;
2419
2420 assert(VALID(self));
2421 assert(VALID(self->InStream));
2422
2423 while (isdigit(self->current))
2424 {
2425 number *= 10;
2426 number += (self->current - '0');
2427 self->InStream(self, NULL);
2428 }
2429 if (target)
2430 *target = number;
2431 return TRUE;
2432 }
2433
2434 /*************************************************************************
2435 * TrioGetString [private]
2436 */
2437 static int
TrioGetString(trio_T * self,char * target,int max)2438 TrioGetString(trio_T *self, char *target, int max)
2439 {
2440 assert(VALID(self));
2441 assert(VALID(self->InStream));
2442 assert(VALID(target));
2443
2444 while (! ((self->current == NIL) || isspace(self->current)))
2445 {
2446 if (target)
2447 *target++ = self->current;
2448 self->InStream(self, NULL);
2449 }
2450 if (target)
2451 *target = NIL;
2452 return TRUE;
2453 }
2454
2455 /*************************************************************************
2456 * TrioGetDouble [private]
2457 *
2458 * FIXME: add hex-float format
2459 */
2460 static int
TrioGetDouble(trio_T * self,double * doublePointer,int flags)2461 TrioGetDouble(trio_T *self, double *doublePointer, int flags)
2462 {
2463 int ch;
2464 char doubleString[512] = "";
2465 int index = 0;
2466
2467 /* Read entire double number from stream.
2468 * This is needed because StrToDouble requires
2469 * a string, but InStream can be anything else.
2470 */
2471 ch = self->current;
2472 if ((ch == '+') || (ch == '-'))
2473 {
2474 doubleString[index++] = ch;
2475 self->InStream(self, &ch);
2476 }
2477 while (isdigit(ch))
2478 {
2479 /* Integer part */
2480 doubleString[index++] = ch;
2481 self->InStream(self, &ch);
2482 }
2483 if (ch == '.')
2484 {
2485 /* Decimal part */
2486 doubleString[index++] = ch;
2487 self->InStream(self, &ch);
2488 while (isdigit(ch))
2489 {
2490 doubleString[index++] = ch;
2491 self->InStream(self, &ch);
2492 }
2493 if ((ch == 'e') || (ch == 'E'))
2494 {
2495 /* Exponent */
2496 doubleString[index++] = ch;
2497 self->InStream(self, &ch);
2498 if ((ch == '+') || (ch == '-'))
2499 {
2500 doubleString[index++] = ch;
2501 self->InStream(self, &ch);
2502 }
2503 while (isdigit(ch))
2504 {
2505 doubleString[index++] = ch;
2506 self->InStream(self, &ch);
2507 }
2508 }
2509 }
2510
2511 if (*doubleString == NIL)
2512 return FALSE;
2513
2514 if (flags & FLAGS_LONGDOUBLE)
2515 /* *longdoublePointer = StrToLongDouble()*/;
2516 else
2517 {
2518 *doublePointer = StrToDouble(doubleString, NULL);
2519 }
2520 return TRUE;
2521 }
2522
2523 /*************************************************************************
2524 * TrioInStreamString [private]
2525 */
2526 static int
TrioInStreamString(trio_T * self,int * intPointer)2527 TrioInStreamString(trio_T *self, int *intPointer)
2528 {
2529 char **buffer;
2530
2531 assert(VALID(self));
2532 assert(VALID(self->InStream));
2533 assert(VALID(self->location));
2534
2535 buffer = (char **)self->location;
2536 self->current = **buffer;
2537 (*buffer)++;
2538 self->amount++;
2539
2540 if (VALID(intPointer))
2541 {
2542 *intPointer = self->current;
2543 }
2544 /* Terminating zero is converted to End-Of-File */
2545 return ('\0' == self->current) ? EOF : self->current;
2546 }
2547
2548 /*************************************************************************
2549 * TrioScan [private]
2550 */
2551 static int
TrioScan(void * source,size_t sourceSize,int (* InStream)(trio_T *,int *),const char * format,va_list args)2552 TrioScan(void *source,
2553 size_t sourceSize,
2554 int (*InStream)(trio_T *, int *),
2555 const char *format,
2556 va_list args)
2557 {
2558 #if defined(USE_LOCALE)
2559 static struct lconv *localeValues = NULL;
2560 #endif
2561 int rc;
2562 parameter_T parameters[MAX_PARAMETERS];
2563 trio_T internalData;
2564 trio_T *data;
2565 int ch;
2566 int i = 0;
2567 int index;
2568 int flags;
2569
2570 assert(VALID(InStream));
2571 assert(VALID(format));
2572 assert(VALID(args));
2573
2574 memset(&internalData, 0, sizeof(internalData));
2575 data = &internalData;
2576 data->InStream = InStream;
2577 data->location = source;
2578 data->max = sourceSize;
2579
2580 #if defined(USE_LOCALE)
2581 if (NULL == localeValues)
2582 {
2583 localeValues = (struct lconv *)localeconv();
2584 if (StrLength(localeValues->decimal_point) > 0)
2585 {
2586 StrCopyMax(globalDecimalPoint,
2587 sizeof(globalDecimalPoint),
2588 localeValues->decimal_point);
2589 }
2590 if (StrLength(localeValues->thousands_sep) > 0)
2591 {
2592 StrCopyMax(globalThousandSeparator,
2593 sizeof(globalThousandSeparator),
2594 localeValues->thousands_sep);
2595 }
2596 }
2597 #endif
2598
2599 rc = TrioPreprocess(TYPE_SCAN, (char *)format, parameters, args);
2600 if (rc < 0)
2601 return rc;
2602
2603 index = 0;
2604 data->InStream(data, &ch);
2605
2606 while (format[index])
2607 {
2608 if (EOF == ch)
2609 return data->amount;
2610
2611 if (CHAR_IDENTIFIER == format[index])
2612 {
2613 if (CHAR_IDENTIFIER == format[index + 1])
2614 {
2615 /* Two %'s in format matches one % in input stream */
2616 if (CHAR_IDENTIFIER == ch)
2617 {
2618 index += 2;
2619 continue; /* while format chars left */
2620 }
2621 else
2622 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
2623 }
2624
2625 flags = parameters[i].flags;
2626 switch (parameters[i].type)
2627 {
2628 case FORMAT_INT:
2629 TrioGetNumber(data,
2630 (flags & FLAGS_IGNORE) ? NULL
2631 : (void *)(parameters[i].data.numPointer));
2632 break;
2633 case FORMAT_STRING:
2634 TrioGetString(data,
2635 (flags & FLAGS_IGNORE) ? NULL
2636 : parameters[i].data.string,
2637 0);
2638 break;
2639 case FORMAT_DOUBLE:
2640 TrioGetDouble(data,
2641 (flags & FLAGS_IGNORE) ? NULL
2642 : parameters[i].data.doublePointer,
2643 parameters[i].flags);
2644 break;
2645 default:
2646 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
2647 }
2648 data->done++;
2649 index = parameters[i].indexAfterSpecifier;
2650 i++;
2651 }
2652 else /* Not an % identifier */
2653 {
2654 if (isspace((int)format[index]))
2655 {
2656 /* Whitespaces may match any amount of whitespaces */
2657 TrioSkipWhitespaces(data);
2658 ch = data->current;
2659 }
2660 else if (ch == format[index])
2661 {
2662 data->InStream(data, &ch);
2663 }
2664 else
2665 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
2666
2667 index++;
2668 }
2669 }
2670 return data->done;
2671 }
2672
2673 /*************************************************************************
2674 * trio_sscanf
2675 */
2676 int
trio_sscanf(char * buffer,const char * format,...)2677 trio_sscanf(char *buffer, const char *format, ...)
2678 {
2679 int rc;
2680 va_list args;
2681
2682 assert(VALID(buffer));
2683 assert(VALID(format));
2684
2685 va_start(args, format);
2686 rc = TrioScan(&buffer, 0, TrioInStreamString, format, args);
2687 va_end(args);
2688 return rc;
2689 }
2690
2691 /*************************************************************************
2692 * trio_strerror [public]
2693 */
trio_strerror(int errorcode)2694 const char *trio_strerror(int errorcode)
2695 {
2696 switch (TRIO_ERROR_CODE(errorcode))
2697 {
2698 case TRIO_EOF:
2699 return "End of file";
2700 case TRIO_EINVAL:
2701 return "Invalid argument";
2702 case TRIO_ETOOMANY:
2703 return "Too many arguments";
2704 case TRIO_EDBLREF:
2705 return "Double reference";
2706 case TRIO_EGAP:
2707 return "Reference gap";
2708 default:
2709 return "Unknown";
2710 }
2711 }
2712