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