blob: a96b689f8fb0c25e94695cbd4ce4b248ac91f1b7 [file] [log] [blame]
Daniel Veillard92ad2102001-03-27 12:47:33 +00001/*************************************************************************
2 *
3 * $Id$
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 * Avoid heap allocation at all costs to ensure that the trio functions
19 * are async-safe. The exceptions are the printf/fprintf functions, which
20 * uses fputc, and the asprintf functions and the <alloc> modifier, which
21 * by design are required to allocate form the heap.
22 *
23 ************************************************************************/
24
25/* DV for libxml */
Daniel Veillardbc967662001-03-27 13:56:45 +000026#include <libxml/xmlversion.h>
Daniel Veillard92ad2102001-03-27 12:47:33 +000027#ifdef WITH_TRIO
28#include "config.h"
29/*
30 * DV changes applied
31 * excluded all unused interfaces, renamed them without the trio prefix
32 */
33
34/*
35 * FIXME:
36 * - Scan is probably too permissive about its modifiers.
37 * - Width for floating-point numbers (does it make sense?)
38 * - Add hex-float to TrioReadDouble
39 * - C escapes in %#[] ?
40 * - Multibyte characters (done for format parsing, except scan groups)
41 * - Widechar
42 * - Complex numbers? (C99 _Complex)
43 * - Boolean values? (C99 _Bool)
44 * - C99 NaN(n-char-sequence) missing
45 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
46 * for %a, because C99 used %a for other purposes. If specified as
47 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
48 * the C99 hex-float. This means that you cannot scan %as as a hex-float
49 * immediately followed by an 's'.
50 */
51
52static const char rcsid[] = "@(#)$Id$";
53
54#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
55# define TRIO_C99 /* FIXME: C99 support has not been properly tested */
56#endif
57#define TRIO_BSD
58#define TRIO_GNU
59#define TRIO_MISC
60#define TRIO_UNIX98
61#define TRIO_EXTENSION
62#define TRIO_ERRORS
63
64#if defined(unix) || defined(__xlC__) /* AIX xlC workaround */
65# define PLATFORM_UNIX
66#elif defined(AMIGA) && defined(__GNUC__)
67# define PLATFORM_UNIX
68#endif
69
70/*************************************************************************
71 * Include files
72 */
73
74
75#include "trio.h"
76#include "strio.h"
77#include <ctype.h>
78#include <math.h>
79#include <limits.h>
80#include <float.h>
81#include <stdarg.h>
82#include <errno.h>
83#if defined(TRIO_C99)
84# include <stdint.h>
85#endif
86#if defined(PLATFORM_UNIX)
87# include <unistd.h>
88# include <locale.h>
89# define USE_LOCALE
90#endif
91#ifndef DEBUG
92# define NDEBUG
93#endif
94#include <assert.h>
95
96/*************************************************************************
97 * Generic definitions
98 */
99
100#ifndef NULL
101# define NULL 0
102#endif
103#define NIL ((char)0)
104#ifdef __cplusplus
105# undef TRUE
106# undef FALSE
107# define TRUE true
108# define FALSE false
109# define BOOLEAN_T bool
110#else
111# ifndef FALSE
112# define FALSE (1 == 0)
113# define TRUE (! FALSE)
114# endif
115# define BOOLEAN_T int
116#endif
117
118/* mincore() can be used for debugging purposes */
119#define VALID(x) (NULL != (x))
120
121/* Encode the error code and the position. This is decoded
122 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
123 */
124#if defined(TRIO_ERRORS)
125# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
126#else
127# define TRIO_ERROR_RETURN(x,y) (-1)
128#endif
129
130/*************************************************************************
131 * Internal definitions
132 */
133
134#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX)
135# define USE_MULTIBYTE
136#endif
137
138#if !defined(USE_LONGLONG)
139# if defined(__GNUC__) && !defined(__STRICT_ANSI__)
140# define USE_LONGLONG
141# elif defined(__SUNPRO_C)
142# define USE_LONGLONG
143# elif defined(_LONG_LONG) || defined(_LONGLONG)
144# define USE_LONGLONG
145# endif
146#endif
147
148/* The extra long numbers */
149#if defined(USE_LONGLONG)
150# define LONGLONG long long
151# define ULONGLONG unsigned long long
152#else
153# define LONGLONG long
154# define ULONGLONG unsigned long
155#endif
156
157/* The longest possible integer */
158#if defined(TRIO_C99)
159# define LONGEST uintmax_t
160# define SLONGEST intmax_t
161#else
162# define LONGEST ULONGLONG
163# define SLONGEST LONGLONG
164#endif
165
166/* The maximal number of digits are for base 2 */
167#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT + 1)
168/* The width of a pointer. The number of bits in a hex digit is 4 */
169#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(void *) * CHAR_BIT / 4)
170
171/* Infinite and Not-A-Number for floating-point */
172#if defined(HUGE_VAL)
173# define USE_INFINITE
174# if defined(TRIO_C99)
175# define IS_INFINITE(x) isinf(x)
176# else
177# define IS_INFINITE(x) (((x)==HUGE_VAL) ? 1 : (((x)==-HUGE_VAL) ? -1 : 0))
178# endif
179# define INFINITE_LOWER "inf"
180# define INFINITE_UPPER "INF"
181# define LONG_INFINITE_LOWER "infinite"
182# define LONG_INFINITE_UPPER "INFINITE"
183#endif
184#if defined(NAN)
185# define USE_NAN
186# define IS_NAN(x) isnan(x)
187# define NAN_LOWER "nan"
188# define NAN_UPPER "NAN"
189#endif
190
191/* Various constants */
192enum {
193 TYPE_PRINT = 1,
194 TYPE_SCAN = 2,
195
196 /* Flags. Use maximum 32 */
197 FLAGS_NEW = 0,
198 FLAGS_STICKY = 1,
199 FLAGS_SPACE = 2 * FLAGS_STICKY,
200 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
201 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
202 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
203 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
204 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
205 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
206 FLAGS_QUAD = 2 * FLAGS_LONG,
207 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
208 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
209 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
210 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
211 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
212 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
213 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
214 FLAGS_WIDTH = 2 * FLAGS_UPPER,
215 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
216 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
217 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
218 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
219 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
220 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
221 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
222 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
223 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
224 FLAGS_ALLOC = 2 * FLAGS_WIDECHAR,
225 FLAGS_IGNORE = 2 * FLAGS_ALLOC,
226 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
227 FLAGS_SIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
228 /* Reused flags */
229 FLAGS_EXCLUDE = FLAGS_SHORT,
230 /* Compounded flags */
231 FLAGS_ALL_SIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
232
233 NO_POSITION = -1,
234 NO_WIDTH = 0,
235 NO_PRECISION = -1,
236 NO_SIZE = -1,
237
238 NO_BASE = -1,
239 MIN_BASE = 2,
240 MAX_BASE = 36,
241 BASE_BINARY = 2,
242 BASE_OCTAL = 8,
243 BASE_DECIMAL = 10,
244 BASE_HEX = 16,
245
246 /* Maximal number of allowed parameters */
247 MAX_PARAMETERS = 64,
248 /* Maximal number of characters in class */
249 MAX_CHARACTER_CLASS = UCHAR_MAX,
250
251 /* Maximal length of locale separator strings */
252 MAX_LOCALE_SEPARATOR_LENGTH = 64,
253 /* Maximal number of integers in grouping */
254 MAX_LOCALE_GROUPS = 64
255};
256
257#define NO_GROUPING ((int)CHAR_MAX)
258
259/* Fundamental formatting parameter types */
260#define FORMAT_UNKNOWN 0
261#define FORMAT_INT 1
262#define FORMAT_DOUBLE 2
263#define FORMAT_CHAR 3
264#define FORMAT_STRING 4
265#define FORMAT_POINTER 5
266#define FORMAT_COUNT 6
267#define FORMAT_PARAMETER 7
268#define FORMAT_GROUP 8
269#if defined(TRIO_GNU)
270# define FORMAT_ERRNO 10
271#endif
272
273/* Character constants */
274#define CHAR_IDENTIFIER '%'
275#define CHAR_BACKSLASH '\\'
276#define CHAR_QUOTE '\"'
277#define CHAR_ADJUST ' '
278
279/* Character class expressions */
280#define CLASS_ALNUM ":alnum:"
281#define CLASS_ALPHA ":alpha:"
282#define CLASS_CNTRL ":cntrl:"
283#define CLASS_DIGIT ":digit:"
284#define CLASS_GRAPH ":graph:"
285#define CLASS_LOWER ":lower:"
286#define CLASS_PRINT ":print:"
287#define CLASS_PUNCT ":punct:"
288#define CLASS_SPACE ":space:"
289#define CLASS_UPPER ":upper:"
290#define CLASS_XDIGIT ":xdigit:"
291
292/*
293 * SPECIFIERS:
294 *
295 *
296 * a Hex-float
297 * A Hex-float
298 * c Character
299 * C Widechar character (wint_t)
300 * d Decimal
301 * e Float
302 * E Float
303 * F Float
304 * F Float
305 * g Float
306 * G Float
307 * i Integer
308 * m Error message
309 * n Count
310 * o Octal
311 * p Pointer
312 * s String
313 * S Widechar string (wchar_t)
314 * u Unsigned
315 * x Hex
316 * X Hex
317 * [ Group
318 *
319 * Reserved:
320 *
321 * D Binary Coded Decimal %D(length,precision) (OS/390)
322 */
323#define SPECIFIER_CHAR 'c'
324#define SPECIFIER_STRING 's'
325#define SPECIFIER_DECIMAL 'd'
326#define SPECIFIER_INTEGER 'i'
327#define SPECIFIER_UNSIGNED 'u'
328#define SPECIFIER_OCTAL 'o'
329#define SPECIFIER_HEX 'x'
330#define SPECIFIER_HEX_UPPER 'X'
331#define SPECIFIER_FLOAT_E 'e'
332#define SPECIFIER_FLOAT_E_UPPER 'E'
333#define SPECIFIER_FLOAT_F 'f'
334#define SPECIFIER_FLOAT_F_UPPER 'F'
335#define SPECIFIER_FLOAT_G 'g'
336#define SPECIFIER_FLOAT_G_UPPER 'G'
337#define SPECIFIER_POINTER 'p'
338#define SPECIFIER_GROUP '['
339#define SPECIFIER_UNGROUP ']'
340#define SPECIFIER_COUNT 'n'
341#if defined(TRIO_UNIX98)
342# define SPECIFIER_CHAR_UPPER 'C'
343# define SPECIFIER_STRING_UPPER 'S'
344#endif
345#if defined(TRIO_C99)
346# define SPECIFIER_HEXFLOAT 'a'
347# define SPECIFIER_HEXFLOAT_UPPER 'A'
348#endif
349#if defined(TRIO_GNU)
350# define SPECIFIER_ERRNO 'm'
351#endif
352#if defined(TRIO_EXTENSION)
353# define SPECIFIER_BINARY 'b'
354# define SPECIFIER_BINARY_UPPER 'B'
355#endif
356
357/*
358 * QUALIFIERS:
359 *
360 *
361 * Numbers = d,i,o,u,x,X
362 * Float = a,A,e,E,f,F,g,G
363 * String = s
364 * Char = c
365 *
366 *
367 * 9$ Position
368 * Use the 9th parameter. 9 can be any number between 1 and
369 * the maximal argument
370 *
371 * 9 Width
372 * Set width to 9. 9 can be any number, but must not be postfixed
373 * by '$'
374 *
375 * h Short
376 * Numbers:
377 * (unsigned) short int
378 *
379 * hh Short short
380 * Numbers:
381 * (unsigned) char
382 *
383 * l Long
384 * Numbers:
385 * (unsigned) long int
386 * String:
387 * as the S specifier
388 * Char:
389 * as the C specifier
390 *
391 * ll Long Long
392 * Numbers:
393 * (unsigned) long long int
394 *
395 * L Long Double
396 * Float
397 * long double
398 *
399 * # Alternative
400 * Float:
401 * Decimal-point is always present
402 * String:
403 * non-printable characters are handled as \number
404 *
405 * Spacing
406 *
407 * + Sign
408 *
409 * - Alignment
410 *
411 * . Precision
412 *
413 * * Parameter
414 * print: use parameter
415 * scan: no parameter (ignore)
416 *
417 * q Quad
418 *
419 * Z size_t
420 *
421 * w Widechar
422 *
423 * ' Thousands/quote
424 * Numbers:
425 * Integer part grouped in thousands
426 * Binary numbers:
427 * Number grouped in nibbles (4 bits)
428 * String:
429 * Quoted string
430 *
431 * j intmax_t
432 * t prtdiff_t
433 * z size_t
434 *
435 * ! Sticky
436 * @ Parameter (for both print and scan)
437 *
438 * Extensions:
439 * NB: Some of these have been deprecated.
440 * <alloc> = GNU 'a' qualifier
441 * <base=n> = sets base to 'n' (int)
442 * <fill=c> = fill with 'c' (char)
443 * <quote> = quote string
444 */
445#define QUALIFIER_POSITION '$'
446#define QUALIFIER_SHORT 'h'
447#define QUALIFIER_LONG 'l'
448#define QUALIFIER_LONG_UPPER 'L'
449#define QUALIFIER_ALTERNATIVE '#'
450#define QUALIFIER_SPACE ' '
451#define QUALIFIER_PLUS '+'
452#define QUALIFIER_MINUS '-'
453#define QUALIFIER_DOT '.'
454#define QUALIFIER_STAR '*'
455#define QUALIFIER_CIRCUMFLEX '^'
456#if defined(TRIO_C99)
457# define QUALIFIER_SIZE_T 'z'
458# define QUALIFIER_PTRDIFF_T 't'
459# define QUALIFIER_INTMAX_T 'j'
460#endif
461#if defined(TRIO_BSD) || defined(TRIO_GNU)
462# define QUALIFIER_QUAD 'q'
463#endif
464#if defined(TRIO_GNU)
465# define QUALIFIER_SIZE_T_UPPER 'Z'
466#endif
467#if defined(TRIO_MISC)
468# define QUALIFIER_WIDECHAR 'w'
469#endif
470#if defined(TRIO_EXTENSION)
471# define QUALIFIER_QUOTE '\''
472# define QUALIFIER_STICKY '!'
473# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
474# define QUALIFIER_PARAM '@' /* Experimental */
475# define QUALIFIER_COLON ':' /* For scanlists */
476# define QUALIFIER_EXTENSIONBEGIN '<'
477# define QUALIFIER_EXTENSIONEND '>'
478# define QUALIFIER_EXTENSIONSEPARATOR ','
479# define QUALIFIER_EXTENSIONVALUE '='
480#endif
481
482/* Internal structure for parameters */
483typedef struct {
484 int type;
485 int flags;
486 int width;
487 size_t precision;
488 int base;
489 int varsize;
490 int indexAfterSpecifier;
491 union {
492 char *string;
493 void *pointer;
494 union {
495 SLONGEST asSigned;
496 LONGEST asUnsigned;
497 } number;
498 double doubleNumber;
499 double *doublePointer;
500 long double longdoubleNumber;
501 long double *longdoublePointer;
502 int errorNumber;
503 } data;
504} parameter_T;
505
506/* Internal structure */
507typedef struct _trio_T {
508 void *location;
509 void (*OutStream)(struct _trio_T *, int);
510 void (*InStream)(struct _trio_T *, int *);
511 /* The number of characters that would have been written/read if
512 * there had been sufficient space.
513 */
514 size_t processed;
515 /* The number of characters that are actually written/read.
516 * Processed and committed with only differ for the *nprintf
517 * and *nscanf functions.
518 */
519 size_t committed;
520 size_t max;
521 unsigned int current;
522} trio_T;
523
524
525/*************************************************************************
526 * Package scope variables
527 */
528
529#if defined(PLATFORM_UNIX)
530extern int errno;
531#endif
532
533#if defined(USE_LOCALE)
534static struct lconv *globalLocaleValues = NULL;
535#endif
536/* UNIX98 says "in a locale where the radix character is not defined,
537 * the radix character defaults to a period (.)"
538 */
539static char globalDecimalPoint[MAX_LOCALE_SEPARATOR_LENGTH] = ".";
540static char globalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH] = ",";
541static char globalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
542
543static const char globalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
544static const char globalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
545static BOOLEAN_T globalDigitsUnconverted = TRUE;
546static int globalDigitArray[128];
547
548static const char null[] = "(nil)";
549
550static const char extensionFill[] = "fill";
551static const size_t extensionFillSize = sizeof(extensionFill) - 1;
552static const char extensionAlloc[] = "alloc";
553static const size_t extensionAllocSize = sizeof(extensionAlloc) - 1;
554static const char extensionBase[] = "base";
555static const size_t extensionBaseSize = sizeof(extensionBase) - 1;
556static const char extensionQuote[] = "quote";
557static const size_t extensionQuoteSize = sizeof(extensionQuote) - 1;
558
559
560/*************************************************************************
561 * TrioIsQualifier [private]
562 *
563 * Description:
564 * Remember to add all new qualifiers to this function.
565 * QUALIFIER_POSITION must not be added.
566 */
567static BOOLEAN_T
568TrioIsQualifier(const 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_SHORT:
582 case QUALIFIER_LONG:
583 case QUALIFIER_LONG_UPPER:
584 case QUALIFIER_CIRCUMFLEX:
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#if defined(QUALIFIER_QUOTE)
607 case QUALIFIER_QUOTE:
608#endif
609#if defined(QUALIFIER_STICKY)
610 case QUALIFIER_STICKY:
611#endif
612#if defined(QUALIFIER_VARSIZE)
613 case QUALIFIER_VARSIZE:
614#endif
615#if defined(QUALIFIER_PARAM)
616 case QUALIFIER_PARAM:
617#endif
618 return TRUE;
619 default:
620 return FALSE;
621 }
622}
623
624/*************************************************************************
625 * TrioSetLocale [private]
626 */
627static void
628TrioSetLocale()
629{
630#if defined(USE_LOCALE)
631 globalLocaleValues = (struct lconv *)localeconv();
632 if (StrLength(globalLocaleValues->decimal_point) > 0)
633 {
634 StrCopyMax(globalDecimalPoint,
635 sizeof(globalDecimalPoint),
636 globalLocaleValues->decimal_point);
637 }
638 if (StrLength(globalLocaleValues->thousands_sep) > 0)
639 {
640 StrCopyMax(globalThousandSeparator,
641 sizeof(globalThousandSeparator),
642 globalLocaleValues->thousands_sep);
643 }
644 if (StrLength(globalLocaleValues->grouping) > 0)
645 {
646 StrCopyMax(globalGrouping,
647 sizeof(globalGrouping),
648 globalLocaleValues->grouping);
649 }
650#endif
651}
652
653/*************************************************************************
654 * TrioGetPosition [private]
655 *
656 * Get the %n$ position.
657 */
658static int
659TrioGetPosition(const char *format, int *indexPointer)
660{
661 char *tmpformat;
662 int number = 0;
663 int index = *indexPointer;
664
665 number = (int)StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
666 index = (int)(tmpformat - format);
667 if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
668 {
669 *indexPointer = index;
670 /* number is decreased by 1, because n$ starts from 1, whereas
671 * the array it is indexing starts from 0.
672 */
673 return number - 1;
674 }
675 return NO_POSITION;
676}
677
678/*************************************************************************
679 * TrioPreprocess [private]
680 *
681 * Description:
682 * Parse the format string
683 */
684static int
685TrioPreprocess(int type,
686 const char *format,
687 parameter_T *parameters,
688 va_list arglist)
689{
690#if defined(TRIO_ERRORS)
691 /* Count the number of times a parameter is referenced */
692 unsigned short usedEntries[MAX_PARAMETERS];
693#endif
694 /* Parameter counters */
695 int parameterPosition;
696 int currentParam;
697 int maxParam = -1;
698 BOOLEAN_T insideExtension; /* Are we inside an <> extension? */
699 /* Utility variables */
700 int flags;
701 int width;
702 int precision;
703 int varsize;
704 int base;
705 int index; /* Index into formatting string */
706 int dots; /* Count number of dots in modifier part */
707 BOOLEAN_T positional; /* Does the specifier have a positional? */
708 BOOLEAN_T got_sticky = FALSE; /* Are there any sticky modifiers at all? */
709 /* indices specifies the order in which the parameters must be
710 * read from the va_args (this is necessary to handle positionals)
711 */
712 int indices[MAX_PARAMETERS];
713 int pos = 0;
714 /* Various variables */
715 char ch;
716 int charlen;
717 int i = -1;
718 int num;
719 int work;
720 char *tmpformat;
721
722
723#if defined(TRIO_ERRORS)
724 /* The 'parameters' array is not initialized, but we need to
725 * know which entries we have used.
726 */
727 memset(usedEntries, 0, sizeof(usedEntries));
728#endif
729
730 index = 0;
731 parameterPosition = 0;
732#if defined(USE_MULTIBYTE)
733 mblen(NULL, 0);
734#endif
735
736 while (format[index])
737 {
738#if defined(USE_MULTIBYTE)
739 if (! isascii(format[index]))
740 {
741 /* Multibyte characters cannot be legal specifiers or
742 * modifiers, so we skip over them.
743 */
744 charlen = mblen(&format[index], MB_LEN_MAX);
745 index += (charlen > 0) ? charlen : 1;
746 continue; /* while */
747 }
748#endif
749 if (CHAR_IDENTIFIER == format[index++])
750 {
751 if (CHAR_IDENTIFIER == format[index])
752 {
753 index++;
754 continue; /* while */
755 }
756
757 flags = FLAGS_NEW;
758 insideExtension = FALSE;
759 dots = 0;
760 currentParam = TrioGetPosition(format, &index);
761 positional = (NO_POSITION != currentParam);
762 if (!positional)
763 {
764 /* We have no positional, get the next counter */
765 currentParam = parameterPosition;
766 }
767 if(currentParam >= MAX_PARAMETERS)
768 {
769 /* Bail out completely to make the error more obvious */
770 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
771 }
772
773 if (currentParam > maxParam)
774 maxParam = currentParam;
775
776 /* Default values */
777 width = NO_WIDTH;
778 precision = NO_PRECISION;
779 base = NO_BASE;
780 varsize = NO_SIZE;
781
782 while (TrioIsQualifier(format[index])
783 || insideExtension)
784 {
785 ch = format[index++];
786
787#if defined(TRIO_EXTENSION)
788 if (insideExtension)
789 {
790 if (QUALIFIER_EXTENSIONSEPARATOR == ch)
791 {
792 ch = QUALIFIER_EXTENSIONBEGIN;
793 }
794 else
795 {
796 insideExtension = FALSE;
797 }
798 }
799 if (QUALIFIER_EXTENSIONBEGIN == ch)
800 {
801 /* Parse extended format */
802 insideExtension = TRUE;
803 work = index;
804
805 switch (format[work])
806 {
807 case 'a':
808 /* <alloc> */
809 if (StrEqualMax(extensionAlloc, extensionAllocSize,
810 &format[work]))
811 {
812 flags |= FLAGS_ALLOC;
813 work += extensionAllocSize;
814 }
815 break;
816
817 case 'b':
818 /* <base=c> */
819 if (StrEqualMax(extensionBase, extensionBaseSize,
820 &format[work]))
821 {
822 work += extensionBaseSize;
823 if (QUALIFIER_EXTENSIONVALUE == format[work])
824 {
825 work++;
826 base = StrToLong(&format[work], &tmpformat, BASE_DECIMAL);
827 work += (int)(tmpformat - &format[work]);
828 if ((base < MIN_BASE) || (base > MAX_BASE))
829 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
830 }
831 }
832 break;
833
834#if 0
835 /* Deprecated */
836 case 'f':
837 if (StrEqualMax(extensionFill, extensionFillSize,
838 &format[work]))
839 {
840 work += extensionFillSize;
841 if (QUALIFIER_EXTENSIONVALUE == format[work])
842 {
843 work++;
844 adjust = format[work++];
845 }
846 }
847#endif
848 case 'q':
849 /* <quote> */
850 if (StrEqualMax(extensionQuote, extensionQuoteSize,
851 &format[work]))
852 {
853 flags |= FLAGS_QUOTE;
854 work += extensionQuoteSize;
855#if 0
856 /* Deprecated */
857 if (QUALIFIER_EXTENSIONVALUE == format[work])
858 {
859 work++;
860 quote = format[work++];
861 }
862#endif
863 }
864 break;
865
866 default:
867 break;
868 }
869
870 if (QUALIFIER_EXTENSIONEND == work[format])
871 {
872 insideExtension = FALSE;
873 index = ++work;
874 }
875 }
876#endif /* defined(TRIO_EXTENSION) */
877
878 switch (ch)
879 {
880#if defined(TRIO_EXTENSION)
881 case QUALIFIER_EXTENSIONBEGIN:
882 case QUALIFIER_EXTENSIONSEPARATOR:
883 /* Everything is fine, but ignore */
884 break;
885#endif
886 case QUALIFIER_SPACE:
887 flags |= FLAGS_SPACE;
888 break;
889
890 case QUALIFIER_PLUS:
891 flags |= FLAGS_SHOWSIGN;
892 break;
893
894 case QUALIFIER_MINUS:
895 flags |= FLAGS_LEFTADJUST;
896 flags &= ~FLAGS_NILPADDING;
897 break;
898
899 case QUALIFIER_ALTERNATIVE:
900 flags |= FLAGS_ALTERNATIVE;
901 break;
902
903 case QUALIFIER_DOT:
904 if (dots == 0) /* Precision */
905 {
906 dots++;
907
908 /* Skip if no precision */
909 if (QUALIFIER_DOT == format[index])
910 break;
911
912 /* After the first dot we have the precision */
913 flags |= FLAGS_PRECISION;
914 if ((QUALIFIER_STAR == format[index]) ||
915 (QUALIFIER_PARAM == format[index]))
916 {
917 index++;
918 flags |= FLAGS_PRECISION_PARAMETER;
919
920 precision = TrioGetPosition(format, &index);
921 if (precision == NO_POSITION)
922 {
923 parameterPosition++;
924 if (positional)
925 precision = parameterPosition;
926 else
927 {
928 precision = currentParam;
929 currentParam = precision + 1;
930 }
931 }
932 else
933 {
934 if (! positional)
935 currentParam = precision + 1;
936 if (width > maxParam)
937 maxParam = precision;
938 }
939 if (currentParam > maxParam)
940 maxParam = currentParam;
941 }
942 else
943 {
944 precision = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
945 index = (int)(tmpformat - format);
946 }
947 }
948 else if (dots == 1) /* Base */
949 {
950 dots++;
951
952 /* After the second dot we have the base */
953 flags |= FLAGS_BASE;
954 if ((QUALIFIER_STAR == format[index]) ||
955 (QUALIFIER_PARAM == format[index]))
956 {
957 index++;
958 flags |= FLAGS_BASE_PARAMETER;
959 base = TrioGetPosition(format, &index);
960 if (base == NO_POSITION)
961 {
962 parameterPosition++;
963 if (positional)
964 base = parameterPosition;
965 else
966 {
967 base = currentParam;
968 currentParam = base + 1;
969 }
970 }
971 else
972 {
973 if (! positional)
974 currentParam = base + 1;
975 if (base > maxParam)
976 maxParam = base;
977 }
978 if (currentParam > maxParam)
979 maxParam = currentParam;
980 }
981 else
982 {
983 base = StrToLong(&format[index], &tmpformat, BASE_DECIMAL);
984 if (base > MAX_BASE)
985 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
986 index = (int)(tmpformat - format);
987 }
988 }
989 else
990 {
991 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
992 }
993 break; /* QUALIFIER_DOT */
994
995 case QUALIFIER_PARAM:
996 type = TYPE_PRINT;
997 /* FALLTHROUGH */
998 case QUALIFIER_STAR:
999 /* This has different meanings for print and scan */
1000 if (TYPE_PRINT == type)
1001 {
1002 /* Read with from parameter */
1003 flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1004 width = TrioGetPosition(format, &index);
1005 if (width == NO_POSITION)
1006 {
1007 parameterPosition++;
1008 if (positional)
1009 width = parameterPosition;
1010 else
1011 {
1012 width = currentParam;
1013 currentParam = width + 1;
1014 }
1015 }
1016 else
1017 {
1018 if (! positional)
1019 currentParam = width + 1;
1020 if (width > maxParam)
1021 maxParam = width;
1022 }
1023 if (currentParam > maxParam)
1024 maxParam = currentParam;
1025 }
1026 else
1027 {
1028 /* Scan, but do not store result */
1029 flags |= FLAGS_IGNORE;
1030 }
1031
1032 break; /* QUALIFIER_STAR */
1033
1034 case '0':
1035 if (! (flags & FLAGS_LEFTADJUST))
1036 flags |= FLAGS_NILPADDING;
1037 /* FALLTHROUGH */
1038 case '1': case '2': case '3': case '4':
1039 case '5': case '6': case '7': case '8': case '9':
1040 flags |= FLAGS_WIDTH;
1041 /* &format[index - 1] is used to "rewind" the read
1042 * character from format
1043 */
1044 width = StrToLong(&format[index - 1], &tmpformat, BASE_DECIMAL);
1045 index = (int)(tmpformat - format);
1046 break;
1047
1048 case QUALIFIER_SHORT:
1049 if (flags & FLAGS_SHORTSHORT)
1050 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1051 else if (flags & FLAGS_SHORT)
1052 flags |= FLAGS_SHORTSHORT;
1053 else
1054 flags |= FLAGS_SHORT;
1055 break;
1056
1057 case QUALIFIER_LONG:
1058 if (flags & FLAGS_QUAD)
1059 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1060 else if (flags & FLAGS_LONG)
1061 flags |= FLAGS_QUAD;
1062 else
1063 flags |= FLAGS_LONG;
1064 break;
1065
1066 case QUALIFIER_LONG_UPPER:
1067 flags |= FLAGS_LONGDOUBLE;
1068 break;
1069
1070#if defined(QUALIFIER_SIZE_T)
1071 case QUALIFIER_SIZE_T:
1072 flags |= FLAGS_SIZE_T;
1073 /* Modify flags for later truncation of number */
1074 if (sizeof(size_t) == sizeof(ULONGLONG))
1075 flags |= FLAGS_QUAD;
1076 else if (sizeof(size_t) == sizeof(long))
1077 flags |= FLAGS_LONG;
1078 break;
1079#endif
1080
1081#if defined(QUALIFIER_PTRDIFF_T)
1082 case QUALIFIER_PTRDIFF_T:
1083 flags |= FLAGS_PTRDIFF_T;
1084 if (sizeof(ptrdiff_t) == sizeof(ULONGLONG))
1085 flags |= FLAGS_QUAD;
1086 else if (sizeof(ptrdiff_t) == sizeof(long))
1087 flags |= FLAGS_LONG;
1088 break;
1089#endif
1090
1091#if defined(QUALIFIER_INTMAX_T)
1092 case QUALIFIER_INTMAX_T:
1093 flags |= FLAGS_INTMAX_T;
1094 if (sizeof(intmax_t) == sizeof(ULONGLONG))
1095 flags |= FLAGS_QUAD;
1096 else if (sizeof(intmax_t) == sizeof(long))
1097 flags |= FLAGS_LONG;
1098 break;
1099#endif
1100
1101#if defined(QUALIFIER_QUAD)
1102 case QUALIFIER_QUAD:
1103 flags |= FLAGS_QUAD;
1104 break;
1105#endif
1106
1107#if defined(QUALIFIER_WIDECHAR)
1108 case QUALIFIER_WIDECHAR:
1109 flags |= FLAGS_WIDECHAR;
1110 break;
1111#endif
1112
1113#if defined(QUALIFIER_SIZE_T_UPPER)
1114 case QUALIFIER_SIZE_T_UPPER:
1115 break;
1116#endif
1117
1118#if defined(QUALIFIER_QUOTE)
1119 case QUALIFIER_QUOTE:
1120 flags |= FLAGS_QUOTE;
1121 break;
1122#endif
1123
1124#if defined(QUALIFIER_STICKY)
1125 case QUALIFIER_STICKY:
1126 flags |= FLAGS_STICKY;
1127 got_sticky = TRUE;
1128 break;
1129#endif
1130
1131#if defined(QUALIFIER_VARSIZE)
1132 case QUALIFIER_VARSIZE:
1133 flags |= FLAGS_SIZE_PARAMETER;
1134 parameterPosition++;
1135 if (positional)
1136 varsize = parameterPosition;
1137 else
1138 {
1139 varsize = currentParam;
1140 currentParam = varsize + 1;
1141 }
1142 if (currentParam > maxParam)
1143 maxParam = currentParam;
1144 break;
1145#endif
1146
1147 default:
1148 /* Bail out completely to make the error more obvious */
1149 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1150 }
1151 } /* while qualifier */
1152
1153 /* Parameters only need the type and value. The value is
1154 * read later.
1155 */
1156 if (flags & FLAGS_WIDTH_PARAMETER)
1157 {
1158#if defined(TRIO_ERRORS)
1159 usedEntries[width] += 1;
1160#endif
1161 parameters[pos].type = FORMAT_PARAMETER;
1162 indices[width] = pos;
1163 width = pos++;
1164 }
1165 if (flags & FLAGS_PRECISION_PARAMETER)
1166 {
1167#if defined(TRIO_ERRORS)
1168 usedEntries[precision] += 1;
1169#endif
1170 parameters[pos].type = FORMAT_PARAMETER;
1171 indices[precision] = pos;
1172 precision = pos++;
1173 }
1174 if (flags & FLAGS_BASE_PARAMETER)
1175 {
1176#if defined(TRIO_ERRORS)
1177 usedEntries[base] += 1;
1178#endif
1179 parameters[pos].type = FORMAT_PARAMETER;
1180 indices[base] = pos;
1181 base = pos++;
1182 }
1183 if (flags & FLAGS_SIZE_PARAMETER)
1184 {
1185#if defined(TRIO_ERRORS)
1186 usedEntries[varsize] += 1;
1187#endif
1188 parameters[pos].type = FORMAT_PARAMETER;
1189 indices[varsize] = pos;
1190 varsize = pos++;
1191 }
1192
1193 indices[currentParam] = pos;
1194
1195 switch (format[index++])
1196 {
1197#if defined(SPECIFIER_CHAR_UPPER)
1198 case SPECIFIER_CHAR_UPPER:
1199 flags |= FLAGS_LONG;
1200 /* FALLTHROUGH */
1201#endif
1202 case SPECIFIER_CHAR:
1203 parameters[pos].type = FORMAT_CHAR;
1204 break;
1205
1206#if defined(SPECIFIER_STRING_UPPER)
1207 case SPECIFIER_STRING_UPPER:
1208 flags |= FLAGS_LONG;
1209 /* FALLTHROUGH */
1210#endif
1211 case SPECIFIER_STRING:
1212 parameters[pos].type = FORMAT_STRING;
1213 break;
1214
1215 case SPECIFIER_GROUP:
1216 if (TYPE_SCAN == type)
1217 {
1218 parameters[pos].type = FORMAT_GROUP;
1219 while (format[index])
1220 {
1221 if (format[index++] == SPECIFIER_UNGROUP)
1222 break; /* while */
1223 }
1224 }
1225 break;
1226
1227 case SPECIFIER_INTEGER:
1228 parameters[pos].type = FORMAT_INT;
1229 break;
1230
1231 case SPECIFIER_UNSIGNED:
1232 flags |= FLAGS_UNSIGNED;
1233 parameters[pos].type = FORMAT_INT;
1234 break;
1235
1236 case SPECIFIER_DECIMAL:
1237 /* Disable base modifier */
1238 flags &= ~FLAGS_BASE_PARAMETER;
1239 base = BASE_DECIMAL;
1240 parameters[pos].type = FORMAT_INT;
1241 break;
1242
1243 case SPECIFIER_OCTAL:
1244 flags &= ~FLAGS_BASE_PARAMETER;
1245 base = BASE_OCTAL;
1246 parameters[pos].type = FORMAT_INT;
1247 break;
1248
1249#if defined(SPECIFIER_BINARY)
1250 case SPECIFIER_BINARY_UPPER:
1251 flags |= FLAGS_UPPER;
1252 /* FALLTHROUGH */
1253 case SPECIFIER_BINARY:
1254 flags |= FLAGS_NILPADDING;
1255 flags &= ~FLAGS_BASE_PARAMETER;
1256 base = BASE_BINARY;
1257 parameters[pos].type = FORMAT_INT;
1258 break;
1259#endif
1260
1261 case SPECIFIER_HEX_UPPER:
1262 flags |= FLAGS_UPPER;
1263 /* FALLTHROUGH */
1264 case SPECIFIER_HEX:
1265 flags |= FLAGS_UNSIGNED;
1266 flags &= ~FLAGS_BASE_PARAMETER;
1267 base = BASE_HEX;
1268 parameters[pos].type = FORMAT_INT;
1269 break;
1270
1271 case SPECIFIER_FLOAT_E_UPPER:
1272 flags |= FLAGS_UPPER;
1273 /* FALLTHROUGH */
1274 case SPECIFIER_FLOAT_E:
1275 flags |= FLAGS_FLOAT_E;
1276 parameters[pos].type = FORMAT_DOUBLE;
1277 break;
1278
1279 case SPECIFIER_FLOAT_G_UPPER:
1280 flags |= FLAGS_UPPER;
1281 /* FALLTHROUGH */
1282 case SPECIFIER_FLOAT_G:
1283 flags |= FLAGS_FLOAT_G;
1284 parameters[pos].type = FORMAT_DOUBLE;
1285 break;
1286
1287 case SPECIFIER_FLOAT_F_UPPER:
1288 flags |= FLAGS_UPPER;
1289 /* FALLTHROUGH */
1290 case SPECIFIER_FLOAT_F:
1291 parameters[pos].type = FORMAT_DOUBLE;
1292 break;
1293
1294 case SPECIFIER_POINTER:
1295 parameters[pos].type = FORMAT_POINTER;
1296 break;
1297
1298 case SPECIFIER_COUNT:
1299 parameters[pos].type = FORMAT_COUNT;
1300 break;
1301
1302#if defined(SPECIFIER_HEXFLOAT)
1303# if defined(SPECIFIER_HEXFLOAT_UPPER)
1304 case SPECIFIER_HEXFLOAT_UPPER:
1305 flags |= FLAGS_UPPER;
1306 /* FALLTHROUGH */
1307# endif
1308 case SPECIFIER_HEXFLOAT:
1309 base = BASE_HEX;
1310 parameters[pos].type = FORMAT_DOUBLE;
1311 break;
1312#endif
1313
1314#if defined(FORMAT_ERRNO)
1315 case SPECIFIER_ERRNO:
1316 parameters[pos].type = FORMAT_ERRNO;
1317 break;
1318#endif
1319
1320 default:
1321 /* Bail out completely to make the error more obvious */
1322 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
1323 }
1324
1325#if defined(TRIO_ERRORS)
1326 /* Count the number of times this entry has been used */
1327 usedEntries[currentParam] += 1;
1328#endif
1329
1330 /* Find last sticky parameters */
1331 if (got_sticky && !(flags & FLAGS_STICKY))
1332 {
1333 for (i = pos - 1; i >= 0; i--)
1334 {
1335 if (parameters[i].type == FORMAT_PARAMETER)
1336 continue;
1337 if ((parameters[i].flags & FLAGS_STICKY) &&
1338 (parameters[i].type == parameters[pos].type))
1339 {
1340 /* Do not overwrite current qualifiers */
1341 flags |= (parameters[i].flags & ~FLAGS_STICKY);
1342 if (width == NO_WIDTH)
1343 width = parameters[i].width;
1344 if (precision == NO_PRECISION)
1345 precision = parameters[i].precision;
1346 if (base == NO_BASE)
1347 base = parameters[i].base;
1348 break;
1349 }
1350 }
1351 }
1352
1353 parameters[pos].indexAfterSpecifier = index;
1354 parameters[pos].flags = flags;
1355 parameters[pos].width = width;
1356 parameters[pos].precision = precision;
1357 parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
1358 parameters[pos].varsize = varsize;
1359 pos++;
1360
1361 if (!positional)
1362 parameterPosition++;
1363
1364 } /* if identifier */
1365
1366 } /* while format characters left */
1367
1368 for (num = 0; num <= maxParam; num++)
1369 {
1370#if defined(TRIO_ERRORS)
1371 if (usedEntries[num] != 1)
1372 {
1373 if (usedEntries[num] == 0) /* gap detected */
1374 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1375 else /* double references detected */
1376 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1377 }
1378#endif
1379
1380 i = indices[num];
1381
1382 /* FORMAT_PARAMETERS are only present if they must be read,
1383 * so it makes no sense to check the ignore flag (besides,
1384 * the flags variable is not set for that particular type)
1385 */
1386 if ((parameters[i].type != FORMAT_PARAMETER) &&
1387 (parameters[i].flags & FLAGS_IGNORE))
1388 continue; /* for all arguments */
1389
1390 /* The stack arguments are read according to ANSI C89
1391 * default argument promotions:
1392 *
1393 * char = int
1394 * short = int
1395 * unsigned char = unsigned int
1396 * unsigned short = unsigned int
1397 * float = double
1398 *
1399 * In addition to the ANSI C89 these types are read (the
1400 * default argument promotions of C99 has not been
1401 * considered yet)
1402 *
1403 * long long
1404 * long double
1405 * size_t
1406 * ptrdiff_t
1407 * intmax_t
1408 */
1409 switch (parameters[i].type)
1410 {
1411 case FORMAT_GROUP:
1412 case FORMAT_STRING:
1413 parameters[i].data.string = va_arg(arglist, char *);
1414 break;
1415
1416 case FORMAT_POINTER:
1417 case FORMAT_COUNT:
1418 case FORMAT_UNKNOWN:
1419 parameters[i].data.pointer = va_arg(arglist, void *);
1420 break;
1421
1422 case FORMAT_CHAR:
1423 case FORMAT_INT:
1424 if (TYPE_SCAN == type)
1425 {
1426 parameters[i].data.pointer = (LONGEST *)va_arg(arglist, void *);
1427 }
1428 else
1429 {
1430#if defined(QUALIFIER_VARSIZE)
1431 if (parameters[i].flags & FLAGS_SIZE_PARAMETER)
1432 {
1433 /* Variable sizes are mapped onto the fixed sizes,
1434 * in accordance with integer promotion.
1435 */
1436 parameters[i].flags &= ~FLAGS_ALL_SIZES;
1437 varsize = (int)parameters[parameters[i].varsize].data.number.asUnsigned;
1438 if (varsize <= (int)sizeof(int))
1439 ;
1440 else if (varsize <= (int)sizeof(long))
1441 parameters[i].flags |= FLAGS_LONG;
1442#if defined(QUALIFIER_INTMAX_T)
1443 else if (varsize <= (int)sizeof(LONGLONG))
1444 parameters[i].flags |= FLAGS_QUAD;
1445 else
1446 parameters[i].flags |= FLAGS_INTMAX_T;
1447#else
1448 else
1449 parameters[i].flags |= FLAGS_QUAD;
1450#endif
1451 }
1452#endif
1453#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
1454 if (parameters[i].flags & FLAGS_SIZE_T)
1455 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, size_t);
1456 else
1457#endif
1458#if defined(QUALIFIER_PTRDIFF_T)
1459 if (parameters[i].flags & FLAGS_PTRDIFF_T)
1460 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, ptrdiff_t);
1461 else
1462#endif
1463#if defined(QUALIFIER_INTMAX_T)
1464 if (parameters[i].flags & FLAGS_INTMAX_T)
1465 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, intmax_t);
1466 else
1467#endif
1468 if (parameters[i].flags & FLAGS_QUAD)
1469 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, ULONGLONG);
1470 else if (parameters[i].flags & FLAGS_LONG)
1471 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, long);
1472 else
1473 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, int);
1474 }
1475 break;
1476
1477 case FORMAT_PARAMETER:
1478 parameters[i].data.number.asUnsigned = (LONGEST)va_arg(arglist, int);
1479 break;
1480
1481 case FORMAT_DOUBLE:
1482 if (TYPE_SCAN == type)
1483 {
1484 if (parameters[i].flags & FLAGS_LONG)
1485 parameters[i].data.longdoublePointer = va_arg(arglist, long double *);
1486 else
1487 parameters[i].data.doublePointer = va_arg(arglist, double *);
1488 }
1489 else
1490 {
1491 if (parameters[i].flags & FLAGS_LONG)
1492 parameters[i].data.longdoubleNumber = va_arg(arglist, long double);
1493 else
1494 parameters[i].data.longdoubleNumber = (long double)va_arg(arglist, double);
1495 }
1496 break;
1497
1498#if defined(FORMAT_ERRNO)
1499 case FORMAT_ERRNO:
1500 parameters[i].data.errorNumber = errno;
1501 break;
1502#endif
1503
1504 default:
1505 break;
1506 }
1507 } /* for all specifiers */
1508 return num;
1509}
1510
1511
1512/*************************************************************************
1513 *
1514 * FORMATTING
1515 *
1516 ************************************************************************/
1517
1518
1519/*************************************************************************
1520 * TrioWriteNumber [private]
1521 *
1522 * Description:
1523 * Output a number.
1524 * The complexity of this function is a result of the complexity
1525 * of the dependencies of the flags.
1526 */
1527static void
1528TrioWriteNumber(trio_T *self,
1529 LONGEST number,
1530 int flags,
1531 int width,
1532 int precision,
1533 int base)
1534{
1535 BOOLEAN_T isNegative;
1536 char buffer[MAX_CHARS_IN(LONGEST)
1537 * MAX_LOCALE_SEPARATOR_LENGTH
1538 * MAX_LOCALE_GROUPS];
1539 char *bufferend;
1540 char *pointer;
1541 const char *digits;
1542 int i;
1543 int length;
1544 char *p;
1545 int charsPerThousand;
1546 int groupingIndex;
1547 int count;
1548
1549 assert(VALID(self));
1550 assert(VALID(self->OutStream));
1551 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
1552
1553 digits = (flags & FLAGS_UPPER) ? globalDigitsUpper : globalDigitsLower;
1554
1555 if (flags & FLAGS_UNSIGNED)
1556 isNegative = FALSE;
1557 else if ((isNegative = (((SLONGEST)number) < 0)))
1558 number = -number;
1559
1560 if (flags & FLAGS_QUAD)
1561 number &= (ULONGLONG)-1;
1562 else if (flags & FLAGS_LONG)
1563 number &= (unsigned long)-1;
1564 else
1565 number &= (unsigned int)-1;
1566
1567 /* Build number */
1568 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1569 *pointer-- = NIL;
1570 charsPerThousand = (int)globalGrouping[0];
1571 groupingIndex = 1;
1572 for (i = 1; i < (int)sizeof(buffer); i++)
1573 {
1574 *pointer-- = digits[number % base];
1575 number /= base;
1576 if (number == 0)
1577 break;
1578
1579 if ((flags & FLAGS_QUOTE)
1580 && (charsPerThousand != NO_GROUPING)
1581 && (i % charsPerThousand == 0))
1582 {
1583 /*
1584 * We are building the number from the least significant
1585 * to the most significant digit, so we have to copy the
1586 * thousand separator backwards
1587 */
1588 length = StrLength(globalThousandSeparator);
1589 if (((int)(pointer - buffer) - length) > 0)
1590 {
1591 p = &globalThousandSeparator[length - 1];
1592 while (length-- > 0)
1593 *pointer-- = *p--;
1594 }
1595
1596 /* Advance to next grouping number */
1597 switch (globalGrouping[groupingIndex])
1598 {
1599 case CHAR_MAX: /* Disable grouping */
1600 charsPerThousand = NO_GROUPING;
1601 break;
1602 case 0: /* Repeat last group */
1603 break;
1604 default:
1605 charsPerThousand = (int)globalGrouping[groupingIndex++];
1606 break;
1607 }
1608 }
1609 }
1610
1611 /* Adjust width */
1612 width -= (bufferend - pointer) - 1;
1613
1614 /* Adjust precision */
1615 if (NO_PRECISION != precision)
1616 {
1617 precision -= (bufferend - pointer) - 1;
1618 if (precision < 0)
1619 precision = 0;
1620 flags |= FLAGS_NILPADDING;
1621 }
1622
1623 /* Adjust width further */
1624 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
1625 width--;
1626 if (flags & FLAGS_ALTERNATIVE)
1627 {
1628 switch (base)
1629 {
1630 case BASE_BINARY:
1631 case BASE_HEX:
1632 width -= 2;
1633 break;
1634 case BASE_OCTAL:
1635 width--;
1636 break;
1637 default:
1638 break;
1639 }
1640 }
1641
1642 /* Output prefixes spaces if needed */
1643 if (! ((flags & FLAGS_LEFTADJUST) ||
1644 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
1645 {
1646 count = (precision == NO_PRECISION) ? 0 : precision;
1647 while (width-- > count)
1648 self->OutStream(self, CHAR_ADJUST);
1649 }
1650
1651 /* width has been adjusted for signs and alternatives */
1652 if (isNegative)
1653 self->OutStream(self, '-');
1654 else if (flags & FLAGS_SHOWSIGN)
1655 self->OutStream(self, '+');
1656 else if (flags & FLAGS_SPACE)
1657 self->OutStream(self, ' ');
1658
1659 if (flags & FLAGS_ALTERNATIVE)
1660 {
1661 switch (base)
1662 {
1663 case BASE_BINARY:
1664 self->OutStream(self, '0');
1665 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
1666 break;
1667
1668 case BASE_OCTAL:
1669 self->OutStream(self, '0');
1670 break;
1671
1672 case BASE_HEX:
1673 self->OutStream(self, '0');
1674 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
1675 break;
1676
1677 default:
1678 break;
1679 } /* switch base */
1680 }
1681
1682 /* Output prefixed zero padding if needed */
1683 if (flags & FLAGS_NILPADDING)
1684 {
1685 if (precision == NO_PRECISION)
1686 precision = width;
1687 while (precision-- > 0)
1688 {
1689 self->OutStream(self, '0');
1690 width--;
1691 }
1692 }
1693
1694 /* Output the number itself */
1695 while (*(++pointer))
1696 {
1697 self->OutStream(self, *pointer);
1698 }
1699
1700 /* Output trailing spaces if needed */
1701 if (flags & FLAGS_LEFTADJUST)
1702 {
1703 while (width-- > 0)
1704 self->OutStream(self, CHAR_ADJUST);
1705 }
1706}
1707
1708/*************************************************************************
1709 * TrioWriteString [private]
1710 *
1711 * Description:
1712 * Output a string
1713 */
1714static void
1715TrioWriteString(trio_T *self,
1716 const char *string,
1717 int flags,
1718 int width,
1719 int precision)
1720{
1721 int length;
1722 int ch;
1723
1724 assert(VALID(self));
1725 assert(VALID(self->OutStream));
1726
1727 if (string == NULL)
1728 {
1729 string = null;
1730 length = sizeof(null) - 1;
1731 /* Disable quoting for the null pointer */
1732 flags &= (~FLAGS_QUOTE);
1733 width = 0;
1734 }
1735 else
1736 {
1737 length = StrLength(string);
1738 }
1739 if ((NO_PRECISION != precision) &&
1740 (precision < length))
1741 {
1742 length = precision;
1743 }
1744 width -= length;
1745
1746 if (flags & FLAGS_QUOTE)
1747 self->OutStream(self, CHAR_QUOTE);
1748
1749 if (! (flags & FLAGS_LEFTADJUST))
1750 {
1751 while (width-- > 0)
1752 self->OutStream(self, CHAR_ADJUST);
1753 }
1754
1755 while (length-- > 0)
1756 {
1757 /* The ctype parameters must be an unsigned char (or EOF) */
1758 ch = (unsigned char)(*string++);
1759 if (flags & FLAGS_ALTERNATIVE)
1760 {
1761 if (! (isprint(ch) || isspace(ch)))
1762 {
1763 /* Non-printable characters are converted to C escapes or
1764 * \number, if no C escape exists.
1765 */
1766 self->OutStream(self, CHAR_BACKSLASH);
1767 switch (ch)
1768 {
1769 case '\a': /* alert */
1770 self->OutStream(self, 'a');
1771 break;
1772 case '\b': /* backspace */
1773 self->OutStream(self, 'b');
1774 break;
1775 case '\f': /* formfeed */
1776 self->OutStream(self, 'f');
1777 break;
1778 case '\n': /* newline */
1779 self->OutStream(self, 'n');
1780 break;
1781 case '\r': /* carriage return */
1782 self->OutStream(self, 'r');
1783 break;
1784 case '\t': /* horizontal tab */
1785 self->OutStream(self, 't');
1786 break;
1787 case '\v': /* vertical tab */
1788 self->OutStream(self, 'v');
1789 break;
1790 case '\\': /* backslash */
1791 self->OutStream(self, '\\');
1792 break;
1793 default: /* the rest */
1794 self->OutStream(self, 'x');
1795 TrioWriteNumber(self, (ULONGLONG)ch,
1796 FLAGS_UNSIGNED | FLAGS_NILPADDING,
1797 2, 2, BASE_HEX);
1798 break;
1799 }
1800 }
1801 else if (ch == CHAR_BACKSLASH)
1802 {
1803 self->OutStream(self, CHAR_BACKSLASH);
1804 self->OutStream(self, CHAR_BACKSLASH);
1805 }
1806 else
1807 {
1808 self->OutStream(self, ch);
1809 }
1810 }
1811 else
1812 {
1813 self->OutStream(self, ch);
1814 }
1815 }
1816
1817 if (flags & FLAGS_LEFTADJUST)
1818 {
1819 while (width-- > 0)
1820 self->OutStream(self, CHAR_ADJUST);
1821 }
1822 if (flags & FLAGS_QUOTE)
1823 self->OutStream(self, CHAR_QUOTE);
1824}
1825
1826/*************************************************************************
1827 * TrioWriteDouble [private]
1828 */
1829static void
1830TrioWriteDouble(trio_T *self,
1831 long double longdoubleNumber,
1832 int flags,
1833 int width,
1834 int precision,
1835 int base)
1836{
1837 int charsPerThousand;
1838 int length;
1839 double number;
1840 double precisionPower;
1841 double workNumber;
1842 int integerDigits;
1843 int fractionDigits;
1844 int exponentDigits;
1845 int visibleDigits;
1846 int expectedWidth;
1847 int exponent;
1848 unsigned int uExponent;
1849 double dblBase;
1850 BOOLEAN_T isNegative;
1851 BOOLEAN_T isExponentNegative = FALSE;
1852 BOOLEAN_T isHex;
1853 const char *digits;
1854 char numberBuffer[MAX_CHARS_IN(double)
1855 * MAX_LOCALE_SEPARATOR_LENGTH
1856 * MAX_LOCALE_GROUPS];
1857 char *numberPointer;
1858 char exponentBuffer[MAX_CHARS_IN(double)];
1859 char *exponentPointer;
1860 int groupingIndex;
1861 char *work;
1862 int i;
1863 BOOLEAN_T onlyzero;
1864
1865 assert(VALID(self));
1866 assert(VALID(self->OutStream));
1867 assert(base == BASE_DECIMAL || base == BASE_HEX);
1868
1869 number = (double)longdoubleNumber;
1870
1871#if defined(USE_INFINITE)
1872 /* Handle infinite numbers and non-a-number first */
1873 switch (IS_INFINITE(number))
1874 {
1875 case 1:
1876 TrioWriteString(self,
1877 (flags & FLAGS_UPPER)
1878 ? INFINITE_UPPER
1879 : INFINITE_LOWER,
1880 flags, width, precision);
1881 return;
1882
1883 case -1:
1884 TrioWriteString(self,
1885 (flags & FLAGS_UPPER)
1886 ? "-" INFINITE_UPPER
1887 : "-" INFINITE_LOWER,
1888 flags, width, precision);
1889 return;
1890
1891 default:
1892 break;
1893 }
1894#endif
1895#if defined(USE_NAN)
1896 if (IS_NAN(number))
1897 {
1898 TrioWriteString(self,
1899 (flags & FLAGS_UPPER)
1900 ? NAN_UPPER
1901 : NAN_LOWER,
1902 0, 0, 0, 0, 0);
1903 return;
1904 }
1905#endif
1906
1907 /* Normal numbers */
1908 digits = (flags & FLAGS_UPPER) ? globalDigitsUpper : globalDigitsLower;
1909 isHex = (base == BASE_HEX);
1910 dblBase = (double)base;
1911
1912 if (precision == NO_PRECISION)
1913 precision = FLT_DIG;
1914 precisionPower = pow(10.0, (double)precision);
1915
1916 isNegative = (number < 0.0);
1917 if (isNegative)
1918 number = -number;
1919
1920 if ((flags & FLAGS_FLOAT_G) || isHex)
1921 {
1922 if ((number < 1.0e-4) || (number > precisionPower))
1923 flags |= FLAGS_FLOAT_E;
1924#if defined(TRIO_UNIX98)
1925 if (precision == 0)
1926 precision = 1;
1927#endif
1928 }
1929
1930 if (flags & FLAGS_FLOAT_E)
1931 {
1932 /* Scale the number */
1933 workNumber = log10(number);
1934 if (workNumber == -HUGE_VAL)
1935 {
1936 exponent = 0;
1937 /* Undo setting */
1938 if (flags & FLAGS_FLOAT_G)
1939 flags &= ~FLAGS_FLOAT_E;
1940 }
1941 else
1942 {
1943 exponent = (int)floor(workNumber);
1944 number /= pow(10.0, (double)exponent);
1945 isExponentNegative = (exponent < 0);
1946 uExponent = (isExponentNegative) ? -exponent : exponent;
1947 /* No thousand separators */
1948 flags &= ~FLAGS_QUOTE;
1949 }
1950 }
1951
1952 /*
1953 * Truncated number.
1954 *
1955 * precision is number of significant digits for FLOAT_G
1956 * and number of fractional digits for others
1957 */
1958 integerDigits = (number > DBL_EPSILON)
1959 ? 1 + (int)log10(floor(number))
1960 : 1;
1961 fractionDigits = (flags & FLAGS_FLOAT_G)
1962 ? precision - integerDigits
1963 : precision;
1964 number = floor(0.5 + number * pow(10.0, (double)fractionDigits));
1965 if ((int)log10(number) + 1 > integerDigits + fractionDigits)
1966 {
1967 /* Adjust if number was rounded up one digit (ie. 99 to 100) */
1968 integerDigits++;
1969 }
1970 visibleDigits = integerDigits + fractionDigits;
1971
1972 /* Build the fraction part */
1973 numberPointer = &numberBuffer[sizeof(numberBuffer) - 1];
1974 *numberPointer = NIL;
1975 onlyzero = TRUE;
1976 for (i = 0; i < fractionDigits; i++)
1977 {
1978 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
1979 number = floor(number / dblBase);
1980
1981 /* Prune trailing zeroes */
1982 if (numberPointer[0] != digits[0])
1983 onlyzero = FALSE;
1984 else if (onlyzero && (numberPointer[0] == digits[0]))
1985 numberPointer++;
1986 }
1987
1988 /* Insert decimal point */
1989 if ((flags & FLAGS_ALTERNATIVE) || ((fractionDigits > 0) && !onlyzero))
1990 {
1991 i = StrLength(globalDecimalPoint);
1992 while (i> 0)
1993 {
1994 *(--numberPointer) = globalDecimalPoint[--i];
1995 }
1996 }
1997 /* Insert the integer part and thousand separators */
1998 charsPerThousand = (int)globalGrouping[0];
1999 groupingIndex = 1;
2000 for (i = 1; i < integerDigits + 1; i++)
2001 {
2002 *(--numberPointer) = digits[(int)fmod(number, dblBase)];
2003 number = floor(number / dblBase);
2004 if (number < DBL_EPSILON)
2005 break;
2006
2007 if ((i > 0)
2008 && ((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
2009 && (charsPerThousand != NO_GROUPING)
2010 && (i % charsPerThousand == 0))
2011 {
2012 /*
2013 * We are building the number from the least significant
2014 * to the most significant digit, so we have to copy the
2015 * thousand separator backwards
2016 */
2017 length = StrLength(globalThousandSeparator);
2018 integerDigits += length;
2019 if (((int)(numberPointer - numberBuffer) - length) > 0)
2020 {
2021 work = &globalThousandSeparator[length - 1];
2022 while (length-- > 0)
2023 *(--numberPointer) = *work--;
2024 }
2025
2026 /* Advance to next grouping number */
2027 if (charsPerThousand != NO_GROUPING)
2028 {
2029 switch (globalGrouping[groupingIndex])
2030 {
2031 case CHAR_MAX: /* Disable grouping */
2032 charsPerThousand = NO_GROUPING;
2033 break;
2034 case 0: /* Repeat last group */
2035 break;
2036 default:
2037 charsPerThousand = (int)globalGrouping[groupingIndex++];
2038 break;
2039 }
2040 }
2041 }
2042 }
2043
2044 /* Build the exponent */
2045 exponentDigits = 0;
2046 if (flags & FLAGS_FLOAT_E)
2047 {
2048 exponentPointer = &exponentBuffer[sizeof(exponentBuffer) - 1];
2049 *exponentPointer-- = NIL;
2050 do {
2051 *exponentPointer-- = digits[uExponent % base];
2052 uExponent /= base;
2053 exponentDigits++;
2054 } while (uExponent);
2055 }
2056
2057 /* Calculate expected width.
2058 * sign + integer part + thousands separators + decimal point
2059 * + fraction + exponent
2060 */
2061 expectedWidth = StrLength(numberPointer);
2062 if (isNegative || (flags & FLAGS_SHOWSIGN))
2063 expectedWidth += sizeof("-") - 1;
2064 if (exponentDigits > 0)
2065 expectedWidth += exponentDigits + sizeof("E+") - 1;
2066 if (isExponentNegative)
2067 expectedWidth += sizeof('-') - 1;
2068 if (isHex)
2069 expectedWidth += sizeof("0X") - 1;
2070
2071 /* Output prefixing */
2072 if (flags & FLAGS_NILPADDING)
2073 {
2074 /* Leading zeros must be after sign */
2075 if (isNegative)
2076 self->OutStream(self, '-');
2077 else if (flags & FLAGS_SHOWSIGN)
2078 self->OutStream(self, '+');
2079 if (isHex)
2080 {
2081 self->OutStream(self, '0');
2082 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2083 }
2084 if (!(flags & FLAGS_LEFTADJUST))
2085 {
2086 for (i = expectedWidth; i < width; i++)
2087 {
2088 self->OutStream(self, '0');
2089 }
2090 }
2091 }
2092 else
2093 {
2094 /* Leading spaces must be before sign */
2095 if (!(flags & FLAGS_LEFTADJUST))
2096 {
2097 for (i = expectedWidth; i < width; i++)
2098 {
2099 self->OutStream(self, CHAR_ADJUST);
2100 }
2101 }
2102 if (isNegative)
2103 self->OutStream(self, '-');
2104 else if (flags & FLAGS_SHOWSIGN)
2105 self->OutStream(self, '+');
2106 if (isHex)
2107 {
2108 self->OutStream(self, '0');
2109 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2110 }
2111 }
2112 /* Output number */
2113 for (i = 0; numberPointer[i]; i++)
2114 {
2115 self->OutStream(self, numberPointer[i]);
2116 }
2117 /* Output exponent */
2118 if (exponentDigits > 0)
2119 {
2120 self->OutStream(self,
2121 isHex
2122 ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
2123 : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
2124 self->OutStream(self, (isExponentNegative) ? '-' : '+');
2125 for (i = 0; i < exponentDigits; i++)
2126 {
2127 self->OutStream(self, exponentPointer[i + 1]);
2128 }
2129 }
2130 /* Output trailing spaces */
2131 if (flags & FLAGS_LEFTADJUST)
2132 {
2133 for (i = expectedWidth; i < width; i++)
2134 {
2135 self->OutStream(self, CHAR_ADJUST);
2136 }
2137 }
2138}
2139
2140/*************************************************************************
2141 * TrioFormat [private]
2142 *
2143 * Description:
2144 * This is the main engine for formatting output
2145 */
2146static int
2147TrioFormat(void *destination,
2148 size_t destinationSize,
2149 void (*OutStream)(trio_T *, int),
2150 const char *format,
2151 va_list args)
2152{
2153#if defined(USE_MULTIBYTE)
2154 int charlen;
2155#endif
2156 int status;
2157 parameter_T parameters[MAX_PARAMETERS];
2158 trio_T internalData;
2159 trio_T *data;
2160 int i;
2161 const char *string;
2162 void *pointer;
2163 int flags;
2164 int width;
2165 int precision;
2166 int base;
2167 int index;
2168 ULONGLONG number;
2169
2170 assert(VALID(OutStream));
2171 assert(VALID(format));
2172 assert(VALID(args));
2173
2174 /* memset(&parameters, 0, sizeof(parameters)); */
2175 memset(&internalData, 0, sizeof(internalData));
2176 data = &internalData;
2177 data->OutStream = OutStream;
2178 data->location = destination;
2179 data->max = destinationSize;
2180
2181#if defined(USE_LOCALE)
2182 if (NULL == globalLocaleValues)
2183 {
2184 TrioSetLocale();
2185 }
2186#endif
2187
2188 status = TrioPreprocess(TYPE_PRINT, format, parameters, args);
2189 if (status < 0)
2190 return status;
2191
2192 index = 0;
2193 i = 0;
2194#if defined(USE_MULTIBYTE)
2195 mblen(NULL, 0);
2196#endif
2197
2198 while (format[index])
2199 {
2200#if defined(USE_MULTIBYTE)
2201 if (! isascii(format[index]))
2202 {
2203 charlen = mblen(&format[index], MB_LEN_MAX);
2204 while (charlen-- > 0)
2205 {
2206 OutStream(data, format[index++]);
2207 }
2208 continue; /* while */
2209 }
2210#endif
2211 if (CHAR_IDENTIFIER == format[index])
2212 {
2213 if (CHAR_IDENTIFIER == format[index + 1])
2214 {
2215 OutStream(data, CHAR_IDENTIFIER);
2216 index += 2;
2217 }
2218 else
2219 {
2220 /* Skip the parameter entries */
2221 while (parameters[i].type == FORMAT_PARAMETER)
2222 i++;
2223
2224 flags = parameters[i].flags;
2225
2226 /* Find width */
2227 width = parameters[i].width;
2228 if (flags & FLAGS_WIDTH_PARAMETER)
2229 {
2230 /* Get width from parameter list */
2231 width = (int)parameters[width].data.number.asSigned;
2232 }
2233
2234 /* Find precision */
2235 if (flags & FLAGS_PRECISION)
2236 {
2237 precision = parameters[i].precision;
2238 if (flags & FLAGS_PRECISION_PARAMETER)
2239 {
2240 /* Get precision from parameter list */
2241 precision = (int)parameters[precision].data.number.asSigned;
2242 }
2243 }
2244 else
2245 {
2246 precision = NO_PRECISION;
2247 }
2248
2249 /* Find base */
2250 base = parameters[i].base;
2251 if (flags & FLAGS_BASE_PARAMETER)
2252 {
2253 /* Get base from parameter list */
2254 base = (int)parameters[base].data.number.asSigned;
2255 }
2256
2257 switch (parameters[i].type)
2258 {
2259 case FORMAT_CHAR:
2260 if (flags & FLAGS_QUOTE)
2261 OutStream(data, CHAR_QUOTE);
2262 if (! (flags & FLAGS_LEFTADJUST))
2263 {
2264 while (--width > 0)
2265 OutStream(data, CHAR_ADJUST);
2266 }
2267
2268 OutStream(data, (char)parameters[i].data.number.asSigned);
2269
2270 if (flags & FLAGS_LEFTADJUST)
2271 {
2272 while(--width > 0)
2273 OutStream(data, CHAR_ADJUST);
2274 }
2275 if (flags & FLAGS_QUOTE)
2276 OutStream(data, CHAR_QUOTE);
2277
2278 break; /* FORMAT_CHAR */
2279
2280 case FORMAT_INT:
2281 if (base == NO_BASE)
2282 base = BASE_DECIMAL;
2283
2284 TrioWriteNumber(data,
2285 parameters[i].data.number.asUnsigned,
2286 flags,
2287 width,
2288 precision,
2289 base);
2290
2291 break; /* FORMAT_INT */
2292
2293 case FORMAT_DOUBLE:
2294 TrioWriteDouble(data,
2295 parameters[i].data.longdoubleNumber,
2296 flags,
2297 width,
2298 precision,
2299 base);
2300 break; /* FORMAT_DOUBLE */
2301
2302 case FORMAT_STRING:
2303 TrioWriteString(data,
2304 parameters[i].data.string,
2305 flags,
2306 width,
2307 precision);
2308 break; /* FORMAT_STRING */
2309
2310 case FORMAT_POINTER:
2311 pointer = parameters[i].data.pointer;
2312 if (NULL == pointer)
2313 {
2314 string = null;
2315 while (*string)
2316 OutStream(data, *string++);
2317 }
2318 else
2319 {
2320 /* The subtraction of the null pointer is a workaround
2321 * to avoid a compiler warning. The performance overhead
2322 * is negligible (and likely to be removed by an
2323 * optimising compiler). The (char *) casting is done
2324 * to please ANSI C++.
2325 */
2326 number = (ULONGLONG)((char *)parameters[i].data.pointer
2327 - (char *)0);
2328 /* Shrink to size of pointer */
2329 number &= (ULONGLONG)-1;
2330 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
2331 FLAGS_NILPADDING);
2332 TrioWriteNumber(data,
2333 number,
2334 flags,
2335 POINTER_WIDTH,
2336 precision,
2337 BASE_HEX);
2338 }
2339 break; /* FORMAT_POINTER */
2340
2341 case FORMAT_COUNT:
2342 pointer = parameters[i].data.pointer;
2343 if (NULL != pointer)
2344 {
2345 /* C99 paragraph 7.19.6.1.8 says "the number of
2346 * characters written to the output stream so far by
2347 * this call", which is data->committed
2348 */
2349#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
2350 if (flags & FLAGS_SIZE_T)
2351 *(size_t *)pointer = (size_t)data->committed;
2352 else
2353#endif
2354#if defined(QUALIFIER_PTRDIFF_T)
2355 if (flags & FLAGS_PTRDIFF_T)
2356 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
2357 else
2358#endif
2359#if defined(QUALIFIER_INTMAX_T)
2360 if (flags & FLAGS_INTMAX_T)
2361 *(intmax_t *)pointer = (intmax_t)data->committed;
2362 else
2363#endif
2364 if (flags & FLAGS_QUAD)
2365 {
2366 *(ULONGLONG int *)pointer = (ULONGLONG)data->committed;
2367 }
2368 else if (flags & FLAGS_LONG)
2369 {
2370 *(long int *)pointer = (long int)data->committed;
2371 }
2372 else if (flags & FLAGS_SHORT)
2373 {
2374 *(short int *)pointer = (short int)data->committed;
2375 }
2376 else
2377 {
2378 *(int *)pointer = (int)data->committed;
2379 }
2380 }
2381 break; /* FORMAT_COUNT */
2382
2383 case FORMAT_PARAMETER:
2384 break; /* FORMAT_PARAMETER */
2385
2386#if defined(FORMAT_ERRNO)
2387 case FORMAT_ERRNO:
2388 string = StrError(parameters[i].data.errorNumber);
2389 if (string)
2390 {
2391 TrioWriteString(data,
2392 string,
2393 flags,
2394 width,
2395 precision);
2396 }
2397 else
2398 {
2399 OutStream(data, '#');
2400 TrioWriteNumber(data,
2401 (LONGEST)parameters[i].data.errorNumber,
2402 flags,
2403 width,
2404 precision,
2405 BASE_DECIMAL);
2406 }
2407 break; /* FORMAT_ERRNO */
2408#endif
2409
2410 default:
2411 break;
2412 } /* switch parameter type */
2413
2414 /* Prepare for next */
2415 index = parameters[i].indexAfterSpecifier;
2416 i++;
2417 }
2418 }
2419 else /* not identifier */
2420 {
2421 OutStream(data, format[index++]);
2422 }
2423 }
2424
2425 return data->processed;
2426}
2427
2428/*************************************************************************
2429 * TrioOutStreamFile [private]
2430 */
2431static void
2432TrioOutStreamFile(trio_T *self, int output)
2433{
2434 FILE *file = (FILE *)self->location;
2435
2436 assert(VALID(self));
2437 assert(VALID(file));
2438
2439 self->processed++;
2440 self->committed++;
2441 (void)fputc(output, file);
2442}
2443
2444/*************************************************************************
2445 * TrioOutStreamFileDescriptor [private]
2446 */
2447static void
2448TrioOutStreamFileDescriptor(trio_T *self, int output)
2449{
2450 int fd = *((int *)self->location);
2451 char ch;
2452
2453 assert(VALID(self));
2454
2455 ch = (char)output;
2456 (void)write(fd, &ch, sizeof(char));
2457 self->processed++;
2458 self->committed++;
2459}
2460
2461/*************************************************************************
2462 * TrioOutStreamString [private]
2463 */
2464static void
2465TrioOutStreamString(trio_T *self, int output)
2466{
2467 char **buffer = (char **)self->location;
2468
2469 assert(VALID(self));
2470 assert(VALID(buffer));
2471
2472 **buffer = (char)output;
2473 (*buffer)++;
2474 self->processed++;
2475 self->committed++;
2476}
2477
2478/*************************************************************************
2479 * TrioOutStreamStringMax [private]
2480 */
2481static void
2482TrioOutStreamStringMax(trio_T *self, int output)
2483{
2484 char **buffer;
2485
2486 assert(VALID(self));
2487 buffer = (char **)self->location;
2488 assert(VALID(buffer));
2489
2490 if (self->processed < self->max)
2491 {
2492 **buffer = (char)output;
2493 (*buffer)++;
2494 self->committed++;
2495 }
2496 self->processed++;
2497}
2498
2499/*************************************************************************
2500 * TrioOutStreamStringDynamic [private]
2501 */
2502#define DYNAMIC_START_SIZE 32
2503struct dynamicBuffer {
2504 char *buffer;
2505 size_t length;
2506 size_t allocated;
2507};
2508
2509static void
2510TrioOutStreamStringDynamic(trio_T *self, int output)
2511{
2512 struct dynamicBuffer *infop;
2513
2514 assert(VALID(self));
2515 assert(VALID(self->location));
2516
2517 infop = (struct dynamicBuffer *)self->location;
2518
2519 if (infop->buffer == NULL)
2520 {
2521 /* Start with a reasonable size */
2522 infop->buffer = (char *)malloc(DYNAMIC_START_SIZE);
2523 if (infop->buffer == NULL)
2524 return; /* fail */
2525
2526 infop->allocated = DYNAMIC_START_SIZE;
2527 self->processed = 0;
2528 self->committed = 0;
2529 }
2530 else if (self->committed + sizeof(NIL) >= infop->allocated)
2531 {
2532 char *newptr;
2533
2534 /* Allocate increasing chunks */
2535 newptr = (char *)realloc(infop->buffer, infop->allocated * 2);
2536
2537 if (newptr == NULL)
2538 return;
2539
2540 infop->buffer = newptr;
2541 infop->allocated *= 2;
2542 }
2543
2544 infop->buffer[self->committed] = output;
2545 self->committed++;
2546 self->processed++;
2547
2548 infop->length = self->committed;
2549}
2550
2551#ifndef HAVE_PRINTF
2552/*************************************************************************
2553 * trio_printf
2554 */
2555int
2556printf(const char *format, ...)
2557{
2558 int status;
2559 va_list args;
2560
2561 assert(VALID(format));
2562
2563 va_start(args, format);
2564 status = TrioFormat(stdout, 0, TrioOutStreamFile, format, args);
2565 va_end(args);
2566 return status;
2567}
2568#endif
2569
2570#ifndef HAVE_FPRINTF
2571/*************************************************************************
2572 * trio_fprintf
2573 */
2574int
2575fprintf(FILE *file, const char *format, ...)
2576{
2577 int status;
2578 va_list args;
2579
2580 assert(VALID(file));
2581 assert(VALID(format));
2582
2583 va_start(args, format);
2584 status = TrioFormat(file, 0, TrioOutStreamFile, format, args);
2585 va_end(args);
2586 return status;
2587}
2588#endif
2589
2590#ifndef HAVE_VFPRINTF
2591/*************************************************************************
2592 * trio_vfprintf
2593 */
2594int
2595vfprintf(FILE *file, const char *format, va_list args)
2596{
2597 assert(VALID(file));
2598 assert(VALID(format));
2599 assert(VALID(args));
2600
2601 return TrioFormat(file, 0, TrioOutStreamFile, format, args);
2602}
2603#endif
2604
2605#ifndef HAVE_SPRINTF
2606/*************************************************************************
2607 * trio_sprintf
2608 */
2609int
2610sprintf(char *buffer, const char *format, ...)
2611{
2612 int status;
2613 va_list args;
2614
2615 assert(VALID(buffer));
2616 assert(VALID(format));
2617
2618 va_start(args, format);
2619 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args);
2620 *buffer = NIL; /* Terminate with NIL character */
2621 va_end(args);
2622 return status;
2623}
2624#endif
2625
2626#ifndef HAVE_VSPRINTF
2627/*************************************************************************
2628 * trio_vsprintf
2629 */
2630int
2631vsprintf(char *buffer, const char *format, va_list args)
2632{
2633 int status;
2634
2635 assert(VALID(buffer));
2636 assert(VALID(format));
2637 assert(VALID(args));
2638
2639 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args);
2640 *buffer = NIL;
2641 return status;
2642}
2643#endif
2644
2645#ifndef HAVE_SNPRINTF
2646/*************************************************************************
2647 * trio_snprintf
2648 */
2649int
2650snprintf(char *buffer, size_t bufferSize, const char *format, ...)
2651{
2652 int status;
2653 va_list args;
2654
2655 assert(VALID(buffer));
2656 assert(VALID(format));
2657
2658 va_start(args, format);
2659 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
2660 TrioOutStreamStringMax, format, args);
2661 if (bufferSize > 0)
2662 *buffer = NIL;
2663 va_end(args);
2664 return status;
2665}
2666#endif
2667
2668#ifndef HAVE_VSNPRINTF
2669/*************************************************************************
2670 * trio_vsnprintf
2671 */
2672int
2673vsnprintf(char *buffer, size_t bufferSize, const char *format,
2674 va_list args)
2675{
2676 int status;
2677
2678 assert(VALID(buffer));
2679 assert(VALID(format));
2680 assert(VALID(args));
2681
2682 status = TrioFormat(&buffer, bufferSize > 0 ? bufferSize - 1 : 0,
2683 TrioOutStreamStringMax, format, args);
2684 if (bufferSize > 0)
2685 *buffer = NIL;
2686 return status;
2687}
2688#endif
2689
2690/*************************************************************************
2691 *
2692 * SCANNING
2693 *
2694 ************************************************************************/
2695
2696/* DV for libxml */
2697#ifndef HAVE_SSCANF
2698
2699/*************************************************************************
2700 * TrioSkipWhitespaces [private]
2701 */
2702static int
2703TrioSkipWhitespaces(trio_T *self)
2704{
2705 int ch;
2706
2707 ch = self->current;
2708 while (isspace(ch))
2709 {
2710 self->InStream(self, &ch);
2711 }
2712 return ch;
2713}
2714
2715/*************************************************************************
2716 * TrioGetCharacterClass [private]
2717 *
2718 * FIXME:
2719 * multibyte
2720 */
2721static int
2722TrioGetCharacterClass(const char *format,
2723 int *indexPointer,
2724 int *flagsPointer,
2725 int *characterclass)
2726{
2727 int index = *indexPointer;
2728 int i;
2729 char ch;
2730 char range_begin;
2731 char range_end;
2732
2733 *flagsPointer &= ~FLAGS_EXCLUDE;
2734
2735 if (format[index] == QUALIFIER_CIRCUMFLEX)
2736 {
2737 *flagsPointer |= FLAGS_EXCLUDE;
2738 index++;
2739 }
2740 /* If the ungroup character is at the beginning of the scanlist,
2741 * it will be part of the class, and a second ungroup character
2742 * must follow to end the group.
2743 */
2744 if (format[index] == SPECIFIER_UNGROUP)
2745 {
2746 characterclass[(int)SPECIFIER_UNGROUP]++;
2747 index++;
2748 }
2749 /* Minus is used to specify ranges. To include minus in the class,
2750 * it must be at the beginning of the list
2751 */
2752 if (format[index] == QUALIFIER_MINUS)
2753 {
2754 characterclass[(int)QUALIFIER_MINUS]++;
2755 index++;
2756 }
2757 /* Collect characters */
2758 for (ch = format[index];
2759 ch != SPECIFIER_UNGROUP && ch != NIL;
2760 ch = format[++index])
2761 {
2762 switch (ch)
2763 {
2764 case QUALIFIER_MINUS: /* Scanlist ranges */
2765
2766 /* Both C99 and UNIX98 describes ranges as implementation-
2767 * defined.
2768 *
2769 * We support the following behaviour (although this may
2770 * change as we become wiser)
2771 * - only increasing ranges, ie. [a-b] but not [b-a]
2772 * - transitive ranges, ie. [a-b-c] == [a-c]
2773 * - trailing minus, ie. [a-] is interpreted as an 'a'
2774 * and a '-'
2775 * - duplicates (although we can easily convert these
2776 * into errors)
2777 */
2778 range_begin = format[index - 1];
2779 range_end = format[++index];
2780 if (range_end == SPECIFIER_UNGROUP)
2781 {
2782 /* Trailing minus is included */
2783 characterclass[(int)ch]++;
2784 ch = range_end;
2785 break; /* for */
2786 }
2787 if (range_end == NIL)
2788 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
2789 if (range_begin > range_end)
2790 return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
2791
2792 for (i = (int)range_begin; i <= (int)range_end; i++)
2793 characterclass[i]++;
2794
2795 ch = range_end;
2796 break;
2797
2798 case QUALIFIER_COLON: /* Character class expressions */
2799
2800 if (StrEqualMax(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
2801 &format[index]))
2802 {
2803 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2804 if (isalnum(i))
2805 characterclass[i]++;
2806 index += sizeof(CLASS_ALNUM) - 1;
2807 }
2808 else if (StrEqualMax(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
2809 &format[index]))
2810 {
2811 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2812 if (isalpha(i))
2813 characterclass[i]++;
2814 index += sizeof(CLASS_ALPHA) - 1;
2815 }
2816 else if (StrEqualMax(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
2817 &format[index]))
2818 {
2819 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2820 if (iscntrl(i))
2821 characterclass[i]++;
2822 index += sizeof(CLASS_CNTRL) - 1;
2823 }
2824 else if (StrEqualMax(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
2825 &format[index]))
2826 {
2827 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2828 if (isdigit(i))
2829 characterclass[i]++;
2830 index += sizeof(CLASS_DIGIT) - 1;
2831 }
2832 else if (StrEqualMax(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
2833 &format[index]))
2834 {
2835 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2836 if (isgraph(i))
2837 characterclass[i]++;
2838 index += sizeof(CLASS_GRAPH) - 1;
2839 }
2840 else if (StrEqualMax(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
2841 &format[index]))
2842 {
2843 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2844 if (islower(i))
2845 characterclass[i]++;
2846 index += sizeof(CLASS_LOWER) - 1;
2847 }
2848 else if (StrEqualMax(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
2849 &format[index]))
2850 {
2851 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2852 if (isprint(i))
2853 characterclass[i]++;
2854 index += sizeof(CLASS_PRINT) - 1;
2855 }
2856 else if (StrEqualMax(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
2857 &format[index]))
2858 {
2859 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2860 if (ispunct(i))
2861 characterclass[i]++;
2862 index += sizeof(CLASS_PUNCT) - 1;
2863 }
2864 else if (StrEqualMax(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
2865 &format[index]))
2866 {
2867 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2868 if (isspace(i))
2869 characterclass[i]++;
2870 index += sizeof(CLASS_SPACE) - 1;
2871 }
2872 else if (StrEqualMax(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
2873 &format[index]))
2874 {
2875 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2876 if (isupper(i))
2877 characterclass[i]++;
2878 index += sizeof(CLASS_UPPER) - 1;
2879 }
2880 else if (StrEqualMax(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
2881 &format[index]))
2882 {
2883 for (i = 0; i < MAX_CHARACTER_CLASS; i++)
2884 if (isxdigit(i))
2885 characterclass[i]++;
2886 index += sizeof(CLASS_XDIGIT) - 1;
2887 }
2888 else
2889 {
2890 characterclass[(int)ch]++;
2891 }
2892 break;
2893
2894 default:
2895 characterclass[(int)ch]++;
2896 break;
2897 }
2898 }
2899 return 0;
2900}
2901
2902/*************************************************************************
2903 * TrioReadNumber [private]
2904 *
2905 * We implement our own number conversion in preference of strtol and
2906 * strtoul, because we must handle 'long long' and thousand separators.
2907 */
2908static BOOLEAN_T
2909TrioReadNumber(trio_T *self, LONGEST *target, int flags, int width, int base)
2910{
2911 LONGEST number = 0;
2912 int digit;
2913 int count;
2914 BOOLEAN_T isNegative = FALSE;
2915 int j;
2916
2917 assert(VALID(self));
2918 assert(VALID(self->InStream));
2919 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
2920
2921 TrioSkipWhitespaces(self);
2922
2923 if (!(flags & FLAGS_UNSIGNED))
2924 {
2925 /* Leading sign */
2926 if (self->current == '+')
2927 {
2928 self->InStream(self, NULL);
2929 }
2930 else if (self->current == '-')
2931 {
2932 self->InStream(self, NULL);
2933 isNegative = TRUE;
2934 }
2935 }
2936
2937 count = self->processed;
2938
2939 if (flags & FLAGS_ALTERNATIVE)
2940 {
2941 switch (base)
2942 {
2943 case NO_BASE:
2944 case BASE_OCTAL:
2945 case BASE_HEX:
2946 case BASE_BINARY:
2947 if (self->current == '0')
2948 {
2949 self->InStream(self, NULL);
2950 if (self->current)
2951 {
2952 if ((base == BASE_HEX) &&
2953 (toupper(self->current) == 'X'))
2954 {
2955 self->InStream(self, NULL);
2956 }
2957 else if ((base == BASE_BINARY) &&
2958 (toupper(self->current) == 'B'))
2959 {
2960 self->InStream(self, NULL);
2961 }
2962 }
2963 }
2964 else
2965 return FALSE;
2966 break;
2967 default:
2968 break;
2969 }
2970 }
2971
2972 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
2973 (! ((self->current == EOF) || isspace(self->current))))
2974 {
2975 if (isascii(self->current))
2976 {
2977 digit = globalDigitArray[self->current];
2978 /* Abort if digit is not allowed in the specified base */
2979 if ((digit == -1) || (digit >= base))
2980 break;
2981 }
2982 else if (flags & FLAGS_QUOTE)
2983 {
2984 /* Compare with thousands separator */
2985 for (j = 0; globalThousandSeparator[j] && self->current; j++)
2986 {
2987 if (globalThousandSeparator[j] != self->current)
2988 break;
2989
2990 self->InStream(self, NULL);
2991 }
2992 if (globalThousandSeparator[j])
2993 break; /* Mismatch */
2994 else
2995 continue; /* Match */
2996 }
2997 else
2998 break;
2999
3000 number *= base;
3001 number += digit;
3002
3003 self->InStream(self, NULL);
3004 }
3005
3006 /* Was anything read at all? */
3007 if (self->processed == count)
3008 return FALSE;
3009
3010 if (target)
3011 *target = (isNegative) ? -number : number;
3012 return TRUE;
3013}
3014
3015/*************************************************************************
3016 * TrioReadChar [private]
3017 */
3018static BOOLEAN_T
3019TrioReadChar(trio_T *self, char *target, int width)
3020{
3021 int i;
3022
3023 assert(VALID(self));
3024 assert(VALID(self->InStream));
3025
3026 for (i = 0;
3027 (self->current != EOF) && (i < width);
3028 i++)
3029 {
3030 if (target)
3031 target[i] = self->current;
3032 self->InStream(self, NULL);
3033 }
3034 return TRUE;
3035}
3036
3037/*************************************************************************
3038 * TrioReadString [private]
3039 */
3040static BOOLEAN_T
3041TrioReadString(trio_T *self, char *target, int flags, int width)
3042{
3043 int i;
3044 char ch;
3045 LONGEST number;
3046
3047 assert(VALID(self));
3048 assert(VALID(self->InStream));
3049
3050 TrioSkipWhitespaces(self);
3051
3052 /* Continue until end of string is reached, a whitespace is encountered,
3053 * or width is exceeded
3054 */
3055 for (i = 0;
3056 ((width == NO_WIDTH) || (i < width)) &&
3057 (! ((self->current == EOF) || isspace(self->current)));
3058 i++)
3059 {
3060 ch = self->current;
3061 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
3062 {
3063 self->InStream(self, NULL);
3064 switch (self->current)
3065 {
3066 case 'a':
3067 ch = '\a';
3068 break;
3069 case 'b':
3070 ch = '\b';
3071 break;
3072 case 'f':
3073 ch = '\f';
3074 break;
3075 case 'n':
3076 ch = '\n';
3077 break;
3078 case 'r':
3079 ch = '\r';
3080 break;
3081 case 't':
3082 ch = '\t';
3083 break;
3084 case 'v':
3085 ch = '\v';
3086 break;
3087 case '\\':
3088 ch = '\\';
3089 break;
3090 default:
3091 if (isdigit(self->current))
3092 {
3093 /* Read octal number */
3094 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
3095 return FALSE;
3096 ch = (char)number;
3097 }
3098 else if (toupper(self->current) == 'X')
3099 {
3100 /* Read hexadecimal number */
3101 self->InStream(self, NULL);
3102 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
3103 return FALSE;
3104 ch = (char)number;
3105 }
3106 else
3107 {
3108 ch = self->current;
3109 }
3110 break;
3111 }
3112 }
3113 if (target)
3114 target[i] = ch;
3115 self->InStream(self, NULL);
3116 }
3117 if (target)
3118 target[i] = NIL;
3119 return TRUE;
3120}
3121
3122/*************************************************************************
3123 * TrioReadGroup [private]
3124 *
3125 * FIXME: characterclass does not work with multibyte characters
3126 */
3127static BOOLEAN_T
3128TrioReadGroup(trio_T *self,
3129 char *target,
3130 int *characterclass,
3131 int flags,
3132 int width)
3133{
3134 unsigned int ch;
3135 int i;
3136
3137 assert(VALID(self));
3138 assert(VALID(self->InStream));
3139
3140 ch = self->current;
3141 for (i = 0;
3142 ((width == NO_WIDTH) || (i < width)) &&
3143 (! ((ch == EOF) ||
3144 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
3145 i++)
3146 {
3147 if (target)
3148 target[i] = (char)ch;
3149 self->InStream(self, &ch);
3150 }
3151
3152 if (target)
3153 target[i] = NIL;
3154 return TRUE;
3155}
3156
3157/*************************************************************************
3158 * TrioReadDouble [private]
3159 *
3160 * FIXME:
3161 * add hex-float format
3162 * add long double
3163 */
3164static BOOLEAN_T
3165TrioReadDouble(trio_T *self,
3166 double *target,
3167 int flags,
3168 int width)
3169{
3170 int ch;
3171 char doubleString[512] = "";
3172 int index = 0;
3173 int start;
3174
3175 if ((width == NO_WIDTH) || (width > sizeof(doubleString) - 1))
3176 width = sizeof(doubleString) - 1;
3177
3178 TrioSkipWhitespaces(self);
3179
3180 /* Read entire double number from stream. StrToDouble requires a
3181 * string as input, but InStream can be anything, so we have to
3182 * collect all characters.
3183 */
3184 ch = self->current;
3185 if ((ch == '+') || (ch == '-'))
3186 {
3187 doubleString[index++] = ch;
3188 self->InStream(self, &ch);
3189 width--;
3190 }
3191
3192 start = index;
3193#if defined(USE_INFINITE) || defined(USE_NAN)
3194 switch (ch)
3195 {
3196#if defined(USE_NAN)
3197 case 'n':
3198 case 'N':
3199 /* Not-a-number */
3200 if (index != 0)
3201 break;
3202 /* FALLTHROUGH */
3203#endif
3204 case 'i':
3205 case 'I':
3206 /* Infinity */
3207 while (isalpha(ch) && (index - start < width))
3208 {
3209 doubleString[index++] = ch;
3210 self->InStream(self, &ch);
3211 }
3212 doubleString[index] = NIL;
3213
3214#if defined(USE_INFINITE)
3215 /* Case insensitive string comparison */
3216 if (StrEqual(&doubleString[start], INFINITE_UPPER) ||
3217 StrEqual(&doubleString[start], LONG_INFINITE_UPPER))
3218 {
3219 *target = ((start == 1 && doubleString[0] == '-'))
3220 ? -HUGE_VAL
3221 : HUGE_VAL;
3222 return TRUE;
3223 }
3224#endif
3225#if defined(USE_NAN)
3226 if (StrEqual(doubleString, NAN_LOWER))
3227 {
3228 /* NaN must not have a preceeding + nor - */
3229 *target = NAN;
3230 return TRUE;
3231 }
3232#endif
3233 return FALSE;
3234
3235 default:
3236 break;
3237 }
3238#endif
3239
3240 while (isdigit(ch) && (index - start < width))
3241 {
3242 /* Integer part */
3243 doubleString[index++] = ch;
3244 self->InStream(self, &ch);
3245 }
3246 if (ch == '.')
3247 {
3248 /* Decimal part */
3249 doubleString[index++] = ch;
3250 self->InStream(self, &ch);
3251 while (isdigit(ch) && (index - start < width))
3252 {
3253 doubleString[index++] = ch;
3254 self->InStream(self, &ch);
3255 }
3256 if ((ch == 'e') || (ch == 'E'))
3257 {
3258 /* Exponent */
3259 doubleString[index++] = ch;
3260 self->InStream(self, &ch);
3261 if ((ch == '+') || (ch == '-'))
3262 {
3263 doubleString[index++] = ch;
3264 self->InStream(self, &ch);
3265 }
3266 while (isdigit(ch) && (index - start < width))
3267 {
3268 doubleString[index++] = ch;
3269 self->InStream(self, &ch);
3270 }
3271 }
3272 }
3273
3274 if ((index == start) || (*doubleString == NIL))
3275 return FALSE;
3276
3277 if (flags & FLAGS_LONGDOUBLE)
3278/* *longdoublePointer = StrToLongDouble()*/;
3279 else
3280 {
3281 *target = StrToDouble(doubleString, NULL);
3282 }
3283 return TRUE;
3284}
3285
3286/*************************************************************************
3287 * TrioReadPointer [private]
3288 */
3289static BOOLEAN_T
3290TrioReadPointer(trio_T *self, void **target, int flags)
3291{
3292 LONGEST number;
3293 char buffer[sizeof(null)];
3294
3295 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
3296
3297 if (TrioReadNumber(self,
3298 &number,
3299 flags,
3300 POINTER_WIDTH,
3301 BASE_HEX))
3302 {
3303 /* The addition is a workaround for a compiler warning */
3304 if (target)
3305 *target = (void *)0 + number;
3306 return TRUE;
3307 }
3308 else if (TrioReadString(self,
3309 (flags & FLAGS_IGNORE)
3310 ? NULL
3311 : buffer,
3312 0,
3313 sizeof(null) - 1))
3314 {
3315 if (StrEqualCase(buffer, null))
3316 {
3317 if (target)
3318 *target = NULL;
3319 return TRUE;
3320 }
3321 }
3322 return FALSE;
3323}
3324
3325/*************************************************************************
3326 * TrioScan [private]
3327 */
3328static int
3329TrioScan(void *source,
3330 size_t sourceSize,
3331 void (*InStream)(trio_T *, int *),
3332 const char *format,
3333 va_list args)
3334{
3335#if defined(USE_MULTIBYTE)
3336 int charlen;
3337#endif
3338 int status;
3339 int assignment;
3340 parameter_T parameters[MAX_PARAMETERS];
3341 trio_T internalData;
3342 trio_T *data;
3343 int ch;
3344 int cnt;
3345 int index; /* Index of format string */
3346 int i; /* Index of current parameter */
3347 int flags;
3348 int width;
3349 int base;
3350 void *pointer;
3351
3352 assert(VALID(InStream));
3353 assert(VALID(format));
3354 assert(VALID(args));
3355
3356 memset(&internalData, 0, sizeof(internalData));
3357 data = &internalData;
3358 data->InStream = InStream;
3359 data->location = source;
3360 data->max = sourceSize;
3361
3362#if defined(USE_LOCALE)
3363 if (NULL == globalLocaleValues)
3364 {
3365 TrioSetLocale();
3366 }
3367#endif
3368 if (globalDigitsUnconverted)
3369 {
3370 memset(globalDigitArray, -1, sizeof(globalDigitArray));
3371 for (i = 0; i < sizeof(globalDigitsLower) - 1; i++)
3372 {
3373 globalDigitArray[(int)globalDigitsLower[i]] = i;
3374 globalDigitArray[(int)globalDigitsUpper[i]] = i;
3375 }
3376 globalDigitsUnconverted = FALSE;
3377 }
3378
3379 status = TrioPreprocess(TYPE_SCAN, format, parameters, args);
3380 if (status < 0)
3381 return status;
3382
3383 assignment = 0;
3384 i = 0;
3385 index = 0;
3386 data->InStream(data, &ch);
3387
3388#if defined(USE_MULTIBYTE)
3389 mblen(NULL, 0);
3390#endif
3391
3392 while (format[index])
3393 {
3394#if defined(USE_MULTIBYTE)
3395 if (! isascii(format[index]))
3396 {
3397 charlen = mblen(&format[index], MB_LEN_MAX);
3398 /* Compare multibyte characters in format string */
3399 for (cnt = 0; cnt < charlen - 1; cnt++)
3400 {
3401 if (ch != format[index + cnt])
3402 {
3403 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
3404 }
3405 data->InStream(data, &ch);
3406 }
3407 continue; /* while */
3408 }
3409#endif
3410 if (EOF == ch)
3411 return EOF;
3412
3413 if (CHAR_IDENTIFIER == format[index])
3414 {
3415 if (CHAR_IDENTIFIER == format[index + 1])
3416 {
3417 /* Two % in format matches one % in input stream */
3418 if (CHAR_IDENTIFIER == ch)
3419 {
3420 data->InStream(data, &ch);
3421 index += 2;
3422 continue; /* while format chars left */
3423 }
3424 else
3425 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
3426 }
3427
3428 /* Skip the parameter entries */
3429 while (parameters[i].type == FORMAT_PARAMETER)
3430 i++;
3431
3432 flags = parameters[i].flags;
3433 /* Find width */
3434 width = parameters[i].width;
3435 if (flags & FLAGS_WIDTH_PARAMETER)
3436 {
3437 /* Get width from parameter list */
3438 width = (int)parameters[width].data.number.asSigned;
3439 }
3440 /* Find base */
3441 base = parameters[i].base;
3442 if (flags & FLAGS_BASE_PARAMETER)
3443 {
3444 /* Get base from parameter list */
3445 base = (int)parameters[base].data.number.asSigned;
3446 }
3447
3448 switch (parameters[i].type)
3449 {
3450 case FORMAT_INT:
3451 {
3452 LONGEST number;
3453
3454 if (0 == base)
3455 base = BASE_DECIMAL;
3456
3457 if (!TrioReadNumber(data,
3458 &number,
3459 flags,
3460 width,
3461 base))
3462 return assignment;
3463 assignment++;
3464
3465 if (!(flags & FLAGS_IGNORE))
3466 {
3467 pointer = parameters[i].data.pointer;
3468#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3469 if (flags & FLAGS_SIZE_T)
3470 *(size_t *)pointer = (size_t)number;
3471 else
3472#endif
3473#if defined(QUALIFIER_PTRDIFF_T)
3474 if (flags & FLAGS_PTRDIFF_T)
3475 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
3476 else
3477#endif
3478#if defined(QUALIFIER_INTMAX_T)
3479 if (flags & FLAGS_INTMAX_T)
3480 *(intmax_t *)pointer = (intmax_t)number;
3481 else
3482#endif
3483 if (flags & FLAGS_QUAD)
3484 *(ULONGLONG int *)pointer = (ULONGLONG)number;
3485 else if (flags & FLAGS_LONG)
3486 *(long int *)pointer = (long int)number;
3487 else if (flags & FLAGS_SHORT)
3488 *(short int *)pointer = (short int)number;
3489 else
3490 *(int *)pointer = (int)number;
3491 }
3492 }
3493 break; /* FORMAT_INT */
3494
3495 case FORMAT_STRING:
3496 if (!TrioReadString(data,
3497 (flags & FLAGS_IGNORE)
3498 ? NULL
3499 : parameters[i].data.string,
3500 flags,
3501 width))
3502 return assignment;
3503 assignment++;
3504 break; /* FORMAT_STRING */
3505
3506 case FORMAT_DOUBLE:
3507 if (!TrioReadDouble(data,
3508 (flags & FLAGS_IGNORE)
3509 ? NULL
3510 : parameters[i].data.doublePointer,
3511 flags,
3512 width))
3513 return assignment;
3514 assignment++;
3515 break; /* FORMAT_DOUBLE */
3516
3517 case FORMAT_GROUP:
3518 {
3519 int characterclass[MAX_CHARACTER_CLASS + 1];
3520 int rc;
3521
3522 index += 2;
3523 memset(characterclass, 0, sizeof(characterclass));
3524 rc = TrioGetCharacterClass(format, &index, &flags,
3525 characterclass);
3526 if (rc < 0)
3527 return rc;
3528
3529 if (!TrioReadGroup(data,
3530 (flags & FLAGS_IGNORE)
3531 ? NULL
3532 : parameters[i].data.string,
3533 characterclass,
3534 flags,
3535 parameters[i].width))
3536 return assignment;
3537 assignment++;
3538 }
3539 break; /* FORMAT_GROUP */
3540
3541 case FORMAT_COUNT:
3542 pointer = parameters[i].data.pointer;
3543 if (NULL != pointer)
3544 {
3545#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
3546 if (flags & FLAGS_SIZE_T)
3547 *(size_t *)pointer = (size_t)data->committed;
3548 else
3549#endif
3550#if defined(QUALIFIER_PTRDIFF_T)
3551 if (flags & FLAGS_PTRDIFF_T)
3552 *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
3553 else
3554#endif
3555#if defined(QUALIFIER_INTMAX_T)
3556 if (flags & FLAGS_INTMAX_T)
3557 *(intmax_t *)pointer = (intmax_t)data->committed;
3558 else
3559#endif
3560 if (flags & FLAGS_QUAD)
3561 {
3562 *(ULONGLONG int *)pointer = (ULONGLONG)data->committed;
3563 }
3564 else if (flags & FLAGS_LONG)
3565 {
3566 *(long int *)pointer = (long int)data->committed;
3567 }
3568 else if (flags & FLAGS_SHORT)
3569 {
3570 *(short int *)pointer = (short int)data->committed;
3571 }
3572 else
3573 {
3574 *(int *)pointer = (int)data->committed;
3575 }
3576 }
3577 break; /* FORMAT_COUNT */
3578
3579 case FORMAT_CHAR:
3580 if (!TrioReadChar(data,
3581 (flags & FLAGS_IGNORE)
3582 ? NULL
3583 : parameters[i].data.string,
3584 (width == NO_WIDTH) ? 1 : width))
3585 return assignment;
3586 assignment++;
3587 break; /* FORMAT_CHAR */
3588
3589 case FORMAT_POINTER:
3590 if (!TrioReadPointer(data,
3591 (flags & FLAGS_IGNORE)
3592 ? NULL
3593 : parameters[i].data.pointer,
3594 flags))
3595 return assignment;
3596 assignment++;
3597 break; /* FORMAT_POINTER */
3598
3599 case FORMAT_PARAMETER:
3600 break; /* FORMAT_PARAMETER */
3601
3602 default:
3603 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
3604 }
3605 ch = data->current;
3606 index = parameters[i].indexAfterSpecifier;
3607 i++;
3608 }
3609 else /* Not an % identifier */
3610 {
3611 if (isspace((int)format[index]))
3612 {
3613 /* Whitespaces may match any amount of whitespaces */
3614 ch = TrioSkipWhitespaces(data);
3615 }
3616 else if (ch == format[index])
3617 {
3618 data->InStream(data, &ch);
3619 }
3620 else
3621 return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
3622
3623 index++;
3624 }
3625 }
3626 return assignment;
3627}
3628
3629/*************************************************************************
3630 * TrioInStreamFile [private]
3631 */
3632static void
3633TrioInStreamFile(trio_T *self, int *intPointer)
3634{
3635 FILE *file = (FILE *)self->location;
3636
3637 assert(VALID(self));
3638 assert(VALID(file));
3639
3640 self->current = fgetc(file);
3641 self->processed++;
3642 self->committed++;
3643
3644 if (VALID(intPointer))
3645 {
3646 *intPointer = self->current;
3647 }
3648}
3649
3650/*************************************************************************
3651 * TrioInStreamFileDescriptor [private]
3652 */
3653static void
3654TrioInStreamFileDescriptor(trio_T *self, int *intPointer)
3655{
3656 int fd = *((int *)self->location);
3657 int size;
3658 unsigned char input;
3659
3660 assert(VALID(self));
3661
3662 size = read(fd, &input, sizeof(char));
3663 self->current = (size == 0) ? EOF : input;
3664 self->processed++;
3665 self->committed++;
3666
3667 if (VALID(intPointer))
3668 {
3669 *intPointer = self->current;
3670 }
3671}
3672
3673/*************************************************************************
3674 * TrioInStreamString [private]
3675 */
3676static void
3677TrioInStreamString(trio_T *self, int *intPointer)
3678{
3679 unsigned char **buffer;
3680
3681 assert(VALID(self));
3682 assert(VALID(self->InStream));
3683 assert(VALID(self->location));
3684
3685 buffer = (unsigned char **)self->location;
3686 self->current = (*buffer)[0];
3687 if (self->current == NIL)
3688 self->current = EOF;
3689 (*buffer)++;
3690 self->processed++;
3691 self->committed++;
3692
3693 if (VALID(intPointer))
3694 {
3695 *intPointer = self->current;
3696 }
3697}
3698
3699/*************************************************************************
3700 * trio_sscanf
3701 */
3702int
3703sscanf(const char *buffer, const char *format, ...)
3704{
3705 int status;
3706 va_list args;
3707
3708 assert(VALID(buffer));
3709 assert(VALID(format));
3710
3711 va_start(args, format);
3712 status = TrioScan(&buffer, 0, TrioInStreamString, format, args);
3713 va_end(args);
3714 return status;
3715}
3716
3717/* DV for libxml */
3718#endif /* !HAVE_SSCANF */
3719#endif /* WITH_TRIO */