~ubuntu-branches/ubuntu/oneiric/bogofilter/oneiric

« back to all changes in this revision

Viewing changes to trio/trio.c

  • Committer: Bazaar Package Importer
  • Author(s): Clint Adams
  • Date: 2004-06-27 09:22:31 UTC
  • Revision ID: james.westby@ubuntu.com-20040627092231-u26smic0nhp7rl4z
Tags: upstream-0.92.0
ImportĀ upstreamĀ versionĀ 0.92.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*************************************************************************
 
2
 *
 
3
 * $Id: trio.c,v 1.2 2003/10/29 14:31:52 m-a Exp $
 
4
 *
 
5
 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
 
6
 *
 
7
 * Permission to use, copy, modify, and distribute this software for any
 
8
 * purpose with or without fee is hereby granted, provided that the above
 
9
 * copyright notice and this permission notice appear in all copies.
 
10
 *
 
11
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 
12
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 
13
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
 
14
 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
 
15
 *
 
16
 *************************************************************************
 
17
 *
 
18
 * A note to trio contributors:
 
19
 *
 
20
 * Avoid heap allocation at all costs to ensure that the trio functions
 
21
 * are async-safe. The exceptions are the printf/fprintf functions, which
 
22
 * uses fputc, and the asprintf functions and the <alloc> modifier, which
 
23
 * by design are required to allocate form the heap.
 
24
 *
 
25
 ************************************************************************/
 
26
 
 
27
/*
 
28
 * TODO:
 
29
 *  - Scan is probably too permissive about its modifiers.
 
30
 *  - C escapes in %#[] ?
 
31
 *  - Multibyte characters (done for format parsing, except scan groups)
 
32
 *  - Complex numbers? (C99 _Complex)
 
33
 *  - Boolean values? (C99 _Bool)
 
34
 *  - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
 
35
 *    to print the mantissa, e.g. NaN(0xc000000000000000)
 
36
 *  - Should we support the GNU %a alloc modifier? GNU has an ugly hack
 
37
 *    for %a, because C99 used %a for other purposes. If specified as
 
38
 *    %as or %a[ it is interpreted as the alloc modifier, otherwise as
 
39
 *    the C99 hex-float. This means that you cannot scan %as as a hex-float
 
40
 *    immediately followed by an 's'.
 
41
 *  - Scanning of collating symbols.
 
42
 */
 
43
 
 
44
/*************************************************************************
 
45
 * Trio include files
 
46
 */
 
47
#include "triodef.h"
 
48
#include "trio.h"
 
49
#include "triop.h"
 
50
#include "trionan.h"
 
51
#if !defined(TRIO_MINIMAL)
 
52
# include "triostr.h"
 
53
#endif
 
54
 
 
55
/**************************************************************************
 
56
 *
 
57
 * Definitions
 
58
 *
 
59
 *************************************************************************/
 
60
 
 
61
#include <math.h>
 
62
#include <limits.h>
 
63
#include <float.h>
 
64
 
 
65
#if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_WIDECHAR
 
66
# define TRIO_COMPILER_SUPPORTS_MULTIBYTE
 
67
# if !defined(MB_LEN_MAX)
 
68
#  define MB_LEN_MAX 6
 
69
# endif
 
70
#endif
 
71
 
 
72
#if (defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1100)) || defined(TRIO_COMPILER_BCB)
 
73
# define TRIO_COMPILER_SUPPORTS_MSVC_INT
 
74
#endif
 
75
 
 
76
/*************************************************************************
 
77
 * Generic definitions
 
78
 */
 
79
 
 
80
#if !(defined(DEBUG) || defined(NDEBUG))
 
81
# define NDEBUG
 
82
#endif
 
83
 
 
84
#include <assert.h>
 
85
#include <ctype.h>
 
86
#if !defined(TRIO_COMPILER_SUPPORTS_C99)
 
87
# define isblank(x) (((x)==32) || ((x)==9))
 
88
#endif
 
89
#if defined(TRIO_COMPILER_ANCIENT)
 
90
# include <varargs.h>
 
91
#else
 
92
# include <stdarg.h>
 
93
#endif
 
94
#include <stddef.h>
 
95
#include <errno.h>
 
96
 
 
97
#ifndef NULL
 
98
# define NULL 0
 
99
#endif
 
100
#define NIL ((char)0)
 
101
#ifndef FALSE
 
102
# define FALSE (1 == 0)
 
103
# define TRUE (! FALSE)
 
104
#endif
 
105
#define BOOLEAN_T int
 
106
 
 
107
/* mincore() can be used for debugging purposes */
 
108
#define VALID(x) (NULL != (x))
 
109
 
 
110
#if TRIO_ERRORS
 
111
  /*
 
112
   * Encode the error code and the position. This is decoded
 
113
   * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
 
114
   */
 
115
# define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
 
116
#else
 
117
# define TRIO_ERROR_RETURN(x,y) (-1)
 
118
#endif
 
119
 
 
120
typedef unsigned long trio_flags_t;
 
121
 
 
122
 
 
123
/*************************************************************************
 
124
 * Platform specific definitions
 
125
 */
 
126
#if defined(TRIO_PLATFORM_UNIX)
 
127
# include <unistd.h>
 
128
# include <signal.h>
 
129
# include <locale.h>
 
130
# define USE_LOCALE
 
131
#endif /* TRIO_PLATFORM_UNIX */
 
132
#if defined(TRIO_PLATFORM_VMS)
 
133
# include <unistd.h>
 
134
#endif
 
135
#if defined(TRIO_PLATFORM_WIN32)
 
136
# include <io.h>
 
137
# define read _read
 
138
# define write _write
 
139
#endif /* TRIO_PLATFORM_WIN32 */
 
140
 
 
141
#if TRIO_WIDECHAR
 
142
# if defined(TRIO_COMPILER_SUPPORTS_ISO94)
 
143
#  include <wchar.h>
 
144
#  include <wctype.h>
 
145
typedef wchar_t trio_wchar_t;
 
146
typedef wint_t trio_wint_t;
 
147
# else
 
148
typedef char trio_wchar_t;
 
149
typedef int trio_wint_t;
 
150
#  define WCONST(x) L ## x
 
151
#  define WEOF EOF
 
152
#  define iswalnum(x) isalnum(x)
 
153
#  define iswalpha(x) isalpha(x)
 
154
#  define iswblank(x) isblank(x)
 
155
#  define iswcntrl(x) iscntrl(x)
 
156
#  define iswdigit(x) isdigit(x)
 
157
#  define iswgraph(x) isgraph(x)
 
158
#  define iswlower(x) islower(x)
 
159
#  define iswprint(x) isprint(x)
 
160
#  define iswpunct(x) ispunct(x)
 
161
#  define iswspace(x) isspace(x)
 
162
#  define iswupper(x) isupper(x)
 
163
#  define iswxdigit(x) isxdigit(x)
 
164
# endif
 
165
#endif
 
166
 
 
167
 
 
168
/*************************************************************************
 
169
 * Compiler dependent definitions
 
170
 */
 
171
 
 
172
/* Support for long long */
 
173
#ifndef __cplusplus
 
174
# if !defined(USE_LONGLONG)
 
175
#  if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
 
176
#   define USE_LONGLONG
 
177
#  elif defined(TRIO_COMPILER_SUNPRO)
 
178
#   define USE_LONGLONG
 
179
#  elif defined(_LONG_LONG) || defined(_LONGLONG)
 
180
#   define USE_LONGLONG
 
181
#  endif
 
182
# endif
 
183
#endif
 
184
 
 
185
/* The extra long numbers */
 
186
#if defined(USE_LONGLONG)
 
187
typedef signed long long int trio_longlong_t;
 
188
typedef unsigned long long int trio_ulonglong_t;
 
189
#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
 
190
typedef signed __int64 trio_longlong_t;
 
191
typedef unsigned __int64 trio_ulonglong_t;
 
192
#else
 
193
typedef TRIO_SIGNED long int trio_longlong_t;
 
194
typedef unsigned long int trio_ulonglong_t;
 
195
#endif
 
196
 
 
197
/* Maximal and fixed integer types */
 
198
#if defined(TRIO_COMPILER_SUPPORTS_C99)
 
199
# include <stdint.h>
 
200
typedef intmax_t trio_intmax_t;
 
201
typedef uintmax_t trio_uintmax_t;
 
202
typedef int8_t trio_int8_t;
 
203
typedef int16_t trio_int16_t;
 
204
typedef int32_t trio_int32_t;
 
205
typedef int64_t trio_int64_t;
 
206
#elif defined(TRIO_COMPILER_SUPPORTS_UNIX98)
 
207
# include <inttypes.h>
 
208
typedef intmax_t trio_intmax_t;
 
209
typedef uintmax_t trio_uintmax_t;
 
210
typedef int8_t trio_int8_t;
 
211
typedef int16_t trio_int16_t;
 
212
typedef int32_t trio_int32_t;
 
213
typedef int64_t trio_int64_t;
 
214
#elif defined(TRIO_COMPILER_SUPPORTS_MSVC_INT)
 
215
typedef trio_longlong_t trio_intmax_t;
 
216
typedef trio_ulonglong_t trio_uintmax_t;
 
217
typedef __int8 trio_int8_t;
 
218
typedef __int16 trio_int16_t;
 
219
typedef __int32 trio_int32_t;
 
220
typedef __int64 trio_int64_t;
 
221
#else
 
222
typedef trio_longlong_t trio_intmax_t;
 
223
typedef trio_ulonglong_t trio_uintmax_t;
 
224
# if defined(TRIO_INT8_T)
 
225
typedef TRIO_INT8_T trio_int8_t;
 
226
# else
 
227
typedef TRIO_SIGNED char trio_int8_t;
 
228
# endif
 
229
# if defined(TRIO_INT16_T)
 
230
typedef TRIO_INT16_T trio_int16_t;
 
231
# else
 
232
typedef TRIO_SIGNED short trio_int16_t;
 
233
# endif
 
234
# if defined(TRIO_INT32_T)
 
235
typedef TRIO_INT32_T trio_int32_t;
 
236
# else
 
237
typedef TRIO_SIGNED int trio_int32_t;
 
238
# endif
 
239
# if defined(TRIO_INT64_T)
 
240
typedef TRIO_INT64_T trio_int64_t;
 
241
# else
 
242
typedef trio_longlong_t trio_int64_t;
 
243
# endif
 
244
#endif
 
245
 
 
246
#if !(defined(TRIO_COMPILER_SUPPORTS_C99) \
 
247
 || defined(TRIO_COMPILER_SUPPORTS_UNIX01))
 
248
# define floorl(x) floor((double)(x))
 
249
# define fmodl(x,y) fmod((double)(x),(double)(y))
 
250
# define powl(x,y) pow((double)(x),(double)(y))
 
251
#endif
 
252
 
 
253
#define TRIO_FABS(x) (((x) < 0.0) ? -(x) : (x))
 
254
 
 
255
/*************************************************************************
 
256
 * Internal Definitions
 
257
 */
 
258
 
 
259
#ifndef DECIMAL_DIG
 
260
# define DECIMAL_DIG DBL_DIG
 
261
#endif
 
262
 
 
263
/* Long double sizes */
 
264
#ifdef LDBL_DIG
 
265
# define MAX_MANTISSA_DIGITS LDBL_DIG
 
266
# define MAX_EXPONENT_DIGITS 4
 
267
# define MAX_DOUBLE_DIGITS LDBL_MAX_10_EXP
 
268
#else
 
269
# define MAX_MANTISSA_DIGITS DECIMAL_DIG
 
270
# define MAX_EXPONENT_DIGITS 3
 
271
# define MAX_DOUBLE_DIGITS DBL_MAX_10_EXP
 
272
#endif
 
273
 
 
274
#if defined(TRIO_COMPILER_ANCIENT) || !defined(LDBL_DIG)
 
275
# undef LDBL_DIG
 
276
# undef LDBL_MANT_DIG
 
277
# undef LDBL_EPSILON
 
278
# define LDBL_DIG DBL_DIG
 
279
# define LDBL_MANT_DIG DBL_MANT_DIG
 
280
# define LDBL_EPSILON DBL_EPSILON
 
281
#endif
 
282
 
 
283
/* The maximal number of digits is for base 2 */
 
284
#define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
 
285
/* The width of a pointer. The number of bits in a hex digit is 4 */
 
286
#define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
 
287
 
 
288
/* Infinite and Not-A-Number for floating-point */
 
289
#define INFINITE_LOWER "inf"
 
290
#define INFINITE_UPPER "INF"
 
291
#define LONG_INFINITE_LOWER "infinite"
 
292
#define LONG_INFINITE_UPPER "INFINITE"
 
293
#define NAN_LOWER "nan"
 
294
#define NAN_UPPER "NAN"
 
295
 
 
296
/* Various constants */
 
297
enum {
 
298
  TYPE_PRINT = 1,
 
299
  TYPE_SCAN  = 2,
 
300
 
 
301
  /* Flags. FLAGS_LAST must be less than ULONG_MAX */
 
302
  FLAGS_NEW                 = 0,
 
303
  FLAGS_STICKY              = 1,
 
304
  FLAGS_SPACE               = 2 * FLAGS_STICKY,
 
305
  FLAGS_SHOWSIGN            = 2 * FLAGS_SPACE,
 
306
  FLAGS_LEFTADJUST          = 2 * FLAGS_SHOWSIGN,
 
307
  FLAGS_ALTERNATIVE         = 2 * FLAGS_LEFTADJUST,
 
308
  FLAGS_SHORT               = 2 * FLAGS_ALTERNATIVE,
 
309
  FLAGS_SHORTSHORT          = 2 * FLAGS_SHORT,
 
310
  FLAGS_LONG                = 2 * FLAGS_SHORTSHORT,
 
311
  FLAGS_QUAD                = 2 * FLAGS_LONG,
 
312
  FLAGS_LONGDOUBLE          = 2 * FLAGS_QUAD,
 
313
  FLAGS_SIZE_T              = 2 * FLAGS_LONGDOUBLE,
 
314
  FLAGS_PTRDIFF_T           = 2 * FLAGS_SIZE_T,
 
315
  FLAGS_INTMAX_T            = 2 * FLAGS_PTRDIFF_T,
 
316
  FLAGS_NILPADDING          = 2 * FLAGS_INTMAX_T,
 
317
  FLAGS_UNSIGNED            = 2 * FLAGS_NILPADDING,
 
318
  FLAGS_UPPER               = 2 * FLAGS_UNSIGNED,
 
319
  FLAGS_WIDTH               = 2 * FLAGS_UPPER,
 
320
  FLAGS_WIDTH_PARAMETER     = 2 * FLAGS_WIDTH,
 
321
  FLAGS_PRECISION           = 2 * FLAGS_WIDTH_PARAMETER,
 
322
  FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
 
323
  FLAGS_BASE                = 2 * FLAGS_PRECISION_PARAMETER,
 
324
  FLAGS_BASE_PARAMETER      = 2 * FLAGS_BASE,
 
325
  FLAGS_FLOAT_E             = 2 * FLAGS_BASE_PARAMETER,
 
326
  FLAGS_FLOAT_G             = 2 * FLAGS_FLOAT_E,
 
327
  FLAGS_QUOTE               = 2 * FLAGS_FLOAT_G,
 
328
  FLAGS_WIDECHAR            = 2 * FLAGS_QUOTE,
 
329
  FLAGS_ALLOC               = 2 * FLAGS_WIDECHAR,
 
330
  FLAGS_IGNORE              = 2 * FLAGS_ALLOC,
 
331
  FLAGS_IGNORE_PARAMETER    = 2 * FLAGS_IGNORE,
 
332
  FLAGS_VARSIZE_PARAMETER   = 2 * FLAGS_IGNORE_PARAMETER,
 
333
  FLAGS_FIXED_SIZE          = 2 * FLAGS_VARSIZE_PARAMETER,
 
334
  FLAGS_LAST                = FLAGS_FIXED_SIZE,
 
335
  /* Reused flags */
 
336
  FLAGS_EXCLUDE             = FLAGS_SHORT,
 
337
  FLAGS_USER_DEFINED        = FLAGS_IGNORE,
 
338
  FLAGS_ROUNDING            = FLAGS_INTMAX_T,
 
339
  /* Compounded flags */
 
340
  FLAGS_ALL_VARSIZES        = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
 
341
  FLAGS_ALL_SIZES           = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
 
342
 
 
343
  NO_POSITION  = -1,
 
344
  NO_WIDTH     =  0,
 
345
  NO_PRECISION = -1,
 
346
  NO_SIZE      = -1,
 
347
 
 
348
  /* Do not change these */
 
349
  NO_BASE      = -1,
 
350
  MIN_BASE     =  2,
 
351
  MAX_BASE     = 36,
 
352
  BASE_BINARY  =  2,
 
353
  BASE_OCTAL   =  8,
 
354
  BASE_DECIMAL = 10,
 
355
  BASE_HEX     = 16,
 
356
 
 
357
  /* Maximal number of allowed parameters */
 
358
  MAX_PARAMETERS = 64,
 
359
  /* Maximal number of characters in class */
 
360
  MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
 
361
 
 
362
  /* Maximal string lengths for user-defined specifiers */
 
363
  MAX_USER_NAME = 64,
 
364
  MAX_USER_DATA = 256,
 
365
  
 
366
  /* Maximal length of locale separator strings */
 
367
  MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
 
368
  /* Maximal number of integers in grouping */
 
369
  MAX_LOCALE_GROUPS = 64,
 
370
 
 
371
  /* Initial size of asprintf buffer */
 
372
  DYNAMIC_START_SIZE = 32
 
373
};
 
374
 
 
375
#define NO_GROUPING ((int)CHAR_MAX)
 
376
 
 
377
/* Fundamental formatting parameter types */
 
378
#define FORMAT_UNKNOWN   0
 
379
#define FORMAT_INT       1
 
380
#define FORMAT_DOUBLE    2
 
381
#define FORMAT_CHAR      3
 
382
#define FORMAT_STRING    4
 
383
#define FORMAT_POINTER   5
 
384
#define FORMAT_COUNT     6
 
385
#define FORMAT_PARAMETER 7
 
386
#define FORMAT_GROUP     8
 
387
#if TRIO_GNU
 
388
# define FORMAT_ERRNO    9
 
389
#endif
 
390
#if TRIO_EXTENSION
 
391
# define FORMAT_USER_DEFINED 10
 
392
#endif
 
393
 
 
394
/* Character constants */
 
395
#define CHAR_IDENTIFIER '%'
 
396
#define CHAR_BACKSLASH '\\'
 
397
#define CHAR_QUOTE '\"'
 
398
#define CHAR_ADJUST ' '
 
399
 
 
400
/* Character class expressions */
 
401
#define CLASS_ALNUM "[:alnum:]"
 
402
#define CLASS_ALPHA "[:alpha:]"
 
403
#define CLASS_BLANK "[:blank:]"
 
404
#define CLASS_CNTRL "[:cntrl:]"
 
405
#define CLASS_DIGIT "[:digit:]"
 
406
#define CLASS_GRAPH "[:graph:]"
 
407
#define CLASS_LOWER "[:lower:]"
 
408
#define CLASS_PRINT "[:print:]"
 
409
#define CLASS_PUNCT "[:punct:]"
 
410
#define CLASS_SPACE "[:space:]"
 
411
#define CLASS_UPPER "[:upper:]"
 
412
#define CLASS_XDIGIT "[:xdigit:]"
 
413
 
 
414
/*
 
415
 * SPECIFIERS:
 
416
 *
 
417
 *
 
418
 * a  Hex-float
 
419
 * A  Hex-float
 
420
 * c  Character
 
421
 * C  Widechar character (wint_t)
 
422
 * d  Decimal
 
423
 * e  Float
 
424
 * E  Float
 
425
 * F  Float
 
426
 * F  Float
 
427
 * g  Float
 
428
 * G  Float
 
429
 * i  Integer
 
430
 * m  Error message
 
431
 * n  Count
 
432
 * o  Octal
 
433
 * p  Pointer
 
434
 * s  String
 
435
 * S  Widechar string (wchar_t *)
 
436
 * u  Unsigned
 
437
 * x  Hex
 
438
 * X  Hex
 
439
 * [] Group
 
440
 * <> User-defined
 
441
 *
 
442
 * Reserved:
 
443
 *
 
444
 * D  Binary Coded Decimal %D(length,precision) (OS/390)
 
445
 */
 
446
#define SPECIFIER_CHAR 'c'
 
447
#define SPECIFIER_STRING 's'
 
448
#define SPECIFIER_DECIMAL 'd'
 
449
#define SPECIFIER_INTEGER 'i'
 
450
#define SPECIFIER_UNSIGNED 'u'
 
451
#define SPECIFIER_OCTAL 'o'
 
452
#define SPECIFIER_HEX 'x'
 
453
#define SPECIFIER_HEX_UPPER 'X'
 
454
#define SPECIFIER_FLOAT_E 'e'
 
455
#define SPECIFIER_FLOAT_E_UPPER 'E'
 
456
#define SPECIFIER_FLOAT_F 'f'
 
457
#define SPECIFIER_FLOAT_F_UPPER 'F'
 
458
#define SPECIFIER_FLOAT_G 'g'
 
459
#define SPECIFIER_FLOAT_G_UPPER 'G'
 
460
#define SPECIFIER_POINTER 'p'
 
461
#define SPECIFIER_GROUP '['
 
462
#define SPECIFIER_UNGROUP ']'
 
463
#define SPECIFIER_COUNT 'n'
 
464
#if TRIO_UNIX98
 
465
# define SPECIFIER_CHAR_UPPER 'C'
 
466
# define SPECIFIER_STRING_UPPER 'S'
 
467
#endif
 
468
#if TRIO_C99
 
469
# define SPECIFIER_HEXFLOAT 'a'
 
470
# define SPECIFIER_HEXFLOAT_UPPER 'A'
 
471
#endif
 
472
#if TRIO_GNU
 
473
# define SPECIFIER_ERRNO 'm'
 
474
#endif
 
475
#if TRIO_EXTENSION
 
476
# define SPECIFIER_BINARY 'b'
 
477
# define SPECIFIER_BINARY_UPPER 'B'
 
478
# define SPECIFIER_USER_DEFINED_BEGIN '<'
 
479
# define SPECIFIER_USER_DEFINED_END '>'
 
480
# define SPECIFIER_USER_DEFINED_SEPARATOR ':'
 
481
#endif
 
482
 
 
483
/*
 
484
 * QUALIFIERS:
 
485
 *
 
486
 *
 
487
 * Numbers = d,i,o,u,x,X
 
488
 * Float = a,A,e,E,f,F,g,G
 
489
 * String = s
 
490
 * Char = c
 
491
 *
 
492
 *
 
493
 * 9$ Position
 
494
 *      Use the 9th parameter. 9 can be any number between 1 and
 
495
 *      the maximal argument
 
496
 *
 
497
 * 9 Width
 
498
 *      Set width to 9. 9 can be any number, but must not be postfixed
 
499
 *      by '$'
 
500
 *
 
501
 * h  Short
 
502
 *    Numbers:
 
503
 *      (unsigned) short int
 
504
 *
 
505
 * hh Short short
 
506
 *    Numbers:
 
507
 *      (unsigned) char
 
508
 *
 
509
 * l  Long
 
510
 *    Numbers:
 
511
 *      (unsigned) long int
 
512
 *    String:
 
513
 *      as the S specifier
 
514
 *    Char:
 
515
 *      as the C specifier
 
516
 *
 
517
 * ll Long Long
 
518
 *    Numbers:
 
519
 *      (unsigned) long long int
 
520
 *
 
521
 * L  Long Double
 
522
 *    Float
 
523
 *      long double
 
524
 *
 
525
 * #  Alternative
 
526
 *    Float:
 
527
 *      Decimal-point is always present
 
528
 *    String:
 
529
 *      non-printable characters are handled as \number
 
530
 *
 
531
 *    Spacing
 
532
 *
 
533
 * +  Sign
 
534
 *
 
535
 * -  Alignment
 
536
 *
 
537
 * .  Precision
 
538
 *
 
539
 * *  Parameter
 
540
 *    print: use parameter
 
541
 *    scan: no parameter (ignore)
 
542
 *
 
543
 * q  Quad
 
544
 *
 
545
 * Z  size_t
 
546
 *
 
547
 * w  Widechar
 
548
 *
 
549
 * '  Thousands/quote
 
550
 *    Numbers:
 
551
 *      Integer part grouped in thousands
 
552
 *    Binary numbers:
 
553
 *      Number grouped in nibbles (4 bits)
 
554
 *    String:
 
555
 *      Quoted string
 
556
 *
 
557
 * j  intmax_t
 
558
 * t  prtdiff_t
 
559
 * z  size_t
 
560
 *
 
561
 * !  Sticky
 
562
 * @  Parameter (for both print and scan)
 
563
 *
 
564
 * I  n-bit Integer
 
565
 *    Numbers:
 
566
 *      The following options exists
 
567
 *        I8  = 8-bit integer
 
568
 *        I16 = 16-bit integer
 
569
 *        I32 = 32-bit integer
 
570
 *        I64 = 64-bit integer
 
571
 */
 
572
#define QUALIFIER_POSITION '$'
 
573
#define QUALIFIER_SHORT 'h'
 
574
#define QUALIFIER_LONG 'l'
 
575
#define QUALIFIER_LONG_UPPER 'L'
 
576
#define QUALIFIER_ALTERNATIVE '#'
 
577
#define QUALIFIER_SPACE ' '
 
578
#define QUALIFIER_PLUS '+'
 
579
#define QUALIFIER_MINUS '-'
 
580
#define QUALIFIER_DOT '.'
 
581
#define QUALIFIER_STAR '*'
 
582
#define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
 
583
#if TRIO_C99
 
584
# define QUALIFIER_SIZE_T 'z'
 
585
# define QUALIFIER_PTRDIFF_T 't'
 
586
# define QUALIFIER_INTMAX_T 'j'
 
587
#endif
 
588
#if TRIO_BSD || TRIO_GNU
 
589
# define QUALIFIER_QUAD 'q'
 
590
#endif
 
591
#if TRIO_GNU
 
592
# define QUALIFIER_SIZE_T_UPPER 'Z'
 
593
#endif
 
594
#if TRIO_MISC
 
595
# define QUALIFIER_WIDECHAR 'w'
 
596
#endif
 
597
#if TRIO_MICROSOFT
 
598
# define QUALIFIER_FIXED_SIZE 'I'
 
599
#endif
 
600
#if TRIO_EXTENSION
 
601
# define QUALIFIER_QUOTE '\''
 
602
# define QUALIFIER_STICKY '!'
 
603
# define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
 
604
# define QUALIFIER_PARAM '@' /* Experimental */
 
605
# define QUALIFIER_COLON ':' /* For scanlists */
 
606
# define QUALIFIER_EQUAL '=' /* For scanlists */
 
607
# define QUALIFIER_ROUNDING_UPPER 'R'
 
608
#endif
 
609
 
 
610
 
 
611
/*************************************************************************
 
612
 *
 
613
 * Internal Structures
 
614
 *
 
615
 *************************************************************************/
 
616
 
 
617
/* Parameters */
 
618
typedef struct {
 
619
  /* An indication of which entry in the data union is used */
 
620
  int type;
 
621
  /* The flags */
 
622
  trio_flags_t flags;
 
623
  /* The width qualifier */
 
624
  int width;
 
625
  /* The precision qualifier */
 
626
  int precision;
 
627
  /* The base qualifier */
 
628
  int base;
 
629
  /* The size for the variable size qualifier */
 
630
  int varsize;
 
631
  /* The marker of the end of the specifier */
 
632
  int indexAfterSpecifier;
 
633
  /* The data from the argument list */
 
634
  union {
 
635
    char *string;
 
636
#if TRIO_WIDECHAR
 
637
    trio_wchar_t *wstring;
 
638
#endif
 
639
    trio_pointer_t pointer;
 
640
    union {
 
641
      trio_intmax_t as_signed;
 
642
      trio_uintmax_t as_unsigned;
 
643
    } number;
 
644
    double doubleNumber;
 
645
    double *doublePointer;
 
646
    trio_long_double_t longdoubleNumber;
 
647
    trio_long_double_t *longdoublePointer;
 
648
    int errorNumber;
 
649
  } data;
 
650
  /* For the user-defined specifier */
 
651
  char user_name[MAX_USER_NAME];
 
652
  char user_data[MAX_USER_DATA];
 
653
} trio_parameter_t;
 
654
 
 
655
/* Container for customized functions */
 
656
typedef struct {
 
657
  union {
 
658
    trio_outstream_t out;
 
659
    trio_instream_t in;
 
660
  } stream;
 
661
  trio_pointer_t closure;
 
662
} trio_custom_t;
 
663
 
 
664
/* General trio "class" */
 
665
typedef struct _trio_class_t {
 
666
  /*
 
667
   * The function to write characters to a stream.
 
668
   */
 
669
  void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
 
670
  /*
 
671
   * The function to read characters from a stream.
 
672
   */
 
673
  void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
 
674
  /*
 
675
   * The current location in the stream.
 
676
   */
 
677
  trio_pointer_t location;
 
678
  /*
 
679
   * The character currently being processed.
 
680
   */
 
681
  int current;
 
682
  /*
 
683
   * The number of characters that would have been written/read
 
684
   * if there had been sufficient space.
 
685
   */
 
686
  int processed;
 
687
  /*
 
688
   * The number of characters that are actually written/read.
 
689
   * Processed and committed will only differ for the *nprintf
 
690
   * and *nscanf functions.
 
691
   */
 
692
  int committed;
 
693
  /*
 
694
   * The upper limit of characters that may be written/read.
 
695
   */
 
696
  int max;
 
697
  /*
 
698
   * The last output error that was detected.
 
699
   */
 
700
  int error;
 
701
} trio_class_t;
 
702
 
 
703
/* References (for user-defined callbacks) */
 
704
typedef struct _trio_reference_t {
 
705
  trio_class_t *data;
 
706
  trio_parameter_t *parameter;
 
707
} trio_reference_t;
 
708
 
 
709
/* Registered entries (for user-defined callbacks) */
 
710
typedef struct _trio_userdef_t {
 
711
  struct _trio_userdef_t *next;
 
712
  trio_callback_t callback;
 
713
  char *name;
 
714
} trio_userdef_t;
 
715
 
 
716
/*************************************************************************
 
717
 *
 
718
 * Internal Variables
 
719
 *
 
720
 *************************************************************************/
 
721
 
 
722
static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.2 2003/10/29 14:31:52 m-a Exp $";
 
723
 
 
724
/*
 
725
 * Need this to workaround a parser bug in HP C/iX compiler that fails
 
726
 * to resolves macro definitions that includes type 'long double',
 
727
 * e.g: va_arg(arg_ptr, long double)
 
728
 */
 
729
#if defined(TRIO_PLATFORM_MPEIX)
 
730
static TRIO_CONST trio_long_double_t ___dummy_long_double = 0;
 
731
#endif
 
732
 
 
733
static TRIO_CONST char internalNullString[] = "(nil)";
 
734
 
 
735
#if defined(USE_LOCALE)
 
736
static struct lconv *internalLocaleValues = NULL;
 
737
#endif
 
738
 
 
739
/*
 
740
 * UNIX98 says "in a locale where the radix character is not defined,
 
741
 * the radix character defaults to a period (.)"
 
742
 */
 
743
static int internalDecimalPointLength = 1;
 
744
static int internalThousandSeparatorLength = 1;
 
745
static char internalDecimalPoint = '.';
 
746
static char internalDecimalPointString[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ".";
 
747
static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
 
748
static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
 
749
 
 
750
static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
 
751
static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
752
static BOOLEAN_T internalDigitsUnconverted = TRUE;
 
753
static int internalDigitArray[128];
 
754
#if TRIO_EXTENSION
 
755
static BOOLEAN_T internalCollationUnconverted = TRUE;
 
756
static char internalCollationArray[MAX_CHARACTER_CLASS][MAX_CHARACTER_CLASS];
 
757
#endif
 
758
 
 
759
#if TRIO_EXTENSION
 
760
static TRIO_VOLATILE trio_callback_t internalEnterCriticalRegion = NULL;
 
761
static TRIO_VOLATILE trio_callback_t internalLeaveCriticalRegion = NULL;
 
762
static trio_userdef_t *internalUserDef = NULL;
 
763
#endif
 
764
 
 
765
 
 
766
/*************************************************************************
 
767
 *
 
768
 * Internal Functions
 
769
 *
 
770
 ************************************************************************/
 
771
 
 
772
#if defined(TRIO_MINIMAL)
 
773
# define TRIO_STRING_PUBLIC static
 
774
# include "triostr.c"
 
775
#endif /* defined(TRIO_MINIMAL) */
 
776
 
 
777
/*************************************************************************
 
778
 * TrioIsQualifier
 
779
 *
 
780
 * Description:
 
781
 *  Remember to add all new qualifiers to this function.
 
782
 *  QUALIFIER_POSITION must not be added.
 
783
 */
 
784
TRIO_PRIVATE BOOLEAN_T
 
785
TrioIsQualifier
 
786
TRIO_ARGS1((character),
 
787
           TRIO_CONST char character)
 
788
{
 
789
  /* QUALIFIER_POSITION is not included */
 
790
  switch (character)
 
791
    {
 
792
    case '0': case '1': case '2': case '3': case '4':
 
793
    case '5': case '6': case '7': case '8': case '9':
 
794
    case QUALIFIER_PLUS:
 
795
    case QUALIFIER_MINUS:
 
796
    case QUALIFIER_SPACE:
 
797
    case QUALIFIER_DOT:
 
798
    case QUALIFIER_STAR:
 
799
    case QUALIFIER_ALTERNATIVE:
 
800
    case QUALIFIER_SHORT:
 
801
    case QUALIFIER_LONG:
 
802
    case QUALIFIER_LONG_UPPER:
 
803
    case QUALIFIER_CIRCUMFLEX:
 
804
#if defined(QUALIFIER_SIZE_T)
 
805
    case QUALIFIER_SIZE_T:
 
806
#endif
 
807
#if defined(QUALIFIER_PTRDIFF_T)
 
808
    case QUALIFIER_PTRDIFF_T:
 
809
#endif
 
810
#if defined(QUALIFIER_INTMAX_T)
 
811
    case QUALIFIER_INTMAX_T:
 
812
#endif
 
813
#if defined(QUALIFIER_QUAD)
 
814
    case QUALIFIER_QUAD:
 
815
#endif
 
816
#if defined(QUALIFIER_SIZE_T_UPPER)
 
817
    case QUALIFIER_SIZE_T_UPPER:
 
818
#endif
 
819
#if defined(QUALIFIER_WIDECHAR)
 
820
    case QUALIFIER_WIDECHAR:
 
821
#endif
 
822
#if defined(QUALIFIER_QUOTE)
 
823
    case QUALIFIER_QUOTE:
 
824
#endif
 
825
#if defined(QUALIFIER_STICKY)
 
826
    case QUALIFIER_STICKY:
 
827
#endif
 
828
#if defined(QUALIFIER_VARSIZE)
 
829
    case QUALIFIER_VARSIZE:
 
830
#endif
 
831
#if defined(QUALIFIER_PARAM)
 
832
    case QUALIFIER_PARAM:
 
833
#endif
 
834
#if defined(QUALIFIER_FIXED_SIZE)
 
835
    case QUALIFIER_FIXED_SIZE:
 
836
#endif
 
837
#if defined(QUALIFIER_ROUNDING_UPPER)
 
838
    case QUALIFIER_ROUNDING_UPPER:
 
839
#endif
 
840
      return TRUE;
 
841
    default:
 
842
      return FALSE;
 
843
    }
 
844
}
 
845
 
 
846
/*************************************************************************
 
847
 * TrioSetLocale
 
848
 */
 
849
#if defined(USE_LOCALE)
 
850
TRIO_PRIVATE void
 
851
TrioSetLocale(TRIO_NOARGS)
 
852
{
 
853
  internalLocaleValues = (struct lconv *)localeconv();
 
854
  if (internalLocaleValues)
 
855
    {
 
856
      if ((internalLocaleValues->decimal_point) &&
 
857
          (internalLocaleValues->decimal_point[0] != NIL))
 
858
        {
 
859
          internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
 
860
          if (internalDecimalPointLength == 1)
 
861
            {
 
862
              internalDecimalPoint = internalLocaleValues->decimal_point[0];
 
863
            }
 
864
          else
 
865
            {
 
866
              internalDecimalPoint = NIL;
 
867
              trio_copy_max(internalDecimalPointString,
 
868
                            sizeof(internalDecimalPointString),
 
869
                            internalLocaleValues->decimal_point);
 
870
            }
 
871
        }
 
872
      if ((internalLocaleValues->thousands_sep) &&
 
873
          (internalLocaleValues->thousands_sep[0] != NIL))
 
874
        {
 
875
          trio_copy_max(internalThousandSeparator,
 
876
                        sizeof(internalThousandSeparator),
 
877
                        internalLocaleValues->thousands_sep);
 
878
          internalThousandSeparatorLength = trio_length(internalThousandSeparator);
 
879
        }
 
880
      if ((internalLocaleValues->grouping) &&
 
881
          (internalLocaleValues->grouping[0] != NIL))
 
882
        {
 
883
          trio_copy_max(internalGrouping,
 
884
                        sizeof(internalGrouping),
 
885
                        internalLocaleValues->grouping);
 
886
        }
 
887
    }
 
888
}
 
889
#endif /* defined(USE_LOCALE) */
 
890
 
 
891
TRIO_PRIVATE int
 
892
TrioCalcThousandSeparatorLength
 
893
TRIO_ARGS1((digits),
 
894
           int digits)
 
895
{
 
896
#if TRIO_EXTENSION
 
897
  int count = 0;
 
898
  int step = NO_GROUPING;
 
899
  char *groupingPointer = internalGrouping;
 
900
 
 
901
  while (digits > 0)
 
902
    {
 
903
      if (*groupingPointer == CHAR_MAX)
 
904
        {
 
905
          /* Disable grouping */
 
906
          break; /* while */
 
907
        }
 
908
      else if (*groupingPointer == 0)
 
909
        {
 
910
          /* Repeat last group */
 
911
          if (step == NO_GROUPING)
 
912
            {
 
913
              /* Error in locale */
 
914
              break; /* while */
 
915
            }
 
916
        }
 
917
      else
 
918
        {
 
919
          step = *groupingPointer++;
 
920
        }
 
921
      if (digits > step)
 
922
        count += internalThousandSeparatorLength;
 
923
      digits -= step;
 
924
    }
 
925
  return count;
 
926
#else
 
927
  return 0;
 
928
#endif
 
929
}
 
930
 
 
931
TRIO_PRIVATE BOOLEAN_T
 
932
TrioFollowedBySeparator
 
933
TRIO_ARGS1((position),
 
934
           int position)
 
935
{
 
936
#if TRIO_EXTENSION
 
937
  int step = 0;
 
938
  char *groupingPointer = internalGrouping;
 
939
 
 
940
  position--;
 
941
  if (position == 0)
 
942
    return FALSE;
 
943
  while (position > 0)
 
944
    {
 
945
      if (*groupingPointer == CHAR_MAX)
 
946
        {
 
947
          /* Disable grouping */
 
948
          break; /* while */
 
949
        }
 
950
      else if (*groupingPointer != 0)
 
951
        {
 
952
          step = *groupingPointer++;
 
953
        }
 
954
      if (step == 0)
 
955
        break;
 
956
      position -= step;
 
957
    }
 
958
  return (position == 0);
 
959
#else
 
960
  return FALSE;
 
961
#endif
 
962
}
 
963
 
 
964
/*************************************************************************
 
965
 * TrioGetPosition
 
966
 *
 
967
 * Get the %n$ position.
 
968
 */
 
969
TRIO_PRIVATE int
 
970
TrioGetPosition
 
971
TRIO_ARGS2((format, indexPointer),
 
972
           TRIO_CONST char *format,
 
973
           int *indexPointer)
 
974
{
 
975
#if TRIO_UNIX98
 
976
  char *tmpformat;
 
977
  int number = 0;
 
978
  int index = *indexPointer;
 
979
 
 
980
  number = (int)trio_to_long(&format[index], &tmpformat, BASE_DECIMAL);
 
981
  index = (int)(tmpformat - format);
 
982
  if ((number != 0) && (QUALIFIER_POSITION == format[index++]))
 
983
    {
 
984
      *indexPointer = index;
 
985
      /*
 
986
       * number is decreased by 1, because n$ starts from 1, whereas
 
987
       * the array it is indexing starts from 0.
 
988
       */
 
989
      return number - 1;
 
990
    }
 
991
#endif
 
992
  return NO_POSITION;
 
993
}
 
994
 
 
995
#if TRIO_EXTENSION
 
996
/*************************************************************************
 
997
 * TrioFindNamespace
 
998
 *
 
999
 * Find registered user-defined specifier.
 
1000
 * The prev argument is used for optimization only.
 
1001
 */
 
1002
TRIO_PRIVATE trio_userdef_t *
 
1003
TrioFindNamespace
 
1004
TRIO_ARGS2((name, prev),
 
1005
           TRIO_CONST char *name,
 
1006
           trio_userdef_t **prev)
 
1007
{
 
1008
  trio_userdef_t *def;
 
1009
  
 
1010
  if (internalEnterCriticalRegion)
 
1011
    (void)internalEnterCriticalRegion(NULL);
 
1012
  
 
1013
  for (def = internalUserDef; def; def = def->next)
 
1014
    {
 
1015
      /* Case-sensitive string comparison */
 
1016
      if (trio_equal_case(def->name, name))
 
1017
        break;
 
1018
      
 
1019
      if (prev)
 
1020
        *prev = def;
 
1021
    }
 
1022
  
 
1023
  if (internalLeaveCriticalRegion)
 
1024
    (void)internalLeaveCriticalRegion(NULL);
 
1025
  
 
1026
  return def;
 
1027
}
 
1028
#endif
 
1029
 
 
1030
/*************************************************************************
 
1031
 * TrioPower
 
1032
 *
 
1033
 * Description:
 
1034
 *  Calculate pow(base, exponent), where number and exponent are integers.
 
1035
 */
 
1036
TRIO_PRIVATE trio_long_double_t
 
1037
TrioPower
 
1038
TRIO_ARGS2((number, exponent),
 
1039
           int number,
 
1040
           int exponent)
 
1041
{
 
1042
  trio_long_double_t result;
 
1043
 
 
1044
  if (number == 10)
 
1045
    {
 
1046
      switch (exponent)
 
1047
        {
 
1048
          /* Speed up calculation of common cases */
 
1049
        case 0:
 
1050
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E-1);
 
1051
          break;
 
1052
        case 1:
 
1053
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+0);
 
1054
          break;
 
1055
        case 2:
 
1056
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+1);
 
1057
          break;
 
1058
        case 3:
 
1059
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+2);
 
1060
          break;
 
1061
        case 4:
 
1062
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+3);
 
1063
          break;
 
1064
        case 5:
 
1065
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+4);
 
1066
          break;
 
1067
        case 6:
 
1068
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+5);
 
1069
          break;
 
1070
        case 7:
 
1071
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+6);
 
1072
          break;
 
1073
        case 8:
 
1074
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+7);
 
1075
          break;
 
1076
        case 9:
 
1077
          result = (trio_long_double_t)number * TRIO_SUFFIX_LONG(1E+8);
 
1078
          break;
 
1079
        default:
 
1080
          result = powl((trio_long_double_t)number,
 
1081
                        (trio_long_double_t)exponent);
 
1082
          break;
 
1083
        }
 
1084
    }
 
1085
  else
 
1086
    {
 
1087
      return powl((trio_long_double_t)number, (trio_long_double_t)exponent);
 
1088
    }
 
1089
  return result;
 
1090
}
 
1091
 
 
1092
/*************************************************************************
 
1093
 * TrioLogarithm
 
1094
 */
 
1095
TRIO_PRIVATE double
 
1096
TrioLogarithm
 
1097
TRIO_ARGS2((number, base),
 
1098
           double number,
 
1099
           int base)
 
1100
{
 
1101
  double result;
 
1102
 
 
1103
  if (number <= 0.0)
 
1104
    {
 
1105
      /* xlC crashes on log(0) */
 
1106
      result = (number == 0.0) ? trio_ninf() : trio_nan();
 
1107
    }
 
1108
  else
 
1109
    {
 
1110
      if (base == 10)
 
1111
        {
 
1112
          result = log10(number);
 
1113
        }
 
1114
      else
 
1115
        {
 
1116
          result = log10(number) / log10((double)base);
 
1117
        }
 
1118
    }
 
1119
  return result;
 
1120
}
 
1121
 
 
1122
/*************************************************************************
 
1123
 * TrioLogarithmBase
 
1124
 */
 
1125
TRIO_PRIVATE double
 
1126
TrioLogarithmBase
 
1127
TRIO_ARGS1((base),
 
1128
           int base)
 
1129
{
 
1130
  switch (base)
 
1131
    {
 
1132
    case BASE_BINARY : return 1.0;
 
1133
    case BASE_OCTAL  : return 3.0;
 
1134
    case BASE_DECIMAL: return 3.321928094887362345;
 
1135
    case BASE_HEX    : return 4.0;
 
1136
    default          : return TrioLogarithm((double)base, 2);
 
1137
    }
 
1138
}
 
1139
 
 
1140
/*************************************************************************
 
1141
 * TrioParse
 
1142
 *
 
1143
 * Description:
 
1144
 *  Parse the format string
 
1145
 */
 
1146
TRIO_PRIVATE int
 
1147
TrioParse
 
1148
TRIO_ARGS5((type, format, parameters, arglist, argarray),
 
1149
           int type,
 
1150
           TRIO_CONST char *format,
 
1151
           trio_parameter_t *parameters,
 
1152
           va_list *arglist,
 
1153
           trio_pointer_t *argarray)
 
1154
{
 
1155
  /* Count the number of times a parameter is referenced */
 
1156
  unsigned short usedEntries[MAX_PARAMETERS];
 
1157
  /* Parameter counters */
 
1158
  int parameterPosition;
 
1159
  int currentParam;
 
1160
  int maxParam = -1;
 
1161
  /* Utility variables */
 
1162
  trio_flags_t flags;
 
1163
  int width;
 
1164
  int precision;
 
1165
  int varsize;
 
1166
  int base;
 
1167
  int index;  /* Index into formatting string */
 
1168
  int dots;  /* Count number of dots in modifier part */
 
1169
  BOOLEAN_T positional;  /* Does the specifier have a positional? */
 
1170
  BOOLEAN_T gotSticky = FALSE;  /* Are there any sticky modifiers at all? */
 
1171
  /*
 
1172
   * indices specifies the order in which the parameters must be
 
1173
   * read from the va_args (this is necessary to handle positionals)
 
1174
   */
 
1175
  int indices[MAX_PARAMETERS];
 
1176
  int pos = 0;
 
1177
  /* Various variables */
 
1178
  char ch;
 
1179
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
1180
  int charlen;
 
1181
#endif
 
1182
  int save_errno;
 
1183
  int i = -1;
 
1184
  int num;
 
1185
  char *tmpformat;
 
1186
 
 
1187
  /* One and only one of arglist and argarray must be used */
 
1188
  assert((arglist != NULL) ^ (argarray != NULL));
 
1189
  
 
1190
  /*
 
1191
   * The 'parameters' array is not initialized, but we need to
 
1192
   * know which entries we have used.
 
1193
   */
 
1194
  memset(usedEntries, 0, sizeof(usedEntries));
 
1195
 
 
1196
  save_errno = errno;
 
1197
  index = 0;
 
1198
  parameterPosition = 0;
 
1199
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
1200
  (void)mblen(NULL, 0);
 
1201
#endif
 
1202
  
 
1203
  while (format[index])
 
1204
    {
 
1205
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
1206
      if (! isascii(format[index]))
 
1207
        {
 
1208
          /*
 
1209
           * Multibyte characters cannot be legal specifiers or
 
1210
           * modifiers, so we skip over them.
 
1211
           */
 
1212
          charlen = mblen(&format[index], MB_LEN_MAX);
 
1213
          index += (charlen > 0) ? charlen : 1;
 
1214
          continue; /* while */
 
1215
        }
 
1216
#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
 
1217
      if (CHAR_IDENTIFIER == format[index++])
 
1218
        {
 
1219
          if (CHAR_IDENTIFIER == format[index])
 
1220
            {
 
1221
              index++;
 
1222
              continue; /* while */
 
1223
            }
 
1224
 
 
1225
          flags = FLAGS_NEW;
 
1226
          dots = 0;
 
1227
          currentParam = TrioGetPosition(format, &index);
 
1228
          positional = (NO_POSITION != currentParam);
 
1229
          if (!positional)
 
1230
            {
 
1231
              /* We have no positional, get the next counter */
 
1232
              currentParam = parameterPosition;
 
1233
            }
 
1234
          if(currentParam >= MAX_PARAMETERS)
 
1235
            {
 
1236
              /* Bail out completely to make the error more obvious */
 
1237
              return TRIO_ERROR_RETURN(TRIO_ETOOMANY, index);
 
1238
            }
 
1239
 
 
1240
          if (currentParam > maxParam)
 
1241
            maxParam = currentParam;
 
1242
 
 
1243
          /* Default values */
 
1244
          width = NO_WIDTH;
 
1245
          precision = NO_PRECISION;
 
1246
          base = NO_BASE;
 
1247
          varsize = NO_SIZE;
 
1248
 
 
1249
          while (TrioIsQualifier(format[index]))
 
1250
            {
 
1251
              ch = format[index++];
 
1252
 
 
1253
              switch (ch)
 
1254
                {
 
1255
                case QUALIFIER_SPACE:
 
1256
                  flags |= FLAGS_SPACE;
 
1257
                  break;
 
1258
 
 
1259
                case QUALIFIER_PLUS:
 
1260
                  flags |= FLAGS_SHOWSIGN;
 
1261
                  break;
 
1262
 
 
1263
                case QUALIFIER_MINUS:
 
1264
                  flags |= FLAGS_LEFTADJUST;
 
1265
                  flags &= ~FLAGS_NILPADDING;
 
1266
                  break;
 
1267
 
 
1268
                case QUALIFIER_ALTERNATIVE:
 
1269
                  flags |= FLAGS_ALTERNATIVE;
 
1270
                  break;
 
1271
 
 
1272
                case QUALIFIER_DOT:
 
1273
                  if (dots == 0) /* Precision */
 
1274
                    {
 
1275
                      dots++;
 
1276
 
 
1277
                      /* Skip if no precision */
 
1278
                      if (QUALIFIER_DOT == format[index])
 
1279
                        break;
 
1280
                      
 
1281
                      /* After the first dot we have the precision */
 
1282
                      flags |= FLAGS_PRECISION;
 
1283
                      if ((QUALIFIER_STAR == format[index])
 
1284
#if defined(QUALIFIER_PARAM)
 
1285
                          || (QUALIFIER_PARAM == format[index])
 
1286
#endif
 
1287
                          )
 
1288
                        {
 
1289
                          index++;
 
1290
                          flags |= FLAGS_PRECISION_PARAMETER;
 
1291
 
 
1292
                          precision = TrioGetPosition(format, &index);
 
1293
                          if (precision == NO_POSITION)
 
1294
                            {
 
1295
                              parameterPosition++;
 
1296
                              if (positional)
 
1297
                                precision = parameterPosition;
 
1298
                              else
 
1299
                                {
 
1300
                                  precision = currentParam;
 
1301
                                  currentParam = precision + 1;
 
1302
                                }
 
1303
                            }
 
1304
                          else
 
1305
                            {
 
1306
                              if (! positional)
 
1307
                                currentParam = precision + 1;
 
1308
                              if (width > maxParam)
 
1309
                                maxParam = precision;
 
1310
                            }
 
1311
                          if (currentParam > maxParam)
 
1312
                            maxParam = currentParam;
 
1313
                        }
 
1314
                      else
 
1315
                        {
 
1316
                          precision = trio_to_long(&format[index],
 
1317
                                                   &tmpformat,
 
1318
                                                   BASE_DECIMAL);
 
1319
                          index = (int)(tmpformat - format);
 
1320
                        }
 
1321
                    }
 
1322
                  else if (dots == 1) /* Base */
 
1323
                    {
 
1324
                      dots++;
 
1325
                      
 
1326
                      /* After the second dot we have the base */
 
1327
                      flags |= FLAGS_BASE;
 
1328
                      if ((QUALIFIER_STAR == format[index])
 
1329
#if defined(QUALIFIER_PARAM)
 
1330
                          || (QUALIFIER_PARAM == format[index])
 
1331
#endif
 
1332
                          )
 
1333
                        {
 
1334
                          index++;
 
1335
                          flags |= FLAGS_BASE_PARAMETER;
 
1336
                          base = TrioGetPosition(format, &index);
 
1337
                          if (base == NO_POSITION)
 
1338
                            {
 
1339
                              parameterPosition++;
 
1340
                              if (positional)
 
1341
                                base = parameterPosition;
 
1342
                              else
 
1343
                                {
 
1344
                                  base = currentParam;
 
1345
                                  currentParam = base + 1;
 
1346
                                }
 
1347
                            }
 
1348
                          else
 
1349
                            {
 
1350
                              if (! positional)
 
1351
                                currentParam = base + 1;
 
1352
                              if (base > maxParam)
 
1353
                                maxParam = base;
 
1354
                            }
 
1355
                          if (currentParam > maxParam)
 
1356
                            maxParam = currentParam;
 
1357
                        }
 
1358
                      else
 
1359
                        {
 
1360
                          base = trio_to_long(&format[index],
 
1361
                                              &tmpformat,
 
1362
                                              BASE_DECIMAL);
 
1363
                          if (base > MAX_BASE)
 
1364
                            return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1365
                          index = (int)(tmpformat - format);
 
1366
                        }
 
1367
                    }
 
1368
                  else
 
1369
                    {
 
1370
                      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1371
                    }
 
1372
                  break; /* QUALIFIER_DOT */
 
1373
 
 
1374
#if defined(QUALIFIER_PARAM)
 
1375
                case QUALIFIER_PARAM:
 
1376
                  type = TYPE_PRINT;
 
1377
                  /* FALLTHROUGH */
 
1378
#endif
 
1379
                case QUALIFIER_STAR:
 
1380
                  /* This has different meanings for print and scan */
 
1381
                  if (TYPE_PRINT == type)
 
1382
                    {
 
1383
                      /* Read with from parameter */
 
1384
                      flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
 
1385
                      width = TrioGetPosition(format, &index);
 
1386
                      if (width == NO_POSITION)
 
1387
                        {
 
1388
                          parameterPosition++;
 
1389
                          if (positional)
 
1390
                            width = parameterPosition;
 
1391
                          else
 
1392
                            {
 
1393
                              width = currentParam;
 
1394
                              currentParam = width + 1;
 
1395
                            }
 
1396
                        }
 
1397
                      else
 
1398
                        {
 
1399
                          if (! positional)
 
1400
                            currentParam = width + 1;
 
1401
                          if (width > maxParam)
 
1402
                            maxParam = width;
 
1403
                        }
 
1404
                      if (currentParam > maxParam)
 
1405
                        maxParam = currentParam;
 
1406
                    }
 
1407
                  else
 
1408
                    {
 
1409
                      /* Scan, but do not store result */
 
1410
                      flags |= FLAGS_IGNORE;
 
1411
                    }
 
1412
 
 
1413
                  break; /* QUALIFIER_STAR */
 
1414
 
 
1415
                case '0':
 
1416
                  if (! (flags & FLAGS_LEFTADJUST))
 
1417
                    flags |= FLAGS_NILPADDING;
 
1418
                  /* FALLTHROUGH */
 
1419
                case '1': case '2': case '3': case '4':
 
1420
                case '5': case '6': case '7': case '8': case '9':
 
1421
                  flags |= FLAGS_WIDTH;
 
1422
                  /* &format[index - 1] is used to "rewind" the read
 
1423
                   * character from format
 
1424
                   */
 
1425
                  width = trio_to_long(&format[index - 1],
 
1426
                                       &tmpformat,
 
1427
                                       BASE_DECIMAL);
 
1428
                  index = (int)(tmpformat - format);
 
1429
                  break;
 
1430
 
 
1431
                case QUALIFIER_SHORT:
 
1432
                  if (flags & FLAGS_SHORTSHORT)
 
1433
                    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1434
                  else if (flags & FLAGS_SHORT)
 
1435
                    flags |= FLAGS_SHORTSHORT;
 
1436
                  else
 
1437
                    flags |= FLAGS_SHORT;
 
1438
                  break;
 
1439
 
 
1440
                case QUALIFIER_LONG:
 
1441
                  if (flags & FLAGS_QUAD)
 
1442
                    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1443
                  else if (flags & FLAGS_LONG)
 
1444
                    flags |= FLAGS_QUAD;
 
1445
                  else
 
1446
                    flags |= FLAGS_LONG;
 
1447
                  break;
 
1448
 
 
1449
                case QUALIFIER_LONG_UPPER:
 
1450
                  flags |= FLAGS_LONGDOUBLE;
 
1451
                  break;
 
1452
 
 
1453
#if defined(QUALIFIER_SIZE_T)
 
1454
                case QUALIFIER_SIZE_T:
 
1455
                  flags |= FLAGS_SIZE_T;
 
1456
                  /* Modify flags for later truncation of number */
 
1457
                  if (sizeof(size_t) == sizeof(trio_ulonglong_t))
 
1458
                    flags |= FLAGS_QUAD;
 
1459
                  else if (sizeof(size_t) == sizeof(long))
 
1460
                    flags |= FLAGS_LONG;
 
1461
                  break;
 
1462
#endif
 
1463
 
 
1464
#if defined(QUALIFIER_PTRDIFF_T)
 
1465
                case QUALIFIER_PTRDIFF_T:
 
1466
                  flags |= FLAGS_PTRDIFF_T;
 
1467
                  if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
 
1468
                    flags |= FLAGS_QUAD;
 
1469
                  else if (sizeof(ptrdiff_t) == sizeof(long))
 
1470
                    flags |= FLAGS_LONG;
 
1471
                  break;
 
1472
#endif
 
1473
 
 
1474
#if defined(QUALIFIER_INTMAX_T)
 
1475
                case QUALIFIER_INTMAX_T:
 
1476
                  flags |= FLAGS_INTMAX_T;
 
1477
                  if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
 
1478
                    flags |= FLAGS_QUAD;
 
1479
                  else if (sizeof(trio_intmax_t) == sizeof(long))
 
1480
                    flags |= FLAGS_LONG;
 
1481
                  break;
 
1482
#endif
 
1483
 
 
1484
#if defined(QUALIFIER_QUAD)
 
1485
                case QUALIFIER_QUAD:
 
1486
                  flags |= FLAGS_QUAD;
 
1487
                  break;
 
1488
#endif
 
1489
 
 
1490
#if defined(QUALIFIER_FIXED_SIZE)
 
1491
                case QUALIFIER_FIXED_SIZE:
 
1492
                  if (flags & FLAGS_FIXED_SIZE)
 
1493
                    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1494
 
 
1495
                  if (flags & (FLAGS_ALL_SIZES | FLAGS_LONGDOUBLE |
 
1496
                               FLAGS_WIDECHAR | FLAGS_VARSIZE_PARAMETER))
 
1497
                    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1498
 
 
1499
                  if ((format[index] == '6') &&
 
1500
                      (format[index + 1] == '4'))
 
1501
                    {
 
1502
                      varsize = sizeof(trio_int64_t);
 
1503
                      index += 2;
 
1504
                    }
 
1505
                  else if ((format[index] == '3') &&
 
1506
                           (format[index + 1] == '2'))
 
1507
                    {
 
1508
                      varsize = sizeof(trio_int32_t);
 
1509
                      index += 2;
 
1510
                    }
 
1511
                  else if ((format[index] == '1') &&
 
1512
                           (format[index + 1] == '6'))
 
1513
                    {
 
1514
                      varsize = sizeof(trio_int16_t);
 
1515
                      index += 2;
 
1516
                    }
 
1517
                  else if (format[index] == '8')
 
1518
                    {
 
1519
                      varsize = sizeof(trio_int8_t);
 
1520
                      index++;
 
1521
                    }
 
1522
                  else
 
1523
                    return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1524
                  
 
1525
                  flags |= FLAGS_FIXED_SIZE;
 
1526
                  break;
 
1527
#endif
 
1528
 
 
1529
#if defined(QUALIFIER_WIDECHAR)
 
1530
                case QUALIFIER_WIDECHAR:
 
1531
                  flags |= FLAGS_WIDECHAR;
 
1532
                  break;
 
1533
#endif
 
1534
 
 
1535
#if defined(QUALIFIER_SIZE_T_UPPER)
 
1536
                case QUALIFIER_SIZE_T_UPPER:
 
1537
                  break;
 
1538
#endif
 
1539
 
 
1540
#if defined(QUALIFIER_QUOTE)
 
1541
                case QUALIFIER_QUOTE:
 
1542
                  flags |= FLAGS_QUOTE;
 
1543
                  break;
 
1544
#endif
 
1545
 
 
1546
#if defined(QUALIFIER_STICKY)
 
1547
                case QUALIFIER_STICKY:
 
1548
                  flags |= FLAGS_STICKY;
 
1549
                  gotSticky = TRUE;
 
1550
                  break;
 
1551
#endif
 
1552
                  
 
1553
#if defined(QUALIFIER_VARSIZE)
 
1554
                case QUALIFIER_VARSIZE:
 
1555
                  flags |= FLAGS_VARSIZE_PARAMETER;
 
1556
                  parameterPosition++;
 
1557
                  if (positional)
 
1558
                    varsize = parameterPosition;
 
1559
                  else
 
1560
                    {
 
1561
                      varsize = currentParam;
 
1562
                      currentParam = varsize + 1;
 
1563
                    }
 
1564
                  if (currentParam > maxParam)
 
1565
                    maxParam = currentParam;
 
1566
                  break;
 
1567
#endif
 
1568
 
 
1569
#if defined(QUALIFIER_ROUNDING_UPPER)
 
1570
                case QUALIFIER_ROUNDING_UPPER:
 
1571
                  flags |= FLAGS_ROUNDING;
 
1572
                  break;
 
1573
#endif
 
1574
 
 
1575
                default:
 
1576
                  /* Bail out completely to make the error more obvious */
 
1577
                  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1578
                }
 
1579
            } /* while qualifier */
 
1580
 
 
1581
          /*
 
1582
           * Parameters only need the type and value. The value is
 
1583
           * read later.
 
1584
           */
 
1585
          if (flags & FLAGS_WIDTH_PARAMETER)
 
1586
            {
 
1587
              usedEntries[width] += 1;
 
1588
              parameters[pos].type = FORMAT_PARAMETER;
 
1589
              parameters[pos].flags = 0;
 
1590
              indices[width] = pos;
 
1591
              width = pos++;
 
1592
            }
 
1593
          if (flags & FLAGS_PRECISION_PARAMETER)
 
1594
            {
 
1595
              usedEntries[precision] += 1;
 
1596
              parameters[pos].type = FORMAT_PARAMETER;
 
1597
              parameters[pos].flags = 0;
 
1598
              indices[precision] = pos;
 
1599
              precision = pos++;
 
1600
            }
 
1601
          if (flags & FLAGS_BASE_PARAMETER)
 
1602
            {
 
1603
              usedEntries[base] += 1;
 
1604
              parameters[pos].type = FORMAT_PARAMETER;
 
1605
              parameters[pos].flags = 0;
 
1606
              indices[base] = pos;
 
1607
              base = pos++;
 
1608
            }
 
1609
          if (flags & FLAGS_VARSIZE_PARAMETER)
 
1610
            {
 
1611
              usedEntries[varsize] += 1;
 
1612
              parameters[pos].type = FORMAT_PARAMETER;
 
1613
              parameters[pos].flags = 0;
 
1614
              indices[varsize] = pos;
 
1615
              varsize = pos++;
 
1616
            }
 
1617
          
 
1618
          indices[currentParam] = pos;
 
1619
          
 
1620
          switch (format[index++])
 
1621
            {
 
1622
#if defined(SPECIFIER_CHAR_UPPER)
 
1623
            case SPECIFIER_CHAR_UPPER:
 
1624
              flags |= FLAGS_WIDECHAR;
 
1625
              /* FALLTHROUGH */
 
1626
#endif
 
1627
            case SPECIFIER_CHAR:
 
1628
              if (flags & FLAGS_LONG)
 
1629
                flags |= FLAGS_WIDECHAR;
 
1630
              else if (flags & FLAGS_SHORT)
 
1631
                flags &= ~FLAGS_WIDECHAR;
 
1632
              parameters[pos].type = FORMAT_CHAR;
 
1633
              break;
 
1634
 
 
1635
#if defined(SPECIFIER_STRING_UPPER)
 
1636
            case SPECIFIER_STRING_UPPER:
 
1637
              flags |= FLAGS_WIDECHAR;
 
1638
              /* FALLTHROUGH */
 
1639
#endif
 
1640
            case SPECIFIER_STRING:
 
1641
              if (flags & FLAGS_LONG)
 
1642
                flags |= FLAGS_WIDECHAR;
 
1643
              else if (flags & FLAGS_SHORT)
 
1644
                flags &= ~FLAGS_WIDECHAR;
 
1645
              parameters[pos].type = FORMAT_STRING;
 
1646
              break;
 
1647
 
 
1648
            case SPECIFIER_GROUP:
 
1649
              if (TYPE_SCAN == type)
 
1650
                {
 
1651
                  int depth = 1;
 
1652
                  parameters[pos].type = FORMAT_GROUP;
 
1653
                  if (format[index] == QUALIFIER_CIRCUMFLEX)
 
1654
                    index++;
 
1655
                  if (format[index] == SPECIFIER_UNGROUP)
 
1656
                    index++;
 
1657
                  if (format[index] == QUALIFIER_MINUS)
 
1658
                    index++;
 
1659
                  /* Skip nested brackets */
 
1660
                  while (format[index] != NIL)
 
1661
                    {
 
1662
                      if (format[index] == SPECIFIER_GROUP)
 
1663
                        {
 
1664
                          depth++;
 
1665
                        }
 
1666
                      else if (format[index] == SPECIFIER_UNGROUP)
 
1667
                        {
 
1668
                          if (--depth <= 0)
 
1669
                            {
 
1670
                              index++;
 
1671
                              break;
 
1672
                            }
 
1673
                        }
 
1674
                      index++;
 
1675
                    }
 
1676
                }
 
1677
              break;
 
1678
              
 
1679
            case SPECIFIER_INTEGER:
 
1680
              parameters[pos].type = FORMAT_INT;
 
1681
              break;
 
1682
              
 
1683
            case SPECIFIER_UNSIGNED:
 
1684
              flags |= FLAGS_UNSIGNED;
 
1685
              parameters[pos].type = FORMAT_INT;
 
1686
              break;
 
1687
 
 
1688
            case SPECIFIER_DECIMAL:
 
1689
              /* Disable base modifier */
 
1690
              flags &= ~FLAGS_BASE_PARAMETER;
 
1691
              base = BASE_DECIMAL;
 
1692
              parameters[pos].type = FORMAT_INT;
 
1693
              break;
 
1694
 
 
1695
            case SPECIFIER_OCTAL:
 
1696
              flags |= FLAGS_UNSIGNED;
 
1697
              flags &= ~FLAGS_BASE_PARAMETER;
 
1698
              base = BASE_OCTAL;
 
1699
              parameters[pos].type = FORMAT_INT;
 
1700
              break;
 
1701
 
 
1702
#if defined(SPECIFIER_BINARY)
 
1703
            case SPECIFIER_BINARY_UPPER:
 
1704
              flags |= FLAGS_UPPER;
 
1705
              /* FALLTHROUGH */
 
1706
            case SPECIFIER_BINARY:
 
1707
              flags |= FLAGS_NILPADDING;
 
1708
              flags &= ~FLAGS_BASE_PARAMETER;
 
1709
              base = BASE_BINARY;
 
1710
              parameters[pos].type = FORMAT_INT;
 
1711
              break;
 
1712
#endif
 
1713
 
 
1714
            case SPECIFIER_HEX_UPPER:
 
1715
              flags |= FLAGS_UPPER;
 
1716
              /* FALLTHROUGH */
 
1717
            case SPECIFIER_HEX:
 
1718
              flags |= FLAGS_UNSIGNED;
 
1719
              flags &= ~FLAGS_BASE_PARAMETER;
 
1720
              base = BASE_HEX;
 
1721
              parameters[pos].type = FORMAT_INT;
 
1722
              break;
 
1723
 
 
1724
            case SPECIFIER_FLOAT_E_UPPER:
 
1725
              flags |= FLAGS_UPPER;
 
1726
              /* FALLTHROUGH */
 
1727
            case SPECIFIER_FLOAT_E:
 
1728
              flags |= FLAGS_FLOAT_E;
 
1729
              parameters[pos].type = FORMAT_DOUBLE;
 
1730
              break;
 
1731
 
 
1732
            case SPECIFIER_FLOAT_G_UPPER:
 
1733
              flags |= FLAGS_UPPER;
 
1734
              /* FALLTHROUGH */
 
1735
            case SPECIFIER_FLOAT_G:
 
1736
              flags |= FLAGS_FLOAT_G;
 
1737
              parameters[pos].type = FORMAT_DOUBLE;
 
1738
              break;
 
1739
 
 
1740
            case SPECIFIER_FLOAT_F_UPPER:
 
1741
              flags |= FLAGS_UPPER;
 
1742
              /* FALLTHROUGH */
 
1743
            case SPECIFIER_FLOAT_F:
 
1744
              parameters[pos].type = FORMAT_DOUBLE;
 
1745
              break;
 
1746
 
 
1747
            case SPECIFIER_POINTER:
 
1748
              if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
 
1749
                flags |= FLAGS_QUAD;
 
1750
              else if (sizeof(trio_pointer_t) == sizeof(long))
 
1751
                flags |= FLAGS_LONG;
 
1752
              parameters[pos].type = FORMAT_POINTER;
 
1753
              break;
 
1754
 
 
1755
            case SPECIFIER_COUNT:
 
1756
              parameters[pos].type = FORMAT_COUNT;
 
1757
              break;
 
1758
 
 
1759
#if defined(SPECIFIER_HEXFLOAT)
 
1760
# if defined(SPECIFIER_HEXFLOAT_UPPER)
 
1761
            case SPECIFIER_HEXFLOAT_UPPER:
 
1762
              flags |= FLAGS_UPPER;
 
1763
              /* FALLTHROUGH */
 
1764
# endif
 
1765
            case SPECIFIER_HEXFLOAT:
 
1766
              base = BASE_HEX;
 
1767
              parameters[pos].type = FORMAT_DOUBLE;
 
1768
              break;
 
1769
#endif
 
1770
 
 
1771
#if defined(FORMAT_ERRNO)
 
1772
            case SPECIFIER_ERRNO:
 
1773
              parameters[pos].type = FORMAT_ERRNO;
 
1774
              break;
 
1775
#endif
 
1776
 
 
1777
#if defined(SPECIFIER_USER_DEFINED_BEGIN)
 
1778
            case SPECIFIER_USER_DEFINED_BEGIN:
 
1779
              {
 
1780
                unsigned int max;
 
1781
                int without_namespace = TRUE;
 
1782
                
 
1783
                parameters[pos].type = FORMAT_USER_DEFINED;
 
1784
                parameters[pos].user_name[0] = NIL;
 
1785
                tmpformat = (char *)&format[index];
 
1786
              
 
1787
                while ((ch = format[index]))
 
1788
                  {
 
1789
                    index++;
 
1790
                    if (ch == SPECIFIER_USER_DEFINED_END)
 
1791
                      {
 
1792
                        if (without_namespace)
 
1793
                          {
 
1794
                            /* We must get the handle first */
 
1795
                            parameters[pos].type = FORMAT_PARAMETER;
 
1796
                            parameters[pos].indexAfterSpecifier = index;
 
1797
                            parameters[pos].flags = FLAGS_USER_DEFINED;
 
1798
                            /* Adjust parameters for insertion of new one */
 
1799
                            pos++;
 
1800
                            usedEntries[currentParam] += 1;
 
1801
                            parameters[pos].type = FORMAT_USER_DEFINED;
 
1802
                            currentParam++;
 
1803
                            indices[currentParam] = pos;
 
1804
                            if (currentParam > maxParam)
 
1805
                              maxParam = currentParam;
 
1806
                          }
 
1807
                        /* Copy the user data */
 
1808
                        max = (unsigned int)(&format[index] - tmpformat);
 
1809
                        if (max > MAX_USER_DATA)
 
1810
                          max = MAX_USER_DATA;
 
1811
                        trio_copy_max(parameters[pos].user_data,
 
1812
                                      max,
 
1813
                                      tmpformat);
 
1814
                        break; /* while */
 
1815
                      }
 
1816
                    if (ch == SPECIFIER_USER_DEFINED_SEPARATOR)
 
1817
                      {
 
1818
                        without_namespace = FALSE;
 
1819
                        /* Copy the namespace for later looking-up */
 
1820
                        max = (int)(&format[index] - tmpformat);
 
1821
                        if (max > MAX_USER_NAME)
 
1822
                          max = MAX_USER_NAME;
 
1823
                        trio_copy_max(parameters[pos].user_name,
 
1824
                                      max,
 
1825
                                      tmpformat);
 
1826
                        tmpformat = (char *)&format[index];
 
1827
                      }
 
1828
                  }
 
1829
                if (ch != SPECIFIER_USER_DEFINED_END)
 
1830
                  return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1831
              }
 
1832
              break;
 
1833
#endif /* defined(SPECIFIER_USER_DEFINED_BEGIN) */
 
1834
              
 
1835
            default:
 
1836
              /* Bail out completely to make the error more obvious */
 
1837
              return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
1838
            }
 
1839
 
 
1840
          /*  Count the number of times this entry has been used */
 
1841
          usedEntries[currentParam] += 1;
 
1842
          
 
1843
          /* Find last sticky parameters */
 
1844
          if (gotSticky && !(flags & FLAGS_STICKY))
 
1845
            {
 
1846
              for (i = pos - 1; i >= 0; i--)
 
1847
                {
 
1848
                  if (parameters[i].type == FORMAT_PARAMETER)
 
1849
                    continue;
 
1850
                  if ((parameters[i].flags & FLAGS_STICKY) &&
 
1851
                      (parameters[i].type == parameters[pos].type))
 
1852
                    {
 
1853
                      /* Do not overwrite current qualifiers */
 
1854
                      flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
 
1855
                      if (width == NO_WIDTH)
 
1856
                        width = parameters[i].width;
 
1857
                      if (precision == NO_PRECISION)
 
1858
                        precision = parameters[i].precision;
 
1859
                      if (base == NO_BASE)
 
1860
                        base = parameters[i].base;
 
1861
                      break;
 
1862
                    }
 
1863
                }
 
1864
            }
 
1865
          
 
1866
          parameters[pos].indexAfterSpecifier = index;
 
1867
          parameters[pos].flags = flags;
 
1868
          parameters[pos].width = width;
 
1869
          parameters[pos].precision = precision;
 
1870
          parameters[pos].base = (base == NO_BASE) ? BASE_DECIMAL : base;
 
1871
          parameters[pos].varsize = varsize;
 
1872
          pos++;
 
1873
          
 
1874
          if (! positional)
 
1875
            parameterPosition++;
 
1876
          
 
1877
        } /* if identifier */
 
1878
      
 
1879
    } /* while format characters left */
 
1880
 
 
1881
  for (num = 0; num <= maxParam; num++)
 
1882
    {
 
1883
      if (usedEntries[num] != 1)
 
1884
        {
 
1885
          if (usedEntries[num] == 0) /* gap detected */
 
1886
            return TRIO_ERROR_RETURN(TRIO_EGAP, num);
 
1887
          else /* double references detected */
 
1888
            return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
 
1889
        }
 
1890
      
 
1891
      i = indices[num];
 
1892
 
 
1893
      /*
 
1894
       * FORMAT_PARAMETERS are only present if they must be read,
 
1895
       * so it makes no sense to check the ignore flag (besides,
 
1896
       * the flags variable is not set for that particular type)
 
1897
       */
 
1898
      if ((parameters[i].type != FORMAT_PARAMETER) &&
 
1899
          (parameters[i].flags & FLAGS_IGNORE))
 
1900
        continue; /* for all arguments */
 
1901
 
 
1902
      /*
 
1903
       * The stack arguments are read according to ANSI C89
 
1904
       * default argument promotions:
 
1905
       *
 
1906
       *  char           = int
 
1907
       *  short          = int
 
1908
       *  unsigned char  = unsigned int
 
1909
       *  unsigned short = unsigned int
 
1910
       *  float          = double
 
1911
       *
 
1912
       * In addition to the ANSI C89 these types are read (the
 
1913
       * default argument promotions of C99 has not been
 
1914
       * considered yet)
 
1915
       *
 
1916
       *  long long
 
1917
       *  long double
 
1918
       *  size_t
 
1919
       *  ptrdiff_t
 
1920
       *  intmax_t
 
1921
       */
 
1922
      switch (parameters[i].type)
 
1923
        {
 
1924
        case FORMAT_GROUP:
 
1925
        case FORMAT_STRING:
 
1926
#if TRIO_WIDECHAR
 
1927
          if (flags & FLAGS_WIDECHAR)
 
1928
            {
 
1929
              parameters[i].data.wstring = (argarray == NULL)
 
1930
                ? va_arg(*arglist, trio_wchar_t *)
 
1931
                : (trio_wchar_t *)(argarray[num]);
 
1932
            }
 
1933
          else
 
1934
#endif
 
1935
            {
 
1936
              parameters[i].data.string = (argarray == NULL)
 
1937
                ? va_arg(*arglist, char *)
 
1938
                : (char *)(argarray[num]);
 
1939
            }
 
1940
          break;
 
1941
 
 
1942
#if defined(FORMAT_USER_DEFINED)
 
1943
        case FORMAT_USER_DEFINED:
 
1944
#endif
 
1945
        case FORMAT_POINTER:
 
1946
        case FORMAT_COUNT:
 
1947
        case FORMAT_UNKNOWN:
 
1948
          parameters[i].data.pointer = (argarray == NULL)
 
1949
            ? va_arg(*arglist, trio_pointer_t )
 
1950
            : argarray[num];
 
1951
          break;
 
1952
 
 
1953
        case FORMAT_CHAR:
 
1954
        case FORMAT_INT:
 
1955
          if (TYPE_SCAN == type)
 
1956
            {
 
1957
              if (argarray == NULL)
 
1958
                parameters[i].data.pointer = 
 
1959
                  (trio_pointer_t)va_arg(*arglist, trio_pointer_t);
 
1960
              else
 
1961
                {
 
1962
                  if (parameters[i].type == FORMAT_CHAR)
 
1963
                    parameters[i].data.pointer =
 
1964
                      (trio_pointer_t)((char *)argarray[num]);
 
1965
                  else if (parameters[i].flags & FLAGS_SHORT)
 
1966
                    parameters[i].data.pointer =
 
1967
                      (trio_pointer_t)((short *)argarray[num]);
 
1968
                  else
 
1969
                    parameters[i].data.pointer =
 
1970
                      (trio_pointer_t)((int *)argarray[num]);
 
1971
                }
 
1972
            }
 
1973
          else
 
1974
            {
 
1975
#if defined(QUALIFIER_VARSIZE) || defined(QUALIFIER_FIXED_SIZE)
 
1976
              if (parameters[i].flags
 
1977
                  & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
 
1978
                {
 
1979
                  if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
 
1980
                    {
 
1981
                      /*
 
1982
                       * Variable sizes are mapped onto the fixed sizes, in
 
1983
                       * accordance with integer promotion.
 
1984
                       *
 
1985
                       * Please note that this may not be portable, as we
 
1986
                       * only guess the size, not the layout of the numbers.
 
1987
                       * For example, if int is little-endian, and long is
 
1988
                       * big-endian, then this will fail.
 
1989
                       */
 
1990
                      varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
 
1991
                    }
 
1992
                  else
 
1993
                    {
 
1994
                      /* Used for the I<bits> modifiers */
 
1995
                      varsize = parameters[i].varsize;
 
1996
                    }
 
1997
                  parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
 
1998
                  
 
1999
                  if (varsize <= (int)sizeof(int))
 
2000
                    ;
 
2001
                  else if (varsize <= (int)sizeof(long))
 
2002
                    parameters[i].flags |= FLAGS_LONG;
 
2003
#if defined(QUALIFIER_INTMAX_T)
 
2004
                  else if (varsize <= (int)sizeof(trio_longlong_t))
 
2005
                    parameters[i].flags |= FLAGS_QUAD;
 
2006
                  else
 
2007
                    parameters[i].flags |= FLAGS_INTMAX_T;
 
2008
#else
 
2009
                  else
 
2010
                    parameters[i].flags |= FLAGS_QUAD;
 
2011
#endif
 
2012
                }
 
2013
#endif /* defined(QUALIFIER_VARSIZE) */
 
2014
#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 
2015
              if (parameters[i].flags & FLAGS_SIZE_T)
 
2016
                parameters[i].data.number.as_unsigned = (argarray == NULL)
 
2017
                  ? (trio_uintmax_t)va_arg(*arglist, size_t)
 
2018
                  : (trio_uintmax_t)(*((size_t *)argarray[num]));
 
2019
              else
 
2020
#endif
 
2021
#if defined(QUALIFIER_PTRDIFF_T)
 
2022
              if (parameters[i].flags & FLAGS_PTRDIFF_T)
 
2023
                parameters[i].data.number.as_unsigned = (argarray == NULL)
 
2024
                  ? (trio_uintmax_t)va_arg(*arglist, ptrdiff_t)
 
2025
                  : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
 
2026
              else
 
2027
#endif
 
2028
#if defined(QUALIFIER_INTMAX_T)
 
2029
              if (parameters[i].flags & FLAGS_INTMAX_T)
 
2030
                parameters[i].data.number.as_unsigned = (argarray == NULL)
 
2031
                  ? (trio_uintmax_t)va_arg(*arglist, trio_intmax_t)
 
2032
                  : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
 
2033
              else
 
2034
#endif
 
2035
              if (parameters[i].flags & FLAGS_QUAD)
 
2036
                parameters[i].data.number.as_unsigned = (argarray == NULL)
 
2037
                  ? (trio_uintmax_t)va_arg(*arglist, trio_ulonglong_t)
 
2038
                  : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
 
2039
              else if (parameters[i].flags & FLAGS_LONG)
 
2040
                parameters[i].data.number.as_unsigned = (argarray == NULL)
 
2041
                  ? (trio_uintmax_t)va_arg(*arglist, long)
 
2042
                  : (trio_uintmax_t)(*((long *)argarray[num]));
 
2043
              else
 
2044
                {
 
2045
                  if (argarray == NULL)
 
2046
                    parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(*arglist, int);
 
2047
                  else
 
2048
                    {
 
2049
                      if (parameters[i].type == FORMAT_CHAR)
 
2050
                        parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
 
2051
                      else if (parameters[i].flags & FLAGS_SHORT)
 
2052
                        parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
 
2053
                      else
 
2054
                        parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
 
2055
                    }
 
2056
                }
 
2057
            }
 
2058
          break;
 
2059
 
 
2060
        case FORMAT_PARAMETER:
 
2061
          /*
 
2062
           * The parameter for the user-defined specifier is a pointer,
 
2063
           * whereas the rest (width, precision, base) uses an integer.
 
2064
           */
 
2065
          if (parameters[i].flags & FLAGS_USER_DEFINED)
 
2066
            parameters[i].data.pointer = (argarray == NULL)
 
2067
              ? va_arg(*arglist, trio_pointer_t )
 
2068
              : argarray[num];
 
2069
          else
 
2070
            parameters[i].data.number.as_unsigned = (argarray == NULL)
 
2071
              ? (trio_uintmax_t)va_arg(*arglist, int)
 
2072
              : (trio_uintmax_t)(*((int *)argarray[num]));
 
2073
          break;
 
2074
 
 
2075
        case FORMAT_DOUBLE:
 
2076
          if (TYPE_SCAN == type)
 
2077
            {
 
2078
              if (parameters[i].flags & FLAGS_LONGDOUBLE)
 
2079
                parameters[i].data.longdoublePointer = (argarray == NULL)
 
2080
                  ? va_arg(*arglist, trio_long_double_t *)
 
2081
                  : (trio_long_double_t *)argarray[num];
 
2082
              else
 
2083
                {
 
2084
                  if (parameters[i].flags & FLAGS_LONG)
 
2085
                    parameters[i].data.doublePointer = (argarray == NULL)
 
2086
                      ? va_arg(*arglist, double *)
 
2087
                      : (double *)argarray[num];
 
2088
                  else
 
2089
                    parameters[i].data.doublePointer = (argarray == NULL)
 
2090
                      ? (double *)va_arg(*arglist, float *)
 
2091
                      : (double *)((float *)argarray[num]);
 
2092
                }
 
2093
            }
 
2094
          else
 
2095
            {
 
2096
              if (parameters[i].flags & FLAGS_LONGDOUBLE)
 
2097
                parameters[i].data.longdoubleNumber = (argarray == NULL)
 
2098
                  ? va_arg(*arglist, trio_long_double_t)
 
2099
                  : (trio_long_double_t)(*((trio_long_double_t *)argarray[num]));
 
2100
              else
 
2101
                {
 
2102
                  if (argarray == NULL)
 
2103
                    parameters[i].data.longdoubleNumber =
 
2104
                      (trio_long_double_t)va_arg(*arglist, double);
 
2105
                  else
 
2106
                    {
 
2107
                      if (parameters[i].flags & FLAGS_SHORT)
 
2108
                        parameters[i].data.longdoubleNumber =
 
2109
                          (trio_long_double_t)(*((float *)argarray[num]));
 
2110
                      else
 
2111
                        parameters[i].data.longdoubleNumber =
 
2112
                          (trio_long_double_t)(*((double *)argarray[num]));
 
2113
                    }
 
2114
                }
 
2115
            }
 
2116
          break;
 
2117
 
 
2118
#if defined(FORMAT_ERRNO)
 
2119
        case FORMAT_ERRNO:
 
2120
          parameters[i].data.errorNumber = save_errno;
 
2121
          break;
 
2122
#endif
 
2123
 
 
2124
        default:
 
2125
          break;
 
2126
        }
 
2127
    } /* for all specifiers */
 
2128
  return num;
 
2129
}
 
2130
 
 
2131
 
 
2132
/*************************************************************************
 
2133
 *
 
2134
 * FORMATTING
 
2135
 *
 
2136
 ************************************************************************/
 
2137
 
 
2138
 
 
2139
/*************************************************************************
 
2140
 * TrioWriteNumber
 
2141
 *
 
2142
 * Description:
 
2143
 *  Output a number.
 
2144
 *  The complexity of this function is a result of the complexity
 
2145
 *  of the dependencies of the flags.
 
2146
 */
 
2147
TRIO_PRIVATE void
 
2148
TrioWriteNumber
 
2149
TRIO_ARGS6((self, number, flags, width, precision, base),
 
2150
           trio_class_t *self,
 
2151
           trio_uintmax_t number,
 
2152
           trio_flags_t flags,
 
2153
           int width,
 
2154
           int precision,
 
2155
           int base)
 
2156
{
 
2157
  BOOLEAN_T isNegative;
 
2158
  BOOLEAN_T isNumberZero;
 
2159
  BOOLEAN_T isPrecisionZero;
 
2160
  BOOLEAN_T ignoreNumber;
 
2161
  char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
 
2162
  char *bufferend;
 
2163
  char *pointer;
 
2164
  TRIO_CONST char *digits;
 
2165
  int i;
 
2166
  int length;
 
2167
  char *p;
 
2168
  int count;
 
2169
 
 
2170
  assert(VALID(self));
 
2171
  assert(VALID(self->OutStream));
 
2172
  assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
 
2173
 
 
2174
  digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
 
2175
  if (base == NO_BASE)
 
2176
    base = BASE_DECIMAL;
 
2177
 
 
2178
  isNumberZero = (number == 0);
 
2179
  isPrecisionZero = (precision == 0);
 
2180
  ignoreNumber = (isNumberZero
 
2181
                  && isPrecisionZero
 
2182
                  && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
 
2183
 
 
2184
  if (flags & FLAGS_UNSIGNED)
 
2185
    {
 
2186
      isNegative = FALSE;
 
2187
      flags &= ~FLAGS_SHOWSIGN;
 
2188
    }
 
2189
  else
 
2190
    {
 
2191
      isNegative = ((trio_intmax_t)number < 0);
 
2192
      if (isNegative)
 
2193
        number = -((trio_intmax_t)number);
 
2194
    }
 
2195
 
 
2196
  if (flags & FLAGS_QUAD)
 
2197
    number &= (trio_ulonglong_t)-1;
 
2198
  else if (flags & FLAGS_LONG)
 
2199
    number &= (unsigned long)-1;
 
2200
  else
 
2201
    number &= (unsigned int)-1;
 
2202
  
 
2203
  /* Build number */
 
2204
  pointer = bufferend = &buffer[sizeof(buffer) - 1];
 
2205
  *pointer-- = NIL;
 
2206
  for (i = 1; i < (int)sizeof(buffer); i++)
 
2207
    {
 
2208
      *pointer-- = digits[number % base];
 
2209
      number /= base;
 
2210
      if (number == 0)
 
2211
        break;
 
2212
 
 
2213
      if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
 
2214
        {
 
2215
          /*
 
2216
           * We are building the number from the least significant
 
2217
           * to the most significant digit, so we have to copy the
 
2218
           * thousand separator backwards
 
2219
           */
 
2220
          length = internalThousandSeparatorLength;
 
2221
          if (((int)(pointer - buffer) - length) > 0)
 
2222
            {
 
2223
              p = &internalThousandSeparator[length - 1];
 
2224
              while (length-- > 0)
 
2225
                *pointer-- = *p--;
 
2226
            }
 
2227
        }
 
2228
    }
 
2229
 
 
2230
  if (! ignoreNumber)
 
2231
    {
 
2232
      /* Adjust width */
 
2233
      width -= (bufferend - pointer) - 1;
 
2234
    }
 
2235
 
 
2236
  /* Adjust precision */
 
2237
  if (NO_PRECISION != precision)
 
2238
    {
 
2239
      precision -= (bufferend - pointer) - 1;
 
2240
      if (precision < 0)
 
2241
        precision = 0;
 
2242
      flags |= FLAGS_NILPADDING;
 
2243
    }
 
2244
 
 
2245
  /* Calculate padding */
 
2246
  count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
 
2247
    ? precision
 
2248
    : 0;
 
2249
  
 
2250
  /* Adjust width further */
 
2251
  if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
 
2252
    width--;
 
2253
  if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
 
2254
    {
 
2255
      switch (base)
 
2256
        {
 
2257
        case BASE_BINARY:
 
2258
        case BASE_HEX:
 
2259
          width -= 2;
 
2260
          break;
 
2261
        case BASE_OCTAL:
 
2262
          if (!(flags & FLAGS_NILPADDING) || (count == 0))
 
2263
            width--;
 
2264
          break;
 
2265
        default:
 
2266
          break;
 
2267
        }
 
2268
    }
 
2269
 
 
2270
  /* Output prefixes spaces if needed */
 
2271
  if (! ((flags & FLAGS_LEFTADJUST) ||
 
2272
         ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
 
2273
    {
 
2274
      while (width-- > count)
 
2275
        self->OutStream(self, CHAR_ADJUST);
 
2276
    }
 
2277
 
 
2278
  /* width has been adjusted for signs and alternatives */
 
2279
  if (isNegative)
 
2280
    self->OutStream(self, '-');
 
2281
  else if (flags & FLAGS_SHOWSIGN)
 
2282
    self->OutStream(self, '+');
 
2283
  else if (flags & FLAGS_SPACE)
 
2284
    self->OutStream(self, ' ');
 
2285
 
 
2286
  /* Prefix is not written when the value is zero */
 
2287
  if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
 
2288
    {
 
2289
      switch (base)
 
2290
        {
 
2291
        case BASE_BINARY:
 
2292
          self->OutStream(self, '0');
 
2293
          self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
 
2294
          break;
 
2295
 
 
2296
        case BASE_OCTAL:
 
2297
          if (!(flags & FLAGS_NILPADDING) || (count == 0))
 
2298
            self->OutStream(self, '0');
 
2299
          break;
 
2300
 
 
2301
        case BASE_HEX:
 
2302
          self->OutStream(self, '0');
 
2303
          self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
 
2304
          break;
 
2305
 
 
2306
        default:
 
2307
          break;
 
2308
        } /* switch base */
 
2309
    }
 
2310
 
 
2311
  /* Output prefixed zero padding if needed */
 
2312
  if (flags & FLAGS_NILPADDING)
 
2313
    {
 
2314
      if (precision == NO_PRECISION)
 
2315
        precision = width;
 
2316
      while (precision-- > 0)
 
2317
        {
 
2318
          self->OutStream(self, '0');
 
2319
          width--;
 
2320
        }
 
2321
    }
 
2322
 
 
2323
  if (! ignoreNumber)
 
2324
    {
 
2325
      /* Output the number itself */
 
2326
      while (*(++pointer))
 
2327
        {
 
2328
          self->OutStream(self, *pointer);
 
2329
        }
 
2330
    }
 
2331
 
 
2332
  /* Output trailing spaces if needed */
 
2333
  if (flags & FLAGS_LEFTADJUST)
 
2334
    {
 
2335
      while (width-- > 0)
 
2336
        self->OutStream(self, CHAR_ADJUST);
 
2337
    }
 
2338
}
 
2339
 
 
2340
/*************************************************************************
 
2341
 * TrioWriteStringCharacter
 
2342
 *
 
2343
 * Description:
 
2344
 *  Output a single character of a string
 
2345
 */
 
2346
TRIO_PRIVATE void
 
2347
TrioWriteStringCharacter
 
2348
TRIO_ARGS3((self, ch, flags),
 
2349
           trio_class_t *self,
 
2350
           int ch,
 
2351
           trio_flags_t flags)
 
2352
{
 
2353
  if (flags & FLAGS_ALTERNATIVE)
 
2354
    {
 
2355
      if (! isprint(ch))
 
2356
        {
 
2357
          /*
 
2358
           * Non-printable characters are converted to C escapes or
 
2359
           * \number, if no C escape exists.
 
2360
           */
 
2361
          self->OutStream(self, CHAR_BACKSLASH);
 
2362
          switch (ch)
 
2363
            {
 
2364
            case '\007': self->OutStream(self, 'a'); break;
 
2365
            case '\b': self->OutStream(self, 'b'); break;
 
2366
            case '\f': self->OutStream(self, 'f'); break;
 
2367
            case '\n': self->OutStream(self, 'n'); break;
 
2368
            case '\r': self->OutStream(self, 'r'); break;
 
2369
            case '\t': self->OutStream(self, 't'); break;
 
2370
            case '\v': self->OutStream(self, 'v'); break;
 
2371
            case '\\': self->OutStream(self, '\\'); break;
 
2372
            default:
 
2373
              self->OutStream(self, 'x');
 
2374
              TrioWriteNumber(self, (trio_uintmax_t)ch,
 
2375
                              FLAGS_UNSIGNED | FLAGS_NILPADDING,
 
2376
                              2, 2, BASE_HEX);
 
2377
              break;
 
2378
            }
 
2379
        }
 
2380
      else if (ch == CHAR_BACKSLASH)
 
2381
        {
 
2382
          self->OutStream(self, CHAR_BACKSLASH);
 
2383
          self->OutStream(self, CHAR_BACKSLASH);
 
2384
        }
 
2385
      else
 
2386
        {
 
2387
          self->OutStream(self, ch);
 
2388
        }
 
2389
    }
 
2390
  else
 
2391
    {
 
2392
      self->OutStream(self, ch);
 
2393
    }
 
2394
}
 
2395
 
 
2396
/*************************************************************************
 
2397
 * TrioWriteString
 
2398
 *
 
2399
 * Description:
 
2400
 *  Output a string
 
2401
 */
 
2402
TRIO_PRIVATE void
 
2403
TrioWriteString
 
2404
TRIO_ARGS5((self, string, flags, width, precision),
 
2405
           trio_class_t *self,
 
2406
           TRIO_CONST char *string,
 
2407
           trio_flags_t flags,
 
2408
           int width,
 
2409
           int precision)
 
2410
{
 
2411
  int length;
 
2412
  int ch;
 
2413
 
 
2414
  assert(VALID(self));
 
2415
  assert(VALID(self->OutStream));
 
2416
 
 
2417
  if (string == NULL)
 
2418
    {
 
2419
      string = internalNullString;
 
2420
      length = sizeof(internalNullString) - 1;
 
2421
      /* Disable quoting for the null pointer */
 
2422
      flags &= (~FLAGS_QUOTE);
 
2423
      width = 0;
 
2424
    }
 
2425
  else
 
2426
    {
 
2427
      length = trio_length(string);
 
2428
    }
 
2429
  if ((NO_PRECISION != precision) &&
 
2430
      (precision < length))
 
2431
    {
 
2432
      length = precision;
 
2433
    }
 
2434
  width -= length;
 
2435
 
 
2436
  if (flags & FLAGS_QUOTE)
 
2437
    self->OutStream(self, CHAR_QUOTE);
 
2438
 
 
2439
  if (! (flags & FLAGS_LEFTADJUST))
 
2440
    {
 
2441
      while (width-- > 0)
 
2442
        self->OutStream(self, CHAR_ADJUST);
 
2443
    }
 
2444
 
 
2445
  while (length-- > 0)
 
2446
    {
 
2447
      /* The ctype parameters must be an unsigned char (or EOF) */
 
2448
      ch = (int)((unsigned char)(*string++));
 
2449
      TrioWriteStringCharacter(self, ch, flags);
 
2450
    }
 
2451
 
 
2452
  if (flags & FLAGS_LEFTADJUST)
 
2453
    {
 
2454
      while (width-- > 0)
 
2455
        self->OutStream(self, CHAR_ADJUST);
 
2456
    }
 
2457
  if (flags & FLAGS_QUOTE)
 
2458
    self->OutStream(self, CHAR_QUOTE);
 
2459
}
 
2460
 
 
2461
/*************************************************************************
 
2462
 * TrioWriteWideStringCharacter
 
2463
 *
 
2464
 * Description:
 
2465
 *  Output a wide string as a multi-byte sequence
 
2466
 */
 
2467
#if TRIO_WIDECHAR
 
2468
TRIO_PRIVATE int
 
2469
TrioWriteWideStringCharacter
 
2470
TRIO_ARGS4((self, wch, flags, width),
 
2471
           trio_class_t *self,
 
2472
           trio_wchar_t wch,
 
2473
           trio_flags_t flags,
 
2474
           int width)
 
2475
{
 
2476
  int size;
 
2477
  int i;
 
2478
  int ch;
 
2479
  char *string;
 
2480
  char buffer[MB_LEN_MAX + 1];
 
2481
 
 
2482
  if (width == NO_WIDTH)
 
2483
    width = sizeof(buffer);
 
2484
  
 
2485
  size = wctomb(buffer, wch);
 
2486
  if ((size <= 0) || (size > width) || (buffer[0] == NIL))
 
2487
    return 0;
 
2488
 
 
2489
  string = buffer;
 
2490
  i = size;
 
2491
  while ((width >= i) && (width-- > 0) && (i-- > 0))
 
2492
    {
 
2493
      /* The ctype parameters must be an unsigned char (or EOF) */
 
2494
      ch = (int)((unsigned char)(*string++));
 
2495
      TrioWriteStringCharacter(self, ch, flags);
 
2496
    }
 
2497
  return size;
 
2498
}
 
2499
#endif /* TRIO_WIDECHAR */
 
2500
 
 
2501
/*************************************************************************
 
2502
 * TrioWriteWideString
 
2503
 *
 
2504
 * Description:
 
2505
 *  Output a wide character string as a multi-byte string
 
2506
 */
 
2507
#if TRIO_WIDECHAR
 
2508
TRIO_PRIVATE void
 
2509
TrioWriteWideString
 
2510
TRIO_ARGS5((self, wstring, flags, width, precision),
 
2511
           trio_class_t *self,
 
2512
           TRIO_CONST trio_wchar_t *wstring,
 
2513
           trio_flags_t flags,
 
2514
           int width,
 
2515
           int precision)
 
2516
{
 
2517
  int length;
 
2518
  int size;
 
2519
 
 
2520
  assert(VALID(self));
 
2521
  assert(VALID(self->OutStream));
 
2522
 
 
2523
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
2524
  (void)mblen(NULL, 0);
 
2525
#endif
 
2526
  
 
2527
  if (wstring == NULL)
 
2528
    {
 
2529
      TrioWriteString(self, NULL, flags, width, precision);
 
2530
      return;
 
2531
    }
 
2532
  
 
2533
  if (NO_PRECISION == precision)
 
2534
    {
 
2535
      length = INT_MAX;
 
2536
    }
 
2537
  else
 
2538
    {
 
2539
      length = precision;
 
2540
      width -= length;
 
2541
    }
 
2542
 
 
2543
  if (flags & FLAGS_QUOTE)
 
2544
    self->OutStream(self, CHAR_QUOTE);
 
2545
 
 
2546
  if (! (flags & FLAGS_LEFTADJUST))
 
2547
    {
 
2548
      while (width-- > 0)
 
2549
        self->OutStream(self, CHAR_ADJUST);
 
2550
    }
 
2551
 
 
2552
  while (length > 0)
 
2553
    {
 
2554
      size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
 
2555
      if (size == 0)
 
2556
        break; /* while */
 
2557
      length -= size;
 
2558
    }
 
2559
 
 
2560
  if (flags & FLAGS_LEFTADJUST)
 
2561
    {
 
2562
      while (width-- > 0)
 
2563
        self->OutStream(self, CHAR_ADJUST);
 
2564
    }
 
2565
  if (flags & FLAGS_QUOTE)
 
2566
    self->OutStream(self, CHAR_QUOTE);
 
2567
}
 
2568
#endif /* TRIO_WIDECHAR */
 
2569
 
 
2570
/*************************************************************************
 
2571
 * TrioWriteDouble
 
2572
 *
 
2573
 * http://wwwold.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_211.htm
 
2574
 *
 
2575
 * "5.2.4.2.2 paragraph #4
 
2576
 *
 
2577
 *  The accuracy [...] is implementation defined, as is the accuracy
 
2578
 *  of the conversion between floating-point internal representations
 
2579
 *  and string representations performed by the libray routine in
 
2580
 *  <stdio.h>"
 
2581
 */
 
2582
/* FIXME: handle all instances of constant long-double number (L)
 
2583
 *   and *l() math functions.
 
2584
 */
 
2585
TRIO_PRIVATE void
 
2586
TrioWriteDouble
 
2587
TRIO_ARGS6((self, number, flags, width, precision, base),
 
2588
           trio_class_t *self,
 
2589
           trio_long_double_t number,
 
2590
           trio_flags_t flags,
 
2591
           int width,
 
2592
           int precision,
 
2593
           int base)
 
2594
{
 
2595
  trio_long_double_t integerNumber;
 
2596
  trio_long_double_t fractionNumber;
 
2597
  trio_long_double_t workNumber;
 
2598
  int integerDigits;
 
2599
  int fractionDigits;
 
2600
  int exponentDigits;
 
2601
  int baseDigits;
 
2602
  int integerThreshold;
 
2603
  int fractionThreshold;
 
2604
  int expectedWidth;
 
2605
  int exponent = 0;
 
2606
  unsigned int uExponent = 0;
 
2607
  int exponentBase;
 
2608
  trio_long_double_t dblBase;
 
2609
  trio_long_double_t dblIntegerBase;
 
2610
  trio_long_double_t dblFractionBase;
 
2611
  trio_long_double_t integerAdjust;
 
2612
  trio_long_double_t fractionAdjust;
 
2613
  BOOLEAN_T isNegative;
 
2614
  BOOLEAN_T isExponentNegative = FALSE;
 
2615
  BOOLEAN_T requireTwoDigitExponent;
 
2616
  BOOLEAN_T isHex;
 
2617
  TRIO_CONST char *digits;
 
2618
  char *groupingPointer;
 
2619
  int i;
 
2620
  int index;
 
2621
  BOOLEAN_T hasOnlyZeroes;
 
2622
  int zeroes = 0;
 
2623
  register int trailingZeroes;
 
2624
  BOOLEAN_T keepTrailingZeroes;
 
2625
  BOOLEAN_T keepDecimalPoint;
 
2626
  trio_long_double_t epsilon;
 
2627
  
 
2628
  assert(VALID(self));
 
2629
  assert(VALID(self->OutStream));
 
2630
  assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
 
2631
 
 
2632
  /* Determine sign and look for special quantities */
 
2633
  switch (trio_fpclassify_and_signbit(number, &isNegative))
 
2634
    {
 
2635
    case TRIO_FP_NAN:
 
2636
      TrioWriteString(self,
 
2637
                      (flags & FLAGS_UPPER)
 
2638
                      ? NAN_UPPER
 
2639
                      : NAN_LOWER,
 
2640
                      flags, width, precision);
 
2641
      return;
 
2642
      
 
2643
    case TRIO_FP_INFINITE:
 
2644
      if (isNegative)
 
2645
        {
 
2646
          /* Negative infinity */
 
2647
          TrioWriteString(self,
 
2648
                          (flags & FLAGS_UPPER)
 
2649
                          ? "-" INFINITE_UPPER
 
2650
                          : "-" INFINITE_LOWER,
 
2651
                          flags, width, precision);
 
2652
          return;
 
2653
        }
 
2654
      else
 
2655
        {
 
2656
          /* Positive infinity */
 
2657
          TrioWriteString(self,
 
2658
                          (flags & FLAGS_UPPER)
 
2659
                          ? INFINITE_UPPER
 
2660
                          : INFINITE_LOWER,
 
2661
                          flags, width, precision);
 
2662
          return;
 
2663
        }
 
2664
 
 
2665
    default:
 
2666
      /* Finitude */
 
2667
      break;
 
2668
    }
 
2669
  
 
2670
  /* Normal numbers */
 
2671
  if (flags & FLAGS_LONGDOUBLE)
 
2672
    {
 
2673
      baseDigits = (base == 10)
 
2674
        ? LDBL_DIG
 
2675
        : (int)floor(LDBL_MANT_DIG / TrioLogarithmBase(base));
 
2676
      epsilon = LDBL_EPSILON;
 
2677
    }
 
2678
  else if (flags & FLAGS_SHORT)
 
2679
    {
 
2680
      baseDigits = (base == BASE_DECIMAL)
 
2681
        ? FLT_DIG
 
2682
        : (int)floor(FLT_MANT_DIG / TrioLogarithmBase(base));
 
2683
      epsilon = FLT_EPSILON;
 
2684
    }
 
2685
  else
 
2686
    {
 
2687
      baseDigits = (base == BASE_DECIMAL)
 
2688
        ? DBL_DIG
 
2689
        : (int)floor(DBL_MANT_DIG / TrioLogarithmBase(base));
 
2690
      epsilon = DBL_EPSILON;
 
2691
    }
 
2692
 
 
2693
  digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
 
2694
  isHex = (base == BASE_HEX);
 
2695
  if (base == NO_BASE)
 
2696
    base = BASE_DECIMAL;
 
2697
  dblBase = (trio_long_double_t)base;
 
2698
  keepTrailingZeroes = !( (flags & FLAGS_ROUNDING) ||
 
2699
                          ( (flags & FLAGS_FLOAT_G) &&
 
2700
                            !(flags & FLAGS_ALTERNATIVE) ) );
 
2701
 
 
2702
  if (flags & FLAGS_ROUNDING)
 
2703
    precision = baseDigits;
 
2704
 
 
2705
  if (precision == NO_PRECISION)
 
2706
    {
 
2707
      if (isHex)
 
2708
        {
 
2709
          keepTrailingZeroes = FALSE;
 
2710
          precision = FLT_MANT_DIG;
 
2711
        }
 
2712
      else
 
2713
        {
 
2714
          precision = FLT_DIG;
 
2715
        }
 
2716
    }
 
2717
  
 
2718
  if (isNegative)
 
2719
    number = -number;
 
2720
 
 
2721
  if (isHex)
 
2722
    flags |= FLAGS_FLOAT_E;
 
2723
  
 
2724
  if (flags & FLAGS_FLOAT_G)
 
2725
    {
 
2726
      if (precision == 0)
 
2727
        precision = 1;
 
2728
 
 
2729
      if ((number < 1.0E-4) || (number > powl(base,
 
2730
                                              (trio_long_double_t)precision)))
 
2731
        {
 
2732
          /* Use scientific notation */
 
2733
          flags |= FLAGS_FLOAT_E;
 
2734
        }
 
2735
      else if (number < 1.0)
 
2736
        {
 
2737
          /*
 
2738
           * Use normal notation. If the integer part of the number is
 
2739
           * zero, then adjust the precision to include leading fractional
 
2740
           * zeros.
 
2741
           */
 
2742
          workNumber = TrioLogarithm(number, base);
 
2743
          workNumber = TRIO_FABS(workNumber);
 
2744
          if (workNumber - floorl(workNumber) < 0.001)
 
2745
            workNumber--;
 
2746
          zeroes = (int)floorl(workNumber);
 
2747
        }
 
2748
    }
 
2749
 
 
2750
  if (flags & FLAGS_FLOAT_E)
 
2751
    {
 
2752
      /* Scale the number */
 
2753
      workNumber = TrioLogarithm(number, base);
 
2754
      if (trio_isinf(workNumber) == -1)
 
2755
        {
 
2756
          exponent = 0;
 
2757
          /* Undo setting */
 
2758
          if (flags & FLAGS_FLOAT_G)
 
2759
            flags &= ~FLAGS_FLOAT_E;
 
2760
        }
 
2761
      else
 
2762
        {
 
2763
          exponent = (int)floorl(workNumber);
 
2764
          number /= powl(dblBase, (trio_long_double_t)exponent);
 
2765
          isExponentNegative = (exponent < 0);
 
2766
          uExponent = (isExponentNegative) ? -exponent : exponent;
 
2767
          if (isHex)
 
2768
            uExponent *= 4; /* log16(2) */
 
2769
          /* No thousand separators */
 
2770
          flags &= ~FLAGS_QUOTE;
 
2771
        }
 
2772
    }
 
2773
 
 
2774
  integerNumber = floorl(number);
 
2775
  fractionNumber = number - integerNumber;
 
2776
  
 
2777
  /*
 
2778
   * Truncated number.
 
2779
   *
 
2780
   * Precision is number of significant digits for FLOAT_G
 
2781
   * and number of fractional digits for others.
 
2782
   */
 
2783
  integerDigits = (integerNumber > epsilon)
 
2784
    ? 1 + (int)TrioLogarithm(integerNumber, base)
 
2785
    : 1;
 
2786
  fractionDigits = ((flags & FLAGS_FLOAT_G) && (zeroes == 0))
 
2787
    ? precision - integerDigits
 
2788
    : zeroes + precision;
 
2789
 
 
2790
  dblFractionBase = TrioPower(base, fractionDigits);
 
2791
  
 
2792
  workNumber = number + 0.5 / dblFractionBase;
 
2793
  if (floorl(number) != floorl(workNumber))
 
2794
    {
 
2795
      if (flags & FLAGS_FLOAT_E)
 
2796
        {
 
2797
          /* Adjust if number was rounded up one digit (ie. 0.99 to 1.00) */
 
2798
          exponent++;
 
2799
          isExponentNegative = (exponent < 0);
 
2800
          uExponent = (isExponentNegative) ? -exponent : exponent;
 
2801
          if (isHex)
 
2802
            uExponent *= 4; /* log16(2) */
 
2803
          workNumber = (number + 0.5 / dblFractionBase) / dblBase;
 
2804
          integerNumber = floorl(workNumber);
 
2805
          fractionNumber = workNumber - integerNumber;
 
2806
        }
 
2807
      else
 
2808
        {
 
2809
          /* Adjust if number was rounded up one digit (ie. 99 to 100) */
 
2810
          integerNumber = floorl(number + 0.5);
 
2811
          fractionNumber = 0.0;
 
2812
          integerDigits = (integerNumber > epsilon)
 
2813
            ? 1 + (int)TrioLogarithm(integerNumber, base)
 
2814
            : 1;
 
2815
        }
 
2816
    }
 
2817
 
 
2818
  /* Estimate accuracy */
 
2819
  integerAdjust = fractionAdjust = 0.5;
 
2820
  if (flags & FLAGS_ROUNDING)
 
2821
    {
 
2822
      if (integerDigits > baseDigits)
 
2823
        {
 
2824
          integerThreshold = baseDigits;
 
2825
          fractionDigits = 0;
 
2826
          dblFractionBase = 1.0;
 
2827
          fractionThreshold = 0;
 
2828
          precision = 0; /* Disable decimal-point */
 
2829
          integerAdjust = TrioPower(base, integerDigits - integerThreshold - 1);
 
2830
          fractionAdjust = 0.0;
 
2831
        }
 
2832
      else
 
2833
        {
 
2834
          integerThreshold = integerDigits;
 
2835
          fractionThreshold = fractionDigits - integerThreshold;
 
2836
          fractionAdjust = 1.0;
 
2837
        }
 
2838
    }
 
2839
  else
 
2840
    {
 
2841
      integerThreshold = INT_MAX;
 
2842
      fractionThreshold = INT_MAX;
 
2843
    }
 
2844
  
 
2845
  /*
 
2846
   * Calculate expected width.
 
2847
   *  sign + integer part + thousands separators + decimal point
 
2848
   *  + fraction + exponent
 
2849
   */
 
2850
  fractionAdjust /= dblFractionBase;
 
2851
  hasOnlyZeroes = (floorl((fractionNumber + fractionAdjust) * dblFractionBase) < epsilon);
 
2852
  keepDecimalPoint = ( (flags & FLAGS_ALTERNATIVE) ||
 
2853
                       !((precision == 0) ||
 
2854
                         (!keepTrailingZeroes && hasOnlyZeroes)) );
 
2855
  if (flags & FLAGS_FLOAT_E)
 
2856
    {
 
2857
      exponentDigits = (uExponent == 0)
 
2858
        ? 1
 
2859
        : (int)ceil(TrioLogarithm((double)(uExponent + 1),
 
2860
                                  (isHex) ? 10.0 : base));
 
2861
    }
 
2862
  else
 
2863
    exponentDigits = 0;
 
2864
  requireTwoDigitExponent = ((base == BASE_DECIMAL) && (exponentDigits == 1));
 
2865
 
 
2866
  expectedWidth = integerDigits + fractionDigits
 
2867
    + (keepDecimalPoint
 
2868
       ? internalDecimalPointLength
 
2869
       : 0)
 
2870
    + ((flags & FLAGS_QUOTE)
 
2871
       ? TrioCalcThousandSeparatorLength(integerDigits)
 
2872
       : 0);
 
2873
  if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
 
2874
    expectedWidth += sizeof("-") - 1;
 
2875
  if (exponentDigits > 0)
 
2876
    expectedWidth += exponentDigits +
 
2877
      ((requireTwoDigitExponent ? sizeof("E+0") : sizeof("E+")) - 1);
 
2878
  if (isHex)
 
2879
    expectedWidth += sizeof("0X") - 1;
 
2880
  
 
2881
  /* Output prefixing */
 
2882
  if (flags & FLAGS_NILPADDING)
 
2883
    {
 
2884
      /* Leading zeros must be after sign */
 
2885
      if (isNegative)
 
2886
        self->OutStream(self, '-');
 
2887
      else if (flags & FLAGS_SHOWSIGN)
 
2888
        self->OutStream(self, '+');
 
2889
      else if (flags & FLAGS_SPACE)
 
2890
        self->OutStream(self, ' ');
 
2891
      if (isHex)
 
2892
        {
 
2893
          self->OutStream(self, '0');
 
2894
          self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
 
2895
        }
 
2896
      if (!(flags & FLAGS_LEFTADJUST))
 
2897
        {
 
2898
          for (i = expectedWidth; i < width; i++)
 
2899
            {
 
2900
              self->OutStream(self, '0');
 
2901
            }
 
2902
        }
 
2903
    }
 
2904
  else
 
2905
    {
 
2906
      /* Leading spaces must be before sign */
 
2907
      if (!(flags & FLAGS_LEFTADJUST))
 
2908
        {
 
2909
          for (i = expectedWidth; i < width; i++)
 
2910
            {
 
2911
              self->OutStream(self, CHAR_ADJUST);
 
2912
            }
 
2913
        }
 
2914
      if (isNegative)
 
2915
        self->OutStream(self, '-');
 
2916
      else if (flags & FLAGS_SHOWSIGN)
 
2917
        self->OutStream(self, '+');
 
2918
      else if (flags & FLAGS_SPACE)
 
2919
        self->OutStream(self, ' ');
 
2920
      if (isHex)
 
2921
        {
 
2922
          self->OutStream(self, '0');
 
2923
          self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
 
2924
        }
 
2925
    }
 
2926
  
 
2927
  /* Output the integer part and thousand separators */
 
2928
  dblIntegerBase = 1.0 / TrioPower(base, integerDigits - 1);
 
2929
  for (i = 0; i < integerDigits; i++)
 
2930
    {
 
2931
      workNumber = floorl(((integerNumber + integerAdjust) * dblIntegerBase));
 
2932
      if (i > integerThreshold)
 
2933
        {
 
2934
          /* Beyond accuracy */
 
2935
          self->OutStream(self, digits[0]);
 
2936
        }
 
2937
      else
 
2938
        {
 
2939
          self->OutStream(self, digits[(int)fmodl(workNumber, dblBase)]);
 
2940
        }
 
2941
      dblIntegerBase *= dblBase;
 
2942
      
 
2943
      if (((flags & (FLAGS_FLOAT_E | FLAGS_QUOTE)) == FLAGS_QUOTE)
 
2944
          && TrioFollowedBySeparator(integerDigits - i))
 
2945
        {
 
2946
          for (groupingPointer = internalThousandSeparator;
 
2947
               *groupingPointer != NIL;
 
2948
               groupingPointer++)
 
2949
            {
 
2950
              self->OutStream(self, *groupingPointer);
 
2951
            }
 
2952
        }
 
2953
    }
 
2954
  
 
2955
  /* Insert decimal point and build the fraction part */
 
2956
  trailingZeroes = 0;
 
2957
 
 
2958
  if (keepDecimalPoint)
 
2959
    {
 
2960
      if (internalDecimalPoint)
 
2961
        {
 
2962
          self->OutStream(self, internalDecimalPoint);
 
2963
        }
 
2964
      else
 
2965
        {
 
2966
          for (i = 0; i < internalDecimalPointLength; i++)
 
2967
            {
 
2968
              self->OutStream(self, internalDecimalPointString[i]);
 
2969
            }
 
2970
        }
 
2971
    }
 
2972
 
 
2973
  for (i = 0; i < fractionDigits; i++)
 
2974
    {
 
2975
      if ((integerDigits > integerThreshold) || (i > fractionThreshold))
 
2976
        {
 
2977
          /* Beyond accuracy */
 
2978
          trailingZeroes++;
 
2979
        }
 
2980
      else
 
2981
        {
 
2982
          fractionNumber *= dblBase;
 
2983
          fractionAdjust *= dblBase;
 
2984
          workNumber = floorl(fractionNumber + fractionAdjust);
 
2985
          fractionNumber -= workNumber;
 
2986
          index = (int)fmodl(workNumber, dblBase);
 
2987
          if (index == 0)
 
2988
            {
 
2989
              trailingZeroes++;
 
2990
            }
 
2991
          else
 
2992
            {
 
2993
              while (trailingZeroes > 0)
 
2994
                {
 
2995
                  /* Not trailing zeroes after all */
 
2996
                  self->OutStream(self, digits[0]);
 
2997
                  trailingZeroes--;
 
2998
                }
 
2999
              self->OutStream(self, digits[index]);
 
3000
            }
 
3001
        }
 
3002
    }
 
3003
  
 
3004
  if (keepTrailingZeroes)
 
3005
    {
 
3006
      while (trailingZeroes > 0)
 
3007
        {
 
3008
          self->OutStream(self, digits[0]);
 
3009
          trailingZeroes--;
 
3010
        }
 
3011
    }
 
3012
  
 
3013
  /* Output exponent */
 
3014
  if (exponentDigits > 0)
 
3015
    {
 
3016
      self->OutStream(self,
 
3017
                      isHex
 
3018
                      ? ((flags & FLAGS_UPPER) ? 'P' : 'p')
 
3019
                      : ((flags & FLAGS_UPPER) ? 'E' : 'e'));
 
3020
      self->OutStream(self, (isExponentNegative) ? '-' : '+');
 
3021
 
 
3022
      /* The exponent must contain at least two digits */
 
3023
      if (requireTwoDigitExponent)
 
3024
        self->OutStream(self, '0');
 
3025
 
 
3026
      if (isHex)
 
3027
        base = 10.0;
 
3028
      exponentBase = (int)TrioPower(base, exponentDigits - 1);
 
3029
      for (i = 0; i < exponentDigits; i++)
 
3030
        {
 
3031
          self->OutStream(self, digits[(uExponent / exponentBase) % base]);
 
3032
          exponentBase /= base;
 
3033
        }
 
3034
    }
 
3035
  /* Output trailing spaces */
 
3036
  if (flags & FLAGS_LEFTADJUST)
 
3037
    {
 
3038
      for (i = expectedWidth; i < width; i++)
 
3039
        {
 
3040
          self->OutStream(self, CHAR_ADJUST);
 
3041
        }
 
3042
    }
 
3043
}
 
3044
 
 
3045
/*************************************************************************
 
3046
 * TrioFormatProcess
 
3047
 *
 
3048
 * Description:
 
3049
 *  This is the main engine for formatting output
 
3050
 */
 
3051
TRIO_PRIVATE int
 
3052
TrioFormatProcess
 
3053
TRIO_ARGS3((data, format, parameters),
 
3054
           trio_class_t *data,
 
3055
           TRIO_CONST char *format,
 
3056
           trio_parameter_t *parameters)
 
3057
{
 
3058
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
3059
  int charlen;
 
3060
#endif
 
3061
  int i;
 
3062
  TRIO_CONST char *string;
 
3063
  trio_pointer_t pointer;
 
3064
  trio_flags_t flags;
 
3065
  int width;
 
3066
  int precision;
 
3067
  int base;
 
3068
  int index;
 
3069
  
 
3070
  index = 0;
 
3071
  i = 0;
 
3072
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
3073
  (void)mblen(NULL, 0);
 
3074
#endif
 
3075
  
 
3076
  while (format[index])
 
3077
    {
 
3078
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
3079
      if (! isascii(format[index]))
 
3080
        {
 
3081
          charlen = mblen(&format[index], MB_LEN_MAX);
 
3082
          /*
 
3083
           * Only valid multibyte characters are handled here. Invalid
 
3084
           * multibyte characters (charlen == -1) are handled as normal
 
3085
           * characters.
 
3086
           */
 
3087
          if (charlen != -1)
 
3088
            {
 
3089
              while (charlen-- > 0)
 
3090
                {
 
3091
                  data->OutStream(data, format[index++]);
 
3092
                }
 
3093
              continue; /* while characters left in formatting string */
 
3094
            }
 
3095
        }
 
3096
#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
 
3097
      if (CHAR_IDENTIFIER == format[index])
 
3098
        {
 
3099
          if (CHAR_IDENTIFIER == format[index + 1])
 
3100
            {
 
3101
              data->OutStream(data, CHAR_IDENTIFIER);
 
3102
              index += 2;
 
3103
            }
 
3104
          else
 
3105
            {
 
3106
              /* Skip the parameter entries */
 
3107
              while (parameters[i].type == FORMAT_PARAMETER)
 
3108
                i++;
 
3109
              
 
3110
              flags = parameters[i].flags;
 
3111
 
 
3112
              /* Find width */
 
3113
              width = parameters[i].width;
 
3114
              if (flags & FLAGS_WIDTH_PARAMETER)
 
3115
                {
 
3116
                  /* Get width from parameter list */
 
3117
                  width = (int)parameters[width].data.number.as_signed;
 
3118
                  if (width < 0)
 
3119
                    {
 
3120
                      /*
 
3121
                       * A negative width is the same as the - flag and
 
3122
                       * a positive width.
 
3123
                       */
 
3124
                      flags |= FLAGS_LEFTADJUST;
 
3125
                      flags &= ~FLAGS_NILPADDING;
 
3126
                      width = -width;
 
3127
                    }
 
3128
                }
 
3129
              
 
3130
              /* Find precision */
 
3131
              if (flags & FLAGS_PRECISION)
 
3132
                {
 
3133
                  precision = parameters[i].precision;
 
3134
                  if (flags & FLAGS_PRECISION_PARAMETER)
 
3135
                    {
 
3136
                      /* Get precision from parameter list */
 
3137
                      precision = (int)parameters[precision].data.number.as_signed;
 
3138
                      if (precision < 0)
 
3139
                        {
 
3140
                          /*
 
3141
                           * A negative precision is the same as no
 
3142
                           * precision
 
3143
                           */
 
3144
                          precision = NO_PRECISION;
 
3145
                        }
 
3146
                    }
 
3147
                }
 
3148
              else
 
3149
                {
 
3150
                  precision = NO_PRECISION;
 
3151
                }
 
3152
 
 
3153
              /* Find base */
 
3154
              base = parameters[i].base;
 
3155
              if (flags & FLAGS_BASE_PARAMETER)
 
3156
                {
 
3157
                  /* Get base from parameter list */
 
3158
                  base = (int)parameters[base].data.number.as_signed;
 
3159
                }
 
3160
              
 
3161
              switch (parameters[i].type)
 
3162
                {
 
3163
                case FORMAT_CHAR:
 
3164
                  if (flags & FLAGS_QUOTE)
 
3165
                    data->OutStream(data, CHAR_QUOTE);
 
3166
                  if (! (flags & FLAGS_LEFTADJUST))
 
3167
                    {
 
3168
                      while (--width > 0)
 
3169
                        data->OutStream(data, CHAR_ADJUST);
 
3170
                    }
 
3171
#if TRIO_WIDECHAR
 
3172
                  if (flags & FLAGS_WIDECHAR)
 
3173
                    {
 
3174
                      TrioWriteWideStringCharacter(data,
 
3175
                                                   (trio_wchar_t)parameters[i].data.number.as_signed,
 
3176
                                                   flags,
 
3177
                                                   NO_WIDTH);
 
3178
                    }
 
3179
                  else
 
3180
#endif
 
3181
                    {
 
3182
                      TrioWriteStringCharacter(data,
 
3183
                                               (int)parameters[i].data.number.as_signed,
 
3184
                                               flags);
 
3185
                    }
 
3186
 
 
3187
                  if (flags & FLAGS_LEFTADJUST)
 
3188
                    {
 
3189
                      while(--width > 0)
 
3190
                        data->OutStream(data, CHAR_ADJUST);
 
3191
                    }
 
3192
                  if (flags & FLAGS_QUOTE)
 
3193
                    data->OutStream(data, CHAR_QUOTE);
 
3194
 
 
3195
                  break; /* FORMAT_CHAR */
 
3196
 
 
3197
                case FORMAT_INT:
 
3198
                  TrioWriteNumber(data,
 
3199
                                  parameters[i].data.number.as_unsigned,
 
3200
                                  flags,
 
3201
                                  width,
 
3202
                                  precision,
 
3203
                                  base);
 
3204
 
 
3205
                  break; /* FORMAT_INT */
 
3206
 
 
3207
                case FORMAT_DOUBLE:
 
3208
                  TrioWriteDouble(data,
 
3209
                                  parameters[i].data.longdoubleNumber,
 
3210
                                  flags,
 
3211
                                  width,
 
3212
                                  precision,
 
3213
                                  base);
 
3214
                  break; /* FORMAT_DOUBLE */
 
3215
 
 
3216
                case FORMAT_STRING:
 
3217
#if TRIO_WIDECHAR
 
3218
                  if (flags & FLAGS_WIDECHAR)
 
3219
                    {
 
3220
                      TrioWriteWideString(data,
 
3221
                                          parameters[i].data.wstring,
 
3222
                                          flags,
 
3223
                                          width,
 
3224
                                          precision);
 
3225
                    }
 
3226
                  else
 
3227
#endif
 
3228
                    {
 
3229
                      TrioWriteString(data,
 
3230
                                      parameters[i].data.string,
 
3231
                                      flags,
 
3232
                                      width,
 
3233
                                      precision);
 
3234
                    }
 
3235
                  break; /* FORMAT_STRING */
 
3236
 
 
3237
                case FORMAT_POINTER:
 
3238
                  {
 
3239
                    trio_reference_t reference;
 
3240
                    
 
3241
                    reference.data = data;
 
3242
                    reference.parameter = &parameters[i];
 
3243
                    trio_print_pointer(&reference, parameters[i].data.pointer);
 
3244
                  }
 
3245
                  break; /* FORMAT_POINTER */
 
3246
 
 
3247
                case FORMAT_COUNT:
 
3248
                  pointer = parameters[i].data.pointer;
 
3249
                  if (NULL != pointer)
 
3250
                    {
 
3251
                      /*
 
3252
                       * C99 paragraph 7.19.6.1.8 says "the number of
 
3253
                       * characters written to the output stream so far by
 
3254
                       * this call", which is data->committed
 
3255
                       */
 
3256
#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 
3257
                      if (flags & FLAGS_SIZE_T)
 
3258
                        *(size_t *)pointer = (size_t)data->committed;
 
3259
                      else
 
3260
#endif
 
3261
#if defined(QUALIFIER_PTRDIFF_T)
 
3262
                      if (flags & FLAGS_PTRDIFF_T)
 
3263
                        *(ptrdiff_t *)pointer = (ptrdiff_t)data->committed;
 
3264
                      else
 
3265
#endif
 
3266
#if defined(QUALIFIER_INTMAX_T)
 
3267
                      if (flags & FLAGS_INTMAX_T)
 
3268
                        *(trio_intmax_t *)pointer = (trio_intmax_t)data->committed;
 
3269
                      else
 
3270
#endif
 
3271
                      if (flags & FLAGS_QUAD)
 
3272
                        {
 
3273
                          *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->committed;
 
3274
                        }
 
3275
                      else if (flags & FLAGS_LONG)
 
3276
                        {
 
3277
                          *(long int *)pointer = (long int)data->committed;
 
3278
                        }
 
3279
                      else if (flags & FLAGS_SHORT)
 
3280
                        {
 
3281
                          *(short int *)pointer = (short int)data->committed;
 
3282
                        }
 
3283
                      else
 
3284
                        {
 
3285
                          *(int *)pointer = (int)data->committed;
 
3286
                        }
 
3287
                    }
 
3288
                  break; /* FORMAT_COUNT */
 
3289
 
 
3290
                case FORMAT_PARAMETER:
 
3291
                  break; /* FORMAT_PARAMETER */
 
3292
 
 
3293
#if defined(FORMAT_ERRNO)
 
3294
                case FORMAT_ERRNO:
 
3295
                  string = trio_error(parameters[i].data.errorNumber);
 
3296
                  if (string)
 
3297
                    {
 
3298
                      TrioWriteString(data,
 
3299
                                      string,
 
3300
                                      flags,
 
3301
                                      width,
 
3302
                                      precision);
 
3303
                    }
 
3304
                  else
 
3305
                    {
 
3306
                      data->OutStream(data, '#');
 
3307
                      TrioWriteNumber(data,
 
3308
                                      (trio_uintmax_t)parameters[i].data.errorNumber,
 
3309
                                      flags,
 
3310
                                      width,
 
3311
                                      precision,
 
3312
                                      BASE_DECIMAL);
 
3313
                    }
 
3314
                  break; /* FORMAT_ERRNO */
 
3315
#endif /* defined(FORMAT_ERRNO) */
 
3316
 
 
3317
#if defined(FORMAT_USER_DEFINED)
 
3318
                case FORMAT_USER_DEFINED:
 
3319
                  {
 
3320
                    trio_reference_t reference;
 
3321
                    trio_userdef_t *def = NULL;
 
3322
 
 
3323
                    if (parameters[i].user_name[0] == NIL)
 
3324
                      {
 
3325
                        /* Use handle */
 
3326
                        if ((i > 0) ||
 
3327
                            (parameters[i - 1].type == FORMAT_PARAMETER))
 
3328
                          def = (trio_userdef_t *)parameters[i - 1].data.pointer;
 
3329
                      }
 
3330
                    else
 
3331
                      {
 
3332
                        /* Look up namespace */
 
3333
                        def = TrioFindNamespace(parameters[i].user_name, NULL);
 
3334
                      }
 
3335
                    if (def) {
 
3336
                      reference.data = data;
 
3337
                      reference.parameter = &parameters[i];
 
3338
                      def->callback(&reference);
 
3339
                    }
 
3340
                  }
 
3341
                  break;
 
3342
#endif /* defined(FORMAT_USER_DEFINED) */
 
3343
                  
 
3344
                default:
 
3345
                  break;
 
3346
                } /* switch parameter type */
 
3347
 
 
3348
              /* Prepare for next */
 
3349
              index = parameters[i].indexAfterSpecifier;
 
3350
              i++;
 
3351
            }
 
3352
        }
 
3353
      else /* not identifier */
 
3354
        {
 
3355
          data->OutStream(data, format[index++]);
 
3356
        }
 
3357
    }
 
3358
  return data->processed;
 
3359
}
 
3360
 
 
3361
/*************************************************************************
 
3362
 * TrioFormatRef
 
3363
 */
 
3364
TRIO_PRIVATE int
 
3365
TrioFormatRef
 
3366
TRIO_ARGS4((reference, format, arglist, argarray),
 
3367
           trio_reference_t *reference,
 
3368
           TRIO_CONST char *format,
 
3369
           va_list *arglist,
 
3370
           trio_pointer_t *argarray)
 
3371
{
 
3372
  int status;
 
3373
  trio_parameter_t parameters[MAX_PARAMETERS];
 
3374
 
 
3375
  status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
 
3376
  if (status < 0)
 
3377
    return status;
 
3378
 
 
3379
  status = TrioFormatProcess(reference->data, format, parameters);
 
3380
  if (reference->data->error != 0)
 
3381
    {
 
3382
      status = reference->data->error;
 
3383
    }
 
3384
  return status;
 
3385
}
 
3386
 
 
3387
/*************************************************************************
 
3388
 * TrioFormat
 
3389
 */
 
3390
TRIO_PRIVATE int
 
3391
TrioFormat
 
3392
TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
 
3393
           trio_pointer_t destination,
 
3394
           size_t destinationSize,
 
3395
           void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
 
3396
           TRIO_CONST char *format,
 
3397
           va_list *arglist,
 
3398
           trio_pointer_t *argarray)
 
3399
{
 
3400
  int status;
 
3401
  trio_class_t data;
 
3402
  trio_parameter_t parameters[MAX_PARAMETERS];
 
3403
 
 
3404
  assert(VALID(OutStream));
 
3405
  assert(VALID(format));
 
3406
 
 
3407
  memset(&data, 0, sizeof(data));
 
3408
  data.OutStream = OutStream;
 
3409
  data.location = destination;
 
3410
  data.max = destinationSize;
 
3411
  data.error = 0;
 
3412
 
 
3413
#if defined(USE_LOCALE)
 
3414
  if (NULL == internalLocaleValues)
 
3415
    {
 
3416
      TrioSetLocale();
 
3417
    }
 
3418
#endif
 
3419
 
 
3420
  status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
 
3421
  if (status < 0)
 
3422
    return status;
 
3423
 
 
3424
  status = TrioFormatProcess(&data, format, parameters);
 
3425
  if (data.error != 0)
 
3426
    {
 
3427
      status = data.error;
 
3428
    }
 
3429
  return status;
 
3430
}
 
3431
 
 
3432
/*************************************************************************
 
3433
 * TrioOutStreamFile
 
3434
 */
 
3435
TRIO_PRIVATE void
 
3436
TrioOutStreamFile
 
3437
TRIO_ARGS2((self, output),
 
3438
           trio_class_t *self,
 
3439
           int output)
 
3440
{
 
3441
  FILE *file;
 
3442
 
 
3443
  assert(VALID(self));
 
3444
  assert(VALID(self->location));
 
3445
 
 
3446
  file = (FILE *)self->location;
 
3447
  self->processed++;
 
3448
  if (fputc(output, file) == EOF)
 
3449
    {
 
3450
      self->error = TRIO_ERROR_RETURN(TRIO_EOF, 0);
 
3451
    }
 
3452
  else
 
3453
    {
 
3454
      self->committed++;
 
3455
    }
 
3456
}
 
3457
 
 
3458
/*************************************************************************
 
3459
 * TrioOutStreamFileDescriptor
 
3460
 */
 
3461
TRIO_PRIVATE void
 
3462
TrioOutStreamFileDescriptor
 
3463
TRIO_ARGS2((self, output),
 
3464
           trio_class_t *self,
 
3465
           int output)
 
3466
{
 
3467
  int fd;
 
3468
  char ch;
 
3469
 
 
3470
  assert(VALID(self));
 
3471
 
 
3472
  fd = *((int *)self->location);
 
3473
  ch = (char)output;
 
3474
  self->processed++;
 
3475
  if (write(fd, &ch, sizeof(char)) == -1)
 
3476
    {
 
3477
      self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
 
3478
    }
 
3479
  else
 
3480
    {
 
3481
      self->committed++;
 
3482
    }
 
3483
}
 
3484
 
 
3485
/*************************************************************************
 
3486
 * TrioOutStreamCustom
 
3487
 */
 
3488
TRIO_PRIVATE void
 
3489
TrioOutStreamCustom
 
3490
TRIO_ARGS2((self, output),
 
3491
           trio_class_t *self,
 
3492
           int output)
 
3493
{
 
3494
  int status;
 
3495
  trio_custom_t *data;
 
3496
 
 
3497
  assert(VALID(self));
 
3498
  assert(VALID(self->location));
 
3499
 
 
3500
  data = (trio_custom_t *)self->location;
 
3501
  if (data->stream.out)
 
3502
    {
 
3503
      status = (data->stream.out)(data->closure, output);
 
3504
      if (status >= 0)
 
3505
        {
 
3506
          self->committed++;
 
3507
        }
 
3508
      else
 
3509
        {
 
3510
          if (self->error == 0)
 
3511
            {
 
3512
              self->error = TRIO_ERROR_RETURN(TRIO_ECUSTOM, -status);
 
3513
            }
 
3514
        }
 
3515
    }
 
3516
  self->processed++;
 
3517
}
 
3518
 
 
3519
/*************************************************************************
 
3520
 * TrioOutStreamString
 
3521
 */
 
3522
TRIO_PRIVATE void
 
3523
TrioOutStreamString
 
3524
TRIO_ARGS2((self, output),
 
3525
           trio_class_t *self,
 
3526
           int output)
 
3527
{
 
3528
  char **buffer;
 
3529
 
 
3530
  assert(VALID(self));
 
3531
  assert(VALID(self->location));
 
3532
 
 
3533
  buffer = (char **)self->location;
 
3534
  **buffer = (char)output;
 
3535
  (*buffer)++;
 
3536
  self->processed++;
 
3537
  self->committed++;
 
3538
}
 
3539
 
 
3540
/*************************************************************************
 
3541
 * TrioOutStreamStringMax
 
3542
 */
 
3543
TRIO_PRIVATE void
 
3544
TrioOutStreamStringMax
 
3545
TRIO_ARGS2((self, output),
 
3546
           trio_class_t *self,
 
3547
           int output)
 
3548
{
 
3549
  char **buffer;
 
3550
 
 
3551
  assert(VALID(self));
 
3552
  assert(VALID(self->location));
 
3553
  
 
3554
  buffer = (char **)self->location;
 
3555
 
 
3556
  if (self->processed < self->max)
 
3557
    {
 
3558
      **buffer = (char)output;
 
3559
      (*buffer)++;
 
3560
      self->committed++;
 
3561
    }
 
3562
  self->processed++;
 
3563
}
 
3564
 
 
3565
/*************************************************************************
 
3566
 * TrioOutStreamStringDynamic
 
3567
 */
 
3568
TRIO_PRIVATE void
 
3569
TrioOutStreamStringDynamic
 
3570
TRIO_ARGS2((self, output),
 
3571
           trio_class_t *self,
 
3572
           int output)
 
3573
{
 
3574
  assert(VALID(self));
 
3575
  assert(VALID(self->location));
 
3576
 
 
3577
  if (self->error == 0)
 
3578
    {
 
3579
      trio_xstring_append_char((trio_string_t *)self->location,
 
3580
                               (char)output);
 
3581
      self->committed++;
 
3582
    }
 
3583
  /* The processed variable must always be increased */
 
3584
  self->processed++;
 
3585
}
 
3586
 
 
3587
/*************************************************************************
 
3588
 *
 
3589
 * Formatted printing functions
 
3590
 *
 
3591
 ************************************************************************/
 
3592
 
 
3593
#if defined(TRIO_DOCUMENTATION)
 
3594
# include "doc/doc_printf.h"
 
3595
#endif
 
3596
/** @addtogroup Printf
 
3597
    @{
 
3598
*/
 
3599
 
 
3600
/*************************************************************************
 
3601
 * printf
 
3602
 */
 
3603
 
 
3604
/**
 
3605
   Print to standard output stream.
 
3606
 
 
3607
   @param format Formatting string.
 
3608
   @param ... Arguments.
 
3609
   @return Number of printed characters.
 
3610
 */
 
3611
TRIO_PUBLIC int
 
3612
trio_printf
 
3613
TRIO_VARGS2((format, va_alist),
 
3614
            TRIO_CONST char *format,
 
3615
            TRIO_VA_DECL)
 
3616
{
 
3617
  int status;
 
3618
  va_list args;
 
3619
 
 
3620
  assert(VALID(format));
 
3621
  
 
3622
  TRIO_VA_START(args, format);
 
3623
  status = TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
 
3624
  TRIO_VA_END(args);
 
3625
  return status;
 
3626
}
 
3627
 
 
3628
/**
 
3629
   Print to standard output stream.
 
3630
 
 
3631
   @param format Formatting string.
 
3632
   @param args Arguments.
 
3633
   @return Number of printed characters.
 
3634
 */
 
3635
TRIO_PUBLIC int
 
3636
trio_vprintf
 
3637
TRIO_ARGS2((format, args),
 
3638
           TRIO_CONST char *format,
 
3639
           va_list args)
 
3640
{
 
3641
  assert(VALID(format));
 
3642
 
 
3643
  return TrioFormat(stdout, 0, TrioOutStreamFile, format, &args, NULL);
 
3644
}
 
3645
 
 
3646
/**
 
3647
   Print to standard output stream.
 
3648
 
 
3649
   @param format Formatting string.
 
3650
   @param args Arguments.
 
3651
   @return Number of printed characters.
 
3652
 */
 
3653
TRIO_PUBLIC int
 
3654
trio_printfv
 
3655
TRIO_ARGS2((format, args),
 
3656
           TRIO_CONST char *format,
 
3657
           trio_pointer_t * args)
 
3658
{
 
3659
  assert(VALID(format));
 
3660
 
 
3661
  return TrioFormat(stdout, 0, TrioOutStreamFile, format, NULL, args);
 
3662
}
 
3663
 
 
3664
/*************************************************************************
 
3665
 * fprintf
 
3666
 */
 
3667
 
 
3668
/**
 
3669
   Print to file.
 
3670
 
 
3671
   @param file File pointer.
 
3672
   @param format Formatting string.
 
3673
   @param ... Arguments.
 
3674
   @return Number of printed characters.
 
3675
 */
 
3676
TRIO_PUBLIC int
 
3677
trio_fprintf
 
3678
TRIO_VARGS3((file, format, va_alist),
 
3679
            FILE *file,
 
3680
            TRIO_CONST char *format,
 
3681
            TRIO_VA_DECL)
 
3682
{
 
3683
  int status;
 
3684
  va_list args;
 
3685
 
 
3686
  assert(VALID(file));
 
3687
  assert(VALID(format));
 
3688
  
 
3689
  TRIO_VA_START(args, format);
 
3690
  status = TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
 
3691
  TRIO_VA_END(args);
 
3692
  return status;
 
3693
}
 
3694
 
 
3695
/**
 
3696
   Print to file.
 
3697
 
 
3698
   @param file File pointer.
 
3699
   @param format Formatting string.
 
3700
   @param args Arguments.
 
3701
   @return Number of printed characters.
 
3702
 */
 
3703
TRIO_PUBLIC int
 
3704
trio_vfprintf
 
3705
TRIO_ARGS3((file, format, args),
 
3706
           FILE *file,
 
3707
           TRIO_CONST char *format,
 
3708
           va_list args)
 
3709
{
 
3710
  assert(VALID(file));
 
3711
  assert(VALID(format));
 
3712
  
 
3713
  return TrioFormat(file, 0, TrioOutStreamFile, format, &args, NULL);
 
3714
}
 
3715
 
 
3716
/**
 
3717
   Print to file.
 
3718
 
 
3719
   @param file File pointer.
 
3720
   @param format Formatting string.
 
3721
   @param args Arguments.
 
3722
   @return Number of printed characters.
 
3723
 */
 
3724
TRIO_PUBLIC int
 
3725
trio_fprintfv
 
3726
TRIO_ARGS3((file, format, args),
 
3727
           FILE *file,
 
3728
           TRIO_CONST char *format,
 
3729
           trio_pointer_t * args)
 
3730
{
 
3731
  assert(VALID(file));
 
3732
  assert(VALID(format));
 
3733
  
 
3734
  return TrioFormat(file, 0, TrioOutStreamFile, format, NULL, args);
 
3735
}
 
3736
 
 
3737
/*************************************************************************
 
3738
 * dprintf
 
3739
 */
 
3740
 
 
3741
/**
 
3742
   Print to file descriptor.
 
3743
 
 
3744
   @param fd File descriptor.
 
3745
   @param format Formatting string.
 
3746
   @param ... Arguments.
 
3747
   @return Number of printed characters.
 
3748
 */
 
3749
TRIO_PUBLIC int
 
3750
trio_dprintf
 
3751
TRIO_VARGS3((fd, format, va_alist),
 
3752
            int fd,
 
3753
            TRIO_CONST char *format,
 
3754
            TRIO_VA_DECL)
 
3755
{
 
3756
  int status;
 
3757
  va_list args;
 
3758
 
 
3759
  assert(VALID(format));
 
3760
  
 
3761
  TRIO_VA_START(args, format);
 
3762
  status = TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
 
3763
  TRIO_VA_END(args);
 
3764
  return status;
 
3765
}
 
3766
 
 
3767
/**
 
3768
   Print to file descriptor.
 
3769
 
 
3770
   @param fd File descriptor.
 
3771
   @param format Formatting string.
 
3772
   @param args Arguments.
 
3773
   @return Number of printed characters.
 
3774
 */
 
3775
TRIO_PUBLIC int
 
3776
trio_vdprintf
 
3777
TRIO_ARGS3((fd, format, args),
 
3778
           int fd,
 
3779
           TRIO_CONST char *format,
 
3780
           va_list args)
 
3781
{
 
3782
  assert(VALID(format));
 
3783
  
 
3784
  return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, &args, NULL);
 
3785
}
 
3786
 
 
3787
/**
 
3788
   Print to file descriptor.
 
3789
 
 
3790
   @param fd File descriptor.
 
3791
   @param format Formatting string.
 
3792
   @param args Arguments.
 
3793
   @return Number of printed characters.
 
3794
 */
 
3795
TRIO_PUBLIC int
 
3796
trio_dprintfv
 
3797
TRIO_ARGS3((fd, format, args),
 
3798
           int fd,
 
3799
           TRIO_CONST char *format,
 
3800
           trio_pointer_t *args)
 
3801
{
 
3802
  assert(VALID(format));
 
3803
  
 
3804
  return TrioFormat(&fd, 0, TrioOutStreamFileDescriptor, format, NULL, args);
 
3805
}
 
3806
 
 
3807
/*************************************************************************
 
3808
 * cprintf
 
3809
 */
 
3810
TRIO_PUBLIC int
 
3811
trio_cprintf
 
3812
TRIO_VARGS4((stream, closure, format, va_alist),
 
3813
            trio_outstream_t stream,
 
3814
            trio_pointer_t closure,
 
3815
            TRIO_CONST char *format,
 
3816
            TRIO_VA_DECL)
 
3817
{
 
3818
  int status;
 
3819
  va_list args;
 
3820
  trio_custom_t data;
 
3821
 
 
3822
  assert(VALID(stream));
 
3823
  assert(VALID(format));
 
3824
 
 
3825
  TRIO_VA_START(args, format);
 
3826
  data.stream.out = stream;
 
3827
  data.closure = closure;
 
3828
  status = TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
 
3829
  TRIO_VA_END(args);
 
3830
  return status;
 
3831
}
 
3832
 
 
3833
TRIO_PUBLIC int
 
3834
trio_vcprintf
 
3835
TRIO_ARGS4((stream, closure, format, args),
 
3836
           trio_outstream_t stream,
 
3837
           trio_pointer_t closure,
 
3838
           TRIO_CONST char *format,
 
3839
           va_list args)
 
3840
{
 
3841
  trio_custom_t data;
 
3842
 
 
3843
  assert(VALID(stream));
 
3844
  assert(VALID(format));
 
3845
 
 
3846
  data.stream.out = stream;
 
3847
  data.closure = closure;
 
3848
  return TrioFormat(&data, 0, TrioOutStreamCustom, format, &args, NULL);
 
3849
}
 
3850
 
 
3851
TRIO_PUBLIC int
 
3852
trio_cprintfv
 
3853
TRIO_ARGS4((stream, closure, format, args),
 
3854
           trio_outstream_t stream,
 
3855
           trio_pointer_t closure,
 
3856
           TRIO_CONST char *format,
 
3857
           void **args)
 
3858
{
 
3859
  trio_custom_t data;
 
3860
 
 
3861
  assert(VALID(stream));
 
3862
  assert(VALID(format));
 
3863
 
 
3864
  data.stream.out = stream;
 
3865
  data.closure = closure;
 
3866
  return TrioFormat(&data, 0, TrioOutStreamCustom, format, NULL, args);
 
3867
}
 
3868
 
 
3869
/*************************************************************************
 
3870
 * sprintf
 
3871
 */
 
3872
 
 
3873
/**
 
3874
   Print to string.
 
3875
 
 
3876
   @param buffer Output string.
 
3877
   @param format Formatting string.
 
3878
   @param ... Arguments.
 
3879
   @return Number of printed characters.
 
3880
 */
 
3881
TRIO_PUBLIC int
 
3882
trio_sprintf
 
3883
TRIO_VARGS3((buffer, format, va_alist),
 
3884
            char *buffer,
 
3885
            TRIO_CONST char *format,
 
3886
            TRIO_VA_DECL)
 
3887
{
 
3888
  int status;
 
3889
  va_list args;
 
3890
 
 
3891
  assert(VALID(buffer));
 
3892
  assert(VALID(format));
 
3893
  
 
3894
  TRIO_VA_START(args, format);
 
3895
  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
 
3896
  *buffer = NIL; /* Terminate with NIL character */
 
3897
  TRIO_VA_END(args);
 
3898
  return status;
 
3899
}
 
3900
 
 
3901
/**
 
3902
   Print to string.
 
3903
 
 
3904
   @param buffer Output string.
 
3905
   @param format Formatting string.
 
3906
   @param args Arguments.
 
3907
   @return Number of printed characters.
 
3908
 */
 
3909
TRIO_PUBLIC int
 
3910
trio_vsprintf
 
3911
TRIO_ARGS3((buffer, format, args),
 
3912
           char *buffer,
 
3913
           TRIO_CONST char *format,
 
3914
           va_list args)
 
3915
{
 
3916
  int status;
 
3917
 
 
3918
  assert(VALID(buffer));
 
3919
  assert(VALID(format));
 
3920
 
 
3921
  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, &args, NULL);
 
3922
  *buffer = NIL;
 
3923
  return status;
 
3924
}
 
3925
 
 
3926
/**
 
3927
   Print to string.
 
3928
 
 
3929
   @param buffer Output string.
 
3930
   @param format Formatting string.
 
3931
   @param args Arguments.
 
3932
   @return Number of printed characters.
 
3933
 */
 
3934
TRIO_PUBLIC int
 
3935
trio_sprintfv
 
3936
TRIO_ARGS3((buffer, format, args),
 
3937
           char *buffer,
 
3938
           TRIO_CONST char *format,
 
3939
           trio_pointer_t *args)
 
3940
{
 
3941
  int status;
 
3942
 
 
3943
  assert(VALID(buffer));
 
3944
  assert(VALID(format));
 
3945
 
 
3946
  status = TrioFormat(&buffer, 0, TrioOutStreamString, format, NULL, args);
 
3947
  *buffer = NIL;
 
3948
  return status;
 
3949
}
 
3950
 
 
3951
/*************************************************************************
 
3952
 * snprintf
 
3953
 */
 
3954
 
 
3955
/**
 
3956
   Print at most @p max characters to string.
 
3957
 
 
3958
   @param buffer Output string.
 
3959
   @param max Maximum number of characters to print.
 
3960
   @param format Formatting string.
 
3961
   @param ... Arguments.
 
3962
   @return Number of printed characters.
 
3963
 */
 
3964
TRIO_PUBLIC int
 
3965
trio_snprintf
 
3966
TRIO_VARGS4((buffer, max, format, va_alist),
 
3967
            char *buffer,
 
3968
            size_t max,
 
3969
            TRIO_CONST char *format,
 
3970
            TRIO_VA_DECL)
 
3971
{
 
3972
  int status;
 
3973
  va_list args;
 
3974
 
 
3975
  assert(VALID(buffer));
 
3976
  assert(VALID(format));
 
3977
 
 
3978
  TRIO_VA_START(args, format);
 
3979
  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
 
3980
                      TrioOutStreamStringMax, format, &args, NULL);
 
3981
  if (max > 0)
 
3982
    *buffer = NIL;
 
3983
  TRIO_VA_END(args);
 
3984
  return status;
 
3985
}
 
3986
 
 
3987
/**
 
3988
   Print at most @p max characters to string.
 
3989
 
 
3990
   @param buffer Output string.
 
3991
   @param max Maximum number of characters to print.
 
3992
   @param format Formatting string.
 
3993
   @param args Arguments.
 
3994
   @return Number of printed characters.
 
3995
 */
 
3996
TRIO_PUBLIC int
 
3997
trio_vsnprintf
 
3998
TRIO_ARGS4((buffer, max, format, args),
 
3999
           char *buffer,
 
4000
           size_t max,
 
4001
           TRIO_CONST char *format,
 
4002
           va_list args)
 
4003
{
 
4004
  int status;
 
4005
 
 
4006
  assert(VALID(buffer));
 
4007
  assert(VALID(format));
 
4008
 
 
4009
  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
 
4010
                      TrioOutStreamStringMax, format, &args, NULL);
 
4011
  if (max > 0)
 
4012
    *buffer = NIL;
 
4013
  return status;
 
4014
}
 
4015
 
 
4016
/**
 
4017
   Print at most @p max characters to string.
 
4018
 
 
4019
   @param buffer Output string.
 
4020
   @param max Maximum number of characters to print.
 
4021
   @param format Formatting string.
 
4022
   @param args Arguments.
 
4023
   @return Number of printed characters.
 
4024
 */
 
4025
TRIO_PUBLIC int
 
4026
trio_snprintfv
 
4027
TRIO_ARGS4((buffer, max, format, args),
 
4028
           char *buffer,
 
4029
           size_t max,
 
4030
           TRIO_CONST char *format,
 
4031
           trio_pointer_t *args)
 
4032
{
 
4033
  int status;
 
4034
 
 
4035
  assert(VALID(buffer));
 
4036
  assert(VALID(format));
 
4037
 
 
4038
  status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
 
4039
                      TrioOutStreamStringMax, format, NULL, args);
 
4040
  if (max > 0)
 
4041
    *buffer = NIL;
 
4042
  return status;
 
4043
}
 
4044
 
 
4045
/*************************************************************************
 
4046
 * snprintfcat
 
4047
 * Appends the new string to the buffer string overwriting the '\0'
 
4048
 * character at the end of buffer.
 
4049
 */
 
4050
TRIO_PUBLIC int
 
4051
trio_snprintfcat
 
4052
TRIO_VARGS4((buffer, max, format, va_alist),
 
4053
            char *buffer,
 
4054
            size_t max,
 
4055
            TRIO_CONST char *format,
 
4056
            TRIO_VA_DECL)
 
4057
{
 
4058
  int status;
 
4059
  va_list args;
 
4060
  size_t buf_len;
 
4061
 
 
4062
  TRIO_VA_START(args, format);
 
4063
 
 
4064
  assert(VALID(buffer));
 
4065
  assert(VALID(format));
 
4066
 
 
4067
  buf_len = trio_length(buffer);
 
4068
  buffer = &buffer[buf_len];
 
4069
 
 
4070
  status = TrioFormat(&buffer, max - 1 - buf_len,
 
4071
                      TrioOutStreamStringMax, format, &args, NULL);
 
4072
  TRIO_VA_END(args);
 
4073
  *buffer = NIL;
 
4074
  return status;
 
4075
}
 
4076
 
 
4077
TRIO_PUBLIC int
 
4078
trio_vsnprintfcat
 
4079
TRIO_ARGS4((buffer, max, format, args),
 
4080
           char *buffer,
 
4081
           size_t max,
 
4082
           TRIO_CONST char *format,
 
4083
           va_list args)
 
4084
{
 
4085
  int status;
 
4086
  size_t buf_len;
 
4087
  
 
4088
  assert(VALID(buffer));
 
4089
  assert(VALID(format));
 
4090
 
 
4091
  buf_len = trio_length(buffer);
 
4092
  buffer = &buffer[buf_len];
 
4093
  status = TrioFormat(&buffer, max - 1 - buf_len,
 
4094
                      TrioOutStreamStringMax, format, &args, NULL);
 
4095
  *buffer = NIL;
 
4096
  return status;
 
4097
}
 
4098
 
 
4099
/*************************************************************************
 
4100
 * trio_aprintf
 
4101
 */
 
4102
 
 
4103
/* Deprecated */
 
4104
TRIO_PUBLIC char *
 
4105
trio_aprintf
 
4106
TRIO_VARGS2((format, va_alist),
 
4107
            TRIO_CONST char *format,
 
4108
            TRIO_VA_DECL)
 
4109
{
 
4110
  va_list args;
 
4111
  trio_string_t *info;
 
4112
  char *result = NULL;
 
4113
 
 
4114
  assert(VALID(format));
 
4115
  
 
4116
  info = trio_xstring_duplicate("");
 
4117
  if (info)
 
4118
    {
 
4119
      TRIO_VA_START(args, format);
 
4120
      (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
 
4121
                       format, &args, NULL);
 
4122
      TRIO_VA_END(args);
 
4123
 
 
4124
      trio_string_terminate(info);
 
4125
      result = trio_string_extract(info);
 
4126
      trio_string_destroy(info);
 
4127
    }
 
4128
  return result;
 
4129
}
 
4130
 
 
4131
/* Deprecated */
 
4132
TRIO_PUBLIC char *
 
4133
trio_vaprintf
 
4134
TRIO_ARGS2((format, args),
 
4135
           TRIO_CONST char *format,
 
4136
           va_list args)
 
4137
{
 
4138
  trio_string_t *info;
 
4139
  char *result = NULL;
 
4140
  
 
4141
  assert(VALID(format));
 
4142
  
 
4143
  info = trio_xstring_duplicate("");
 
4144
  if (info)
 
4145
    {
 
4146
      (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
 
4147
                       format, &args, NULL);
 
4148
      trio_string_terminate(info);
 
4149
      result = trio_string_extract(info);
 
4150
      trio_string_destroy(info);
 
4151
    }
 
4152
  return result;
 
4153
}
 
4154
 
 
4155
TRIO_PUBLIC int
 
4156
trio_asprintf
 
4157
TRIO_VARGS3((result, format, va_alist),
 
4158
            char **result,
 
4159
            TRIO_CONST char *format,
 
4160
            TRIO_VA_DECL)
 
4161
{
 
4162
  va_list args;
 
4163
  int status;
 
4164
  trio_string_t *info;
 
4165
 
 
4166
  assert(VALID(format));
 
4167
 
 
4168
  *result = NULL;
 
4169
  
 
4170
  info = trio_xstring_duplicate("");
 
4171
  if (info == NULL)
 
4172
    {
 
4173
      status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
 
4174
    }
 
4175
  else
 
4176
    {
 
4177
      TRIO_VA_START(args, format);
 
4178
      status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
 
4179
                          format, &args, NULL);
 
4180
      TRIO_VA_END(args);
 
4181
      if (status >= 0)
 
4182
        {
 
4183
          trio_string_terminate(info);
 
4184
          *result = trio_string_extract(info);
 
4185
        }
 
4186
      trio_string_destroy(info);
 
4187
    }
 
4188
  return status;
 
4189
}
 
4190
 
 
4191
TRIO_PUBLIC int
 
4192
trio_vasprintf
 
4193
TRIO_ARGS3((result, format, args),
 
4194
           char **result,
 
4195
           TRIO_CONST char *format,
 
4196
           va_list args)
 
4197
{
 
4198
  int status;
 
4199
  trio_string_t *info;
 
4200
  
 
4201
  assert(VALID(format));
 
4202
 
 
4203
  *result = NULL;
 
4204
  
 
4205
  info = trio_xstring_duplicate("");
 
4206
  if (info == NULL)
 
4207
    {
 
4208
      status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
 
4209
    }
 
4210
  else
 
4211
    {
 
4212
      status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
 
4213
                          format, &args, NULL);
 
4214
      if (status >= 0)
 
4215
        {
 
4216
          trio_string_terminate(info);
 
4217
          *result = trio_string_extract(info);
 
4218
        }
 
4219
      trio_string_destroy(info);
 
4220
    }
 
4221
  return status;
 
4222
}
 
4223
 
 
4224
/** @} End of Printf documentation module */
 
4225
 
 
4226
/*************************************************************************
 
4227
 *
 
4228
 * CALLBACK
 
4229
 *
 
4230
 ************************************************************************/
 
4231
 
 
4232
#if defined(TRIO_DOCUMENTATION)
 
4233
# include "doc/doc_register.h"
 
4234
#endif
 
4235
/**
 
4236
   @addtogroup UserDefined
 
4237
   @{
 
4238
*/
 
4239
 
 
4240
#if TRIO_EXTENSION
 
4241
 
 
4242
/*************************************************************************
 
4243
 * trio_register
 
4244
 */
 
4245
 
 
4246
/**
 
4247
   Register new user-defined specifier.
 
4248
 
 
4249
   @param callback
 
4250
   @param name
 
4251
   @return Handle.
 
4252
 */
 
4253
TRIO_PUBLIC trio_pointer_t 
 
4254
trio_register
 
4255
TRIO_ARGS2((callback, name),
 
4256
           trio_callback_t callback,
 
4257
           TRIO_CONST char *name)
 
4258
{
 
4259
  trio_userdef_t *def;
 
4260
  trio_userdef_t *prev = NULL;
 
4261
 
 
4262
  if (callback == NULL)
 
4263
    return NULL;
 
4264
 
 
4265
  if (name)
 
4266
    {
 
4267
      /* Handle built-in namespaces */
 
4268
      if (name[0] == ':')
 
4269
        {
 
4270
          if (trio_equal(name, ":enter"))
 
4271
            {
 
4272
              internalEnterCriticalRegion = callback;
 
4273
            }
 
4274
          else if (trio_equal(name, ":leave"))
 
4275
            {
 
4276
              internalLeaveCriticalRegion = callback;
 
4277
            }
 
4278
          return NULL;
 
4279
        }
 
4280
      
 
4281
      /* Bail out if namespace is too long */
 
4282
      if (trio_length(name) >= MAX_USER_NAME)
 
4283
        return NULL;
 
4284
      
 
4285
      /* Bail out if namespace already is registered */
 
4286
      def = TrioFindNamespace(name, &prev);
 
4287
      if (def)
 
4288
        return NULL;
 
4289
    }
 
4290
  
 
4291
  def = (trio_userdef_t *)TRIO_MALLOC(sizeof(trio_userdef_t));
 
4292
  if (def)
 
4293
    {
 
4294
      if (internalEnterCriticalRegion)
 
4295
        (void)internalEnterCriticalRegion(NULL);
 
4296
      
 
4297
      if (name)
 
4298
        {
 
4299
          /* Link into internal list */
 
4300
          if (prev == NULL)
 
4301
            internalUserDef = def;
 
4302
          else
 
4303
            prev->next = def;
 
4304
        }
 
4305
      /* Initialize */
 
4306
      def->callback = callback;
 
4307
      def->name = (name == NULL)
 
4308
        ? NULL
 
4309
        : trio_duplicate(name);
 
4310
      def->next = NULL;
 
4311
 
 
4312
      if (internalLeaveCriticalRegion)
 
4313
        (void)internalLeaveCriticalRegion(NULL);
 
4314
    }
 
4315
  return (trio_pointer_t)def;
 
4316
}
 
4317
 
 
4318
/**
 
4319
   Unregister an existing user-defined specifier.
 
4320
 
 
4321
   @param handle
 
4322
 */
 
4323
void
 
4324
trio_unregister
 
4325
TRIO_ARGS1((handle),
 
4326
           trio_pointer_t handle)
 
4327
{
 
4328
  trio_userdef_t *self = (trio_userdef_t *)handle;
 
4329
  trio_userdef_t *def;
 
4330
  trio_userdef_t *prev = NULL;
 
4331
 
 
4332
  assert(VALID(self));
 
4333
 
 
4334
  if (self->name)
 
4335
    {
 
4336
      def = TrioFindNamespace(self->name, &prev);
 
4337
      if (def)
 
4338
        {
 
4339
          if (internalEnterCriticalRegion)
 
4340
            (void)internalEnterCriticalRegion(NULL);
 
4341
          
 
4342
          if (prev == NULL)
 
4343
            internalUserDef = NULL;
 
4344
          else
 
4345
            prev->next = def->next;
 
4346
          
 
4347
          if (internalLeaveCriticalRegion)
 
4348
            (void)internalLeaveCriticalRegion(NULL);
 
4349
        }
 
4350
      trio_destroy(self->name);
 
4351
    }
 
4352
  TRIO_FREE(self);
 
4353
}
 
4354
 
 
4355
/*************************************************************************
 
4356
 * trio_get_format [public]
 
4357
 */
 
4358
TRIO_CONST char *
 
4359
trio_get_format
 
4360
TRIO_ARGS1((ref),
 
4361
           trio_pointer_t ref)
 
4362
{
 
4363
#if defined(FORMAT_USER_DEFINED)
 
4364
  assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
 
4365
#endif
 
4366
  
 
4367
  return (((trio_reference_t *)ref)->parameter->user_data);
 
4368
}
 
4369
 
 
4370
/*************************************************************************
 
4371
 * trio_get_argument [public]
 
4372
 */
 
4373
trio_pointer_t 
 
4374
trio_get_argument
 
4375
TRIO_ARGS1((ref),
 
4376
           trio_pointer_t ref)
 
4377
{
 
4378
#if defined(FORMAT_USER_DEFINED)
 
4379
  assert(((trio_reference_t *)ref)->parameter->type == FORMAT_USER_DEFINED);
 
4380
#endif
 
4381
  
 
4382
  return ((trio_reference_t *)ref)->parameter->data.pointer;
 
4383
}
 
4384
 
 
4385
/*************************************************************************
 
4386
 * trio_get_width / trio_set_width [public]
 
4387
 */
 
4388
int
 
4389
trio_get_width
 
4390
TRIO_ARGS1((ref),
 
4391
           trio_pointer_t ref)
 
4392
{
 
4393
  return ((trio_reference_t *)ref)->parameter->width;
 
4394
}
 
4395
 
 
4396
void
 
4397
trio_set_width
 
4398
TRIO_ARGS2((ref, width),
 
4399
           trio_pointer_t ref,
 
4400
           int width)
 
4401
{
 
4402
  ((trio_reference_t *)ref)->parameter->width = width;
 
4403
}
 
4404
 
 
4405
/*************************************************************************
 
4406
 * trio_get_precision / trio_set_precision [public]
 
4407
 */
 
4408
int
 
4409
trio_get_precision
 
4410
TRIO_ARGS1((ref),
 
4411
           trio_pointer_t ref)
 
4412
{
 
4413
  return (((trio_reference_t *)ref)->parameter->precision);
 
4414
}
 
4415
 
 
4416
void
 
4417
trio_set_precision
 
4418
TRIO_ARGS2((ref, precision),
 
4419
           trio_pointer_t ref,
 
4420
           int precision)
 
4421
{
 
4422
  ((trio_reference_t *)ref)->parameter->precision = precision;
 
4423
}
 
4424
 
 
4425
/*************************************************************************
 
4426
 * trio_get_base / trio_set_base [public]
 
4427
 */
 
4428
int
 
4429
trio_get_base
 
4430
TRIO_ARGS1((ref),
 
4431
           trio_pointer_t ref)
 
4432
{
 
4433
  return (((trio_reference_t *)ref)->parameter->base);
 
4434
}
 
4435
 
 
4436
void
 
4437
trio_set_base
 
4438
TRIO_ARGS2((ref, base),
 
4439
           trio_pointer_t ref,
 
4440
           int base)
 
4441
{
 
4442
  ((trio_reference_t *)ref)->parameter->base = base;
 
4443
}
 
4444
 
 
4445
/*************************************************************************
 
4446
 * trio_get_long / trio_set_long [public]
 
4447
 */
 
4448
int
 
4449
trio_get_long
 
4450
TRIO_ARGS1((ref),
 
4451
           trio_pointer_t ref)
 
4452
{
 
4453
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONG)
 
4454
    ? TRUE
 
4455
    : FALSE;
 
4456
}
 
4457
 
 
4458
void
 
4459
trio_set_long
 
4460
TRIO_ARGS2((ref, is_long),
 
4461
           trio_pointer_t ref,
 
4462
           int is_long)
 
4463
{
 
4464
  if (is_long)
 
4465
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONG;
 
4466
  else
 
4467
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONG;
 
4468
}
 
4469
 
 
4470
/*************************************************************************
 
4471
 * trio_get_longlong / trio_set_longlong [public]
 
4472
 */
 
4473
int
 
4474
trio_get_longlong
 
4475
TRIO_ARGS1((ref),
 
4476
           trio_pointer_t ref)
 
4477
{
 
4478
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUAD)
 
4479
    ? TRUE
 
4480
    : FALSE;
 
4481
}
 
4482
 
 
4483
void
 
4484
trio_set_longlong
 
4485
TRIO_ARGS2((ref, is_longlong),
 
4486
           trio_pointer_t ref,
 
4487
           int is_longlong)
 
4488
{
 
4489
  if (is_longlong)
 
4490
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUAD;
 
4491
  else
 
4492
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUAD;
 
4493
}
 
4494
 
 
4495
/*************************************************************************
 
4496
 * trio_get_longdouble / trio_set_longdouble [public]
 
4497
 */
 
4498
int
 
4499
trio_get_longdouble
 
4500
TRIO_ARGS1((ref),
 
4501
           trio_pointer_t ref)
 
4502
{
 
4503
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LONGDOUBLE)
 
4504
    ? TRUE
 
4505
    : FALSE;
 
4506
}
 
4507
 
 
4508
void
 
4509
trio_set_longdouble
 
4510
TRIO_ARGS2((ref, is_longdouble),
 
4511
           trio_pointer_t ref,
 
4512
           int is_longdouble)
 
4513
{
 
4514
  if (is_longdouble)
 
4515
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LONGDOUBLE;
 
4516
  else
 
4517
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LONGDOUBLE;
 
4518
}
 
4519
 
 
4520
/*************************************************************************
 
4521
 * trio_get_short / trio_set_short [public]
 
4522
 */
 
4523
int
 
4524
trio_get_short
 
4525
TRIO_ARGS1((ref),
 
4526
           trio_pointer_t ref)
 
4527
{
 
4528
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORT)
 
4529
    ? TRUE
 
4530
    : FALSE;
 
4531
}
 
4532
 
 
4533
void
 
4534
trio_set_short
 
4535
TRIO_ARGS2((ref, is_short),
 
4536
           trio_pointer_t ref,
 
4537
           int is_short)
 
4538
{
 
4539
  if (is_short)
 
4540
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORT;
 
4541
  else
 
4542
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORT;
 
4543
}
 
4544
 
 
4545
/*************************************************************************
 
4546
 * trio_get_shortshort / trio_set_shortshort [public]
 
4547
 */
 
4548
int
 
4549
trio_get_shortshort
 
4550
TRIO_ARGS1((ref),
 
4551
           trio_pointer_t ref)
 
4552
{
 
4553
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHORTSHORT)
 
4554
    ? TRUE
 
4555
    : FALSE;
 
4556
}
 
4557
 
 
4558
void
 
4559
trio_set_shortshort
 
4560
TRIO_ARGS2((ref, is_shortshort),
 
4561
           trio_pointer_t ref,
 
4562
           int is_shortshort)
 
4563
{
 
4564
  if (is_shortshort)
 
4565
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHORTSHORT;
 
4566
  else
 
4567
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHORTSHORT;
 
4568
}
 
4569
 
 
4570
/*************************************************************************
 
4571
 * trio_get_alternative / trio_set_alternative [public]
 
4572
 */
 
4573
int
 
4574
trio_get_alternative
 
4575
TRIO_ARGS1((ref),
 
4576
           trio_pointer_t ref)
 
4577
{
 
4578
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_ALTERNATIVE)
 
4579
    ? TRUE
 
4580
    : FALSE;
 
4581
}
 
4582
 
 
4583
void
 
4584
trio_set_alternative
 
4585
TRIO_ARGS2((ref, is_alternative),
 
4586
           trio_pointer_t ref,
 
4587
           int is_alternative)
 
4588
{
 
4589
  if (is_alternative)
 
4590
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_ALTERNATIVE;
 
4591
  else
 
4592
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_ALTERNATIVE;
 
4593
}
 
4594
 
 
4595
/*************************************************************************
 
4596
 * trio_get_alignment / trio_set_alignment [public]
 
4597
 */
 
4598
int
 
4599
trio_get_alignment
 
4600
TRIO_ARGS1((ref),
 
4601
           trio_pointer_t ref)
 
4602
{
 
4603
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_LEFTADJUST)
 
4604
    ? TRUE
 
4605
    : FALSE;
 
4606
}
 
4607
 
 
4608
void
 
4609
trio_set_alignment
 
4610
TRIO_ARGS2((ref, is_leftaligned),
 
4611
           trio_pointer_t ref,
 
4612
           int is_leftaligned)
 
4613
{
 
4614
  if (is_leftaligned)
 
4615
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_LEFTADJUST;
 
4616
  else
 
4617
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_LEFTADJUST;
 
4618
}
 
4619
 
 
4620
/*************************************************************************
 
4621
 * trio_get_spacing /trio_set_spacing [public]
 
4622
 */
 
4623
int
 
4624
trio_get_spacing
 
4625
TRIO_ARGS1((ref),
 
4626
           trio_pointer_t ref)
 
4627
{
 
4628
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SPACE)
 
4629
    ? TRUE
 
4630
    : FALSE;
 
4631
}
 
4632
 
 
4633
void
 
4634
trio_set_spacing
 
4635
TRIO_ARGS2((ref, is_space),
 
4636
           trio_pointer_t ref,
 
4637
           int is_space)
 
4638
{
 
4639
  if (is_space)
 
4640
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SPACE;
 
4641
  else
 
4642
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SPACE;
 
4643
}
 
4644
 
 
4645
/*************************************************************************
 
4646
 * trio_get_sign / trio_set_sign [public]
 
4647
 */
 
4648
int
 
4649
trio_get_sign
 
4650
TRIO_ARGS1((ref),
 
4651
           trio_pointer_t ref)
 
4652
{
 
4653
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SHOWSIGN)
 
4654
    ? TRUE
 
4655
    : FALSE;
 
4656
}
 
4657
 
 
4658
void
 
4659
trio_set_sign
 
4660
TRIO_ARGS2((ref, is_sign),
 
4661
           trio_pointer_t ref,
 
4662
           int is_sign)
 
4663
{
 
4664
  if (is_sign)
 
4665
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SHOWSIGN;
 
4666
  else
 
4667
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SHOWSIGN;
 
4668
}
 
4669
 
 
4670
/*************************************************************************
 
4671
 * trio_get_padding / trio_set_padding [public]
 
4672
 */
 
4673
int
 
4674
trio_get_padding
 
4675
TRIO_ARGS1((ref),
 
4676
           trio_pointer_t ref)
 
4677
{
 
4678
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_NILPADDING)
 
4679
    ? TRUE
 
4680
    : FALSE;
 
4681
}
 
4682
 
 
4683
void
 
4684
trio_set_padding
 
4685
TRIO_ARGS2((ref, is_padding),
 
4686
           trio_pointer_t ref,
 
4687
           int is_padding)
 
4688
{
 
4689
  if (is_padding)
 
4690
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_NILPADDING;
 
4691
  else
 
4692
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_NILPADDING;
 
4693
}
 
4694
 
 
4695
/*************************************************************************
 
4696
 * trio_get_quote / trio_set_quote [public]
 
4697
 */
 
4698
int
 
4699
trio_get_quote
 
4700
TRIO_ARGS1((ref),
 
4701
           trio_pointer_t ref)
 
4702
{
 
4703
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_QUOTE)
 
4704
    ? TRUE
 
4705
    : FALSE;
 
4706
}
 
4707
 
 
4708
void
 
4709
trio_set_quote
 
4710
TRIO_ARGS2((ref, is_quote),
 
4711
           trio_pointer_t ref,
 
4712
           int is_quote)
 
4713
{
 
4714
  if (is_quote)
 
4715
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_QUOTE;
 
4716
  else
 
4717
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_QUOTE;
 
4718
}
 
4719
 
 
4720
/*************************************************************************
 
4721
 * trio_get_upper / trio_set_upper [public]
 
4722
 */
 
4723
int
 
4724
trio_get_upper
 
4725
TRIO_ARGS1((ref),
 
4726
           trio_pointer_t ref)
 
4727
{
 
4728
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_UPPER)
 
4729
    ? TRUE
 
4730
    : FALSE;
 
4731
}
 
4732
 
 
4733
void
 
4734
trio_set_upper
 
4735
TRIO_ARGS2((ref, is_upper),
 
4736
           trio_pointer_t ref,
 
4737
           int is_upper)
 
4738
{
 
4739
  if (is_upper)
 
4740
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_UPPER;
 
4741
  else
 
4742
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_UPPER;
 
4743
}
 
4744
 
 
4745
/*************************************************************************
 
4746
 * trio_get_largest / trio_set_largest [public]
 
4747
 */
 
4748
#if TRIO_C99
 
4749
int
 
4750
trio_get_largest
 
4751
TRIO_ARGS1((ref),
 
4752
           trio_pointer_t ref)
 
4753
{
 
4754
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_INTMAX_T)
 
4755
    ? TRUE
 
4756
    : FALSE;
 
4757
}
 
4758
 
 
4759
void
 
4760
trio_set_largest
 
4761
TRIO_ARGS2((ref, is_largest),
 
4762
           trio_pointer_t ref,
 
4763
           int is_largest)
 
4764
{
 
4765
  if (is_largest)
 
4766
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_INTMAX_T;
 
4767
  else
 
4768
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_INTMAX_T;
 
4769
}
 
4770
#endif
 
4771
 
 
4772
/*************************************************************************
 
4773
 * trio_get_ptrdiff / trio_set_ptrdiff [public]
 
4774
 */
 
4775
int
 
4776
trio_get_ptrdiff
 
4777
TRIO_ARGS1((ref),
 
4778
           trio_pointer_t ref)
 
4779
{
 
4780
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_PTRDIFF_T)
 
4781
    ? TRUE
 
4782
    : FALSE;
 
4783
}
 
4784
 
 
4785
void
 
4786
trio_set_ptrdiff
 
4787
TRIO_ARGS2((ref, is_ptrdiff),
 
4788
           trio_pointer_t ref,
 
4789
           int is_ptrdiff)
 
4790
{
 
4791
  if (is_ptrdiff)
 
4792
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_PTRDIFF_T;
 
4793
  else
 
4794
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_PTRDIFF_T;
 
4795
}
 
4796
 
 
4797
/*************************************************************************
 
4798
 * trio_get_size / trio_set_size [public]
 
4799
 */
 
4800
#if TRIO_C99
 
4801
int
 
4802
trio_get_size
 
4803
TRIO_ARGS1((ref),
 
4804
           trio_pointer_t ref)
 
4805
{
 
4806
  return (((trio_reference_t *)ref)->parameter->flags & FLAGS_SIZE_T)
 
4807
    ? TRUE
 
4808
    : FALSE;
 
4809
}
 
4810
 
 
4811
void
 
4812
trio_set_size
 
4813
TRIO_ARGS2((ref, is_size),
 
4814
           trio_pointer_t ref,
 
4815
           int is_size)
 
4816
{
 
4817
  if (is_size)
 
4818
    ((trio_reference_t *)ref)->parameter->flags |= FLAGS_SIZE_T;
 
4819
  else
 
4820
    ((trio_reference_t *)ref)->parameter->flags &= ~FLAGS_SIZE_T;
 
4821
}
 
4822
#endif
 
4823
 
 
4824
/*************************************************************************
 
4825
 * trio_print_int [public]
 
4826
 */
 
4827
void
 
4828
trio_print_int
 
4829
TRIO_ARGS2((ref, number),
 
4830
           trio_pointer_t ref,
 
4831
           int number)
 
4832
{
 
4833
  trio_reference_t *self = (trio_reference_t *)ref;
 
4834
 
 
4835
  TrioWriteNumber(self->data,
 
4836
                  (trio_uintmax_t)number,
 
4837
                  self->parameter->flags,
 
4838
                  self->parameter->width,
 
4839
                  self->parameter->precision,
 
4840
                  self->parameter->base);
 
4841
}
 
4842
 
 
4843
/*************************************************************************
 
4844
 * trio_print_uint [public]
 
4845
 */
 
4846
void
 
4847
trio_print_uint
 
4848
TRIO_ARGS2((ref, number),
 
4849
           trio_pointer_t ref,
 
4850
           unsigned int number)
 
4851
{
 
4852
  trio_reference_t *self = (trio_reference_t *)ref;
 
4853
 
 
4854
  TrioWriteNumber(self->data,
 
4855
                  (trio_uintmax_t)number,
 
4856
                  self->parameter->flags | FLAGS_UNSIGNED,
 
4857
                  self->parameter->width,
 
4858
                  self->parameter->precision,
 
4859
                  self->parameter->base);
 
4860
}
 
4861
 
 
4862
/*************************************************************************
 
4863
 * trio_print_double [public]
 
4864
 */
 
4865
void
 
4866
trio_print_double
 
4867
TRIO_ARGS2((ref, number),
 
4868
           trio_pointer_t ref,
 
4869
           double number)
 
4870
{
 
4871
  trio_reference_t *self = (trio_reference_t *)ref;
 
4872
 
 
4873
  TrioWriteDouble(self->data,
 
4874
                  number,
 
4875
                  self->parameter->flags,
 
4876
                  self->parameter->width,
 
4877
                  self->parameter->precision,
 
4878
                  self->parameter->base);
 
4879
}
 
4880
 
 
4881
/*************************************************************************
 
4882
 * trio_print_string [public]
 
4883
 */
 
4884
void
 
4885
trio_print_string
 
4886
TRIO_ARGS2((ref, string),
 
4887
           trio_pointer_t ref,
 
4888
           char *string)
 
4889
{
 
4890
  trio_reference_t *self = (trio_reference_t *)ref;
 
4891
 
 
4892
  TrioWriteString(self->data,
 
4893
                  string,
 
4894
                  self->parameter->flags,
 
4895
                  self->parameter->width,
 
4896
                  self->parameter->precision);
 
4897
}
 
4898
 
 
4899
/*************************************************************************
 
4900
 * trio_print_ref [public]
 
4901
 */
 
4902
int
 
4903
trio_print_ref
 
4904
TRIO_VARGS3((ref, format, va_alist),
 
4905
            trio_pointer_t ref,
 
4906
            TRIO_CONST char *format,
 
4907
            TRIO_VA_DECL)
 
4908
{
 
4909
  int status;
 
4910
  va_list arglist;
 
4911
 
 
4912
  assert(VALID(format));
 
4913
  
 
4914
  TRIO_VA_START(arglist, format);
 
4915
  status = TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
 
4916
  TRIO_VA_END(arglist);
 
4917
  return status;
 
4918
}
 
4919
 
 
4920
/*************************************************************************
 
4921
 * trio_vprint_ref [public]
 
4922
 */
 
4923
int
 
4924
trio_vprint_ref
 
4925
TRIO_ARGS3((ref, format, arglist),
 
4926
           trio_pointer_t ref,
 
4927
           TRIO_CONST char *format,
 
4928
           va_list arglist)
 
4929
{
 
4930
  assert(VALID(format));
 
4931
  
 
4932
  return TrioFormatRef((trio_reference_t *)ref, format, &arglist, NULL);
 
4933
}
 
4934
 
 
4935
/*************************************************************************
 
4936
 * trio_printv_ref [public]
 
4937
 */
 
4938
int
 
4939
trio_printv_ref
 
4940
TRIO_ARGS3((ref, format, argarray),
 
4941
           trio_pointer_t ref,
 
4942
           TRIO_CONST char *format,
 
4943
           trio_pointer_t *argarray)
 
4944
{
 
4945
  assert(VALID(format));
 
4946
  
 
4947
  return TrioFormatRef((trio_reference_t *)ref, format, NULL, argarray);
 
4948
}
 
4949
 
 
4950
#endif /* TRIO_EXTENSION */
 
4951
 
 
4952
/*************************************************************************
 
4953
 * trio_print_pointer [public]
 
4954
 */
 
4955
void
 
4956
trio_print_pointer
 
4957
TRIO_ARGS2((ref, pointer),
 
4958
           trio_pointer_t ref,
 
4959
           trio_pointer_t pointer)
 
4960
{
 
4961
  trio_reference_t *self = (trio_reference_t *)ref;
 
4962
  trio_flags_t flags;
 
4963
  trio_uintmax_t number;
 
4964
 
 
4965
  if (NULL == pointer)
 
4966
    {
 
4967
      TRIO_CONST char *string = internalNullString;
 
4968
      while (*string)
 
4969
        self->data->OutStream(self->data, *string++);
 
4970
    }
 
4971
  else
 
4972
    {
 
4973
      /*
 
4974
       * The subtraction of the null pointer is a workaround
 
4975
       * to avoid a compiler warning. The performance overhead
 
4976
       * is negligible (and likely to be removed by an
 
4977
       * optimizing compiler). The (char *) casting is done
 
4978
       * to please ANSI C++.
 
4979
       */
 
4980
      number = (trio_uintmax_t)((char *)pointer - (char *)0);
 
4981
      /* Shrink to size of pointer */
 
4982
      number &= (trio_uintmax_t)-1;
 
4983
      flags = self->parameter->flags;
 
4984
      flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
 
4985
                FLAGS_NILPADDING);
 
4986
      TrioWriteNumber(self->data,
 
4987
                      number,
 
4988
                      flags,
 
4989
                      POINTER_WIDTH,
 
4990
                      NO_PRECISION,
 
4991
                      BASE_HEX);
 
4992
    }
 
4993
}
 
4994
 
 
4995
/** @} End of UserDefined documentation module */
 
4996
 
 
4997
/*************************************************************************
 
4998
 *
 
4999
 * LOCALES
 
5000
 *
 
5001
 ************************************************************************/
 
5002
 
 
5003
/*************************************************************************
 
5004
 * trio_locale_set_decimal_point
 
5005
 *
 
5006
 * Decimal point can only be one character. The input argument is a
 
5007
 * string to enable multibyte characters. At most MB_LEN_MAX characters
 
5008
 * will be used.
 
5009
 */
 
5010
TRIO_PUBLIC void
 
5011
trio_locale_set_decimal_point
 
5012
TRIO_ARGS1((decimalPoint),
 
5013
           char *decimalPoint)
 
5014
{
 
5015
#if defined(USE_LOCALE)
 
5016
  if (NULL == internalLocaleValues)
 
5017
    {
 
5018
      TrioSetLocale();
 
5019
    }
 
5020
#endif
 
5021
  internalDecimalPointLength = trio_length(decimalPoint);
 
5022
  if (internalDecimalPointLength == 1)
 
5023
    {
 
5024
      internalDecimalPoint = *decimalPoint;
 
5025
    }
 
5026
  else
 
5027
    {
 
5028
      internalDecimalPoint = NIL;
 
5029
      trio_copy_max(internalDecimalPointString,
 
5030
                    sizeof(internalDecimalPointString),
 
5031
                    decimalPoint);
 
5032
    }
 
5033
}
 
5034
 
 
5035
/*************************************************************************
 
5036
 * trio_locale_set_thousand_separator
 
5037
 *
 
5038
 * See trio_locale_set_decimal_point
 
5039
 */
 
5040
TRIO_PUBLIC void
 
5041
trio_locale_set_thousand_separator
 
5042
TRIO_ARGS1((thousandSeparator),
 
5043
           char *thousandSeparator)
 
5044
{
 
5045
#if defined(USE_LOCALE)
 
5046
  if (NULL == internalLocaleValues)
 
5047
    {
 
5048
      TrioSetLocale();
 
5049
    }
 
5050
#endif
 
5051
  trio_copy_max(internalThousandSeparator,
 
5052
                sizeof(internalThousandSeparator),
 
5053
                thousandSeparator);
 
5054
  internalThousandSeparatorLength = trio_length(internalThousandSeparator);
 
5055
}
 
5056
 
 
5057
/*************************************************************************
 
5058
 * trio_locale_set_grouping
 
5059
 *
 
5060
 * Array of bytes. Reversed order.
 
5061
 *
 
5062
 *  CHAR_MAX : No further grouping
 
5063
 *  0        : Repeat last group for the remaining digits (not necessary
 
5064
 *             as C strings are zero-terminated)
 
5065
 *  n        : Set current group to n
 
5066
 *
 
5067
 * Same order as the grouping attribute in LC_NUMERIC.
 
5068
 */
 
5069
TRIO_PUBLIC void
 
5070
trio_locale_set_grouping
 
5071
TRIO_ARGS1((grouping),
 
5072
           char *grouping)
 
5073
{
 
5074
#if defined(USE_LOCALE)
 
5075
  if (NULL == internalLocaleValues)
 
5076
    {
 
5077
      TrioSetLocale();
 
5078
    }
 
5079
#endif
 
5080
  trio_copy_max(internalGrouping,
 
5081
                sizeof(internalGrouping),
 
5082
                grouping);
 
5083
}
 
5084
 
 
5085
 
 
5086
/*************************************************************************
 
5087
 *
 
5088
 * SCANNING
 
5089
 *
 
5090
 ************************************************************************/
 
5091
 
 
5092
/*************************************************************************
 
5093
 * TrioSkipWhitespaces
 
5094
 */
 
5095
TRIO_PRIVATE int
 
5096
TrioSkipWhitespaces
 
5097
TRIO_ARGS1((self),
 
5098
           trio_class_t *self)
 
5099
{
 
5100
  int ch;
 
5101
 
 
5102
  ch = self->current;
 
5103
  while (isspace(ch))
 
5104
    {
 
5105
      self->InStream(self, &ch);
 
5106
    }
 
5107
  return ch;
 
5108
}
 
5109
 
 
5110
/*************************************************************************
 
5111
 * TrioGetCollation
 
5112
 */
 
5113
#if TRIO_EXTENSION
 
5114
TRIO_PRIVATE void
 
5115
TrioGetCollation(TRIO_NOARGS)
 
5116
{
 
5117
  int i;
 
5118
  int j;
 
5119
  int k;
 
5120
  char first[2];
 
5121
  char second[2];
 
5122
 
 
5123
  /* This is computationally expensive */
 
5124
  first[1] = NIL;
 
5125
  second[1] = NIL;
 
5126
  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5127
    {
 
5128
      k = 0;
 
5129
      first[0] = (char)i;
 
5130
      for (j = 0; j < MAX_CHARACTER_CLASS; j++)
 
5131
        {
 
5132
          second[0] = (char)j;
 
5133
          if (trio_equal_locale(first, second))
 
5134
            internalCollationArray[i][k++] = (char)j;
 
5135
        }
 
5136
      internalCollationArray[i][k] = NIL;
 
5137
    }
 
5138
}
 
5139
#endif
 
5140
 
 
5141
/*************************************************************************
 
5142
 * TrioGetCharacterClass
 
5143
 *
 
5144
 * FIXME:
 
5145
 *  multibyte
 
5146
 */
 
5147
TRIO_PRIVATE int
 
5148
TrioGetCharacterClass
 
5149
TRIO_ARGS4((format, indexPointer, flagsPointer, characterclass),
 
5150
           TRIO_CONST char *format,
 
5151
           int *indexPointer,
 
5152
           trio_flags_t *flagsPointer,
 
5153
           int *characterclass)
 
5154
{
 
5155
  int index = *indexPointer;
 
5156
  int i;
 
5157
  char ch;
 
5158
  char range_begin;
 
5159
  char range_end;
 
5160
 
 
5161
  *flagsPointer &= ~FLAGS_EXCLUDE;
 
5162
 
 
5163
  if (format[index] == QUALIFIER_CIRCUMFLEX)
 
5164
    {
 
5165
      *flagsPointer |= FLAGS_EXCLUDE;
 
5166
      index++;
 
5167
    }
 
5168
  /*
 
5169
   * If the ungroup character is at the beginning of the scanlist,
 
5170
   * it will be part of the class, and a second ungroup character
 
5171
   * must follow to end the group.
 
5172
   */
 
5173
  if (format[index] == SPECIFIER_UNGROUP)
 
5174
    {
 
5175
      characterclass[(int)SPECIFIER_UNGROUP]++;
 
5176
      index++;
 
5177
    }
 
5178
  /*
 
5179
   * Minus is used to specify ranges. To include minus in the class,
 
5180
   * it must be at the beginning of the list
 
5181
   */
 
5182
  if (format[index] == QUALIFIER_MINUS)
 
5183
    {
 
5184
      characterclass[(int)QUALIFIER_MINUS]++;
 
5185
      index++;
 
5186
    }
 
5187
  /* Collect characters */
 
5188
  for (ch = format[index];
 
5189
       (ch != SPECIFIER_UNGROUP) && (ch != NIL);
 
5190
       ch = format[++index])
 
5191
    {
 
5192
      switch (ch)
 
5193
        {
 
5194
        case QUALIFIER_MINUS: /* Scanlist ranges */
 
5195
          
 
5196
          /*
 
5197
           * Both C99 and UNIX98 describes ranges as implementation-
 
5198
           * defined.
 
5199
           *
 
5200
           * We support the following behaviour (although this may
 
5201
           * change as we become wiser)
 
5202
           * - only increasing ranges, ie. [a-b] but not [b-a]
 
5203
           * - transitive ranges, ie. [a-b-c] == [a-c]
 
5204
           * - trailing minus, ie. [a-] is interpreted as an 'a'
 
5205
           *   and a '-'
 
5206
           * - duplicates (although we can easily convert these
 
5207
           *   into errors)
 
5208
           */
 
5209
          range_begin = format[index - 1];
 
5210
          range_end = format[++index];
 
5211
          if (range_end == SPECIFIER_UNGROUP)
 
5212
            {
 
5213
              /* Trailing minus is included */
 
5214
              characterclass[(int)ch]++;
 
5215
              ch = range_end;
 
5216
              break; /* for */
 
5217
            }
 
5218
          if (range_end == NIL)
 
5219
            return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
5220
          if (range_begin > range_end)
 
5221
            return TRIO_ERROR_RETURN(TRIO_ERANGE, index);
 
5222
            
 
5223
          for (i = (int)range_begin; i <= (int)range_end; i++)
 
5224
            characterclass[i]++;
 
5225
            
 
5226
          ch = range_end;
 
5227
          break;
 
5228
          
 
5229
#if TRIO_EXTENSION
 
5230
 
 
5231
        case SPECIFIER_GROUP:
 
5232
          
 
5233
          switch (format[index + 1])
 
5234
            {
 
5235
            case QUALIFIER_DOT: /* Collating symbol */
 
5236
              /*
 
5237
               * FIXME: This will be easier to implement when multibyte
 
5238
               * characters have been implemented. Until now, we ignore
 
5239
               * this feature.
 
5240
               */
 
5241
              for (i = index + 2; ; i++)
 
5242
                {
 
5243
                  if (format[i] == NIL)
 
5244
                    /* Error in syntax */
 
5245
                    return -1;
 
5246
                  else if (format[i] == QUALIFIER_DOT)
 
5247
                    break; /* for */
 
5248
                }
 
5249
              if (format[++i] != SPECIFIER_UNGROUP)
 
5250
                return -1;
 
5251
              
 
5252
              index = i;
 
5253
              break;
 
5254
          
 
5255
            case QUALIFIER_EQUAL: /* Equivalence class expressions */
 
5256
              {
 
5257
                unsigned int j;
 
5258
                unsigned int k;
 
5259
            
 
5260
                if (internalCollationUnconverted)
 
5261
                  {
 
5262
                    /* Lazy evaluation of collation array */
 
5263
                    TrioGetCollation();
 
5264
                    internalCollationUnconverted = FALSE;
 
5265
                  }
 
5266
                for (i = index + 2; ; i++)
 
5267
                  {
 
5268
                    if (format[i] == NIL)
 
5269
                      /* Error in syntax */
 
5270
                      return -1;
 
5271
                    else if (format[i] == QUALIFIER_EQUAL)
 
5272
                      break; /* for */
 
5273
                    else
 
5274
                      {
 
5275
                        /* Mark any equivalent character */
 
5276
                        k = (unsigned int)format[i];
 
5277
                        for (j = 0; internalCollationArray[k][j] != NIL; j++)
 
5278
                          characterclass[(int)internalCollationArray[k][j]]++;
 
5279
                      }
 
5280
                  }
 
5281
                if (format[++i] != SPECIFIER_UNGROUP)
 
5282
                  return -1;
 
5283
                
 
5284
                index = i;
 
5285
              }
 
5286
              break;
 
5287
          
 
5288
            case QUALIFIER_COLON: /* Character class expressions */
 
5289
          
 
5290
              if (trio_equal_max(CLASS_ALNUM, sizeof(CLASS_ALNUM) - 1,
 
5291
                                 &format[index]))
 
5292
                {
 
5293
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5294
                    if (isalnum(i))
 
5295
                      characterclass[i]++;
 
5296
                  index += sizeof(CLASS_ALNUM) - 1;
 
5297
                }
 
5298
              else if (trio_equal_max(CLASS_ALPHA, sizeof(CLASS_ALPHA) - 1,
 
5299
                                      &format[index]))
 
5300
                {
 
5301
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5302
                    if (isalpha(i))
 
5303
                      characterclass[i]++;
 
5304
                  index += sizeof(CLASS_ALPHA) - 1;
 
5305
                }
 
5306
              else if (trio_equal_max(CLASS_CNTRL, sizeof(CLASS_CNTRL) - 1,
 
5307
                                      &format[index]))
 
5308
                {
 
5309
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5310
                    if (iscntrl(i))
 
5311
                      characterclass[i]++;
 
5312
                  index += sizeof(CLASS_CNTRL) - 1;
 
5313
                }
 
5314
              else if (trio_equal_max(CLASS_DIGIT, sizeof(CLASS_DIGIT) - 1,
 
5315
                                      &format[index]))
 
5316
                {
 
5317
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5318
                    if (isdigit(i))
 
5319
                      characterclass[i]++;
 
5320
                  index += sizeof(CLASS_DIGIT) - 1;
 
5321
                }
 
5322
              else if (trio_equal_max(CLASS_GRAPH, sizeof(CLASS_GRAPH) - 1,
 
5323
                                      &format[index]))
 
5324
                {
 
5325
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5326
                    if (isgraph(i))
 
5327
                      characterclass[i]++;
 
5328
                  index += sizeof(CLASS_GRAPH) - 1;
 
5329
                }
 
5330
              else if (trio_equal_max(CLASS_LOWER, sizeof(CLASS_LOWER) - 1,
 
5331
                                      &format[index]))
 
5332
                {
 
5333
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5334
                    if (islower(i))
 
5335
                      characterclass[i]++;
 
5336
                  index += sizeof(CLASS_LOWER) - 1;
 
5337
                }
 
5338
              else if (trio_equal_max(CLASS_PRINT, sizeof(CLASS_PRINT) - 1,
 
5339
                                      &format[index]))
 
5340
                {
 
5341
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5342
                    if (isprint(i))
 
5343
                      characterclass[i]++;
 
5344
                  index += sizeof(CLASS_PRINT) - 1;
 
5345
                }
 
5346
              else if (trio_equal_max(CLASS_PUNCT, sizeof(CLASS_PUNCT) - 1,
 
5347
                                      &format[index]))
 
5348
                {
 
5349
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5350
                    if (ispunct(i))
 
5351
                      characterclass[i]++;
 
5352
                  index += sizeof(CLASS_PUNCT) - 1;
 
5353
                }
 
5354
              else if (trio_equal_max(CLASS_SPACE, sizeof(CLASS_SPACE) - 1,
 
5355
                                      &format[index]))
 
5356
                {
 
5357
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5358
                    if (isspace(i))
 
5359
                      characterclass[i]++;
 
5360
                  index += sizeof(CLASS_SPACE) - 1;
 
5361
                }
 
5362
              else if (trio_equal_max(CLASS_UPPER, sizeof(CLASS_UPPER) - 1,
 
5363
                                      &format[index]))
 
5364
                {
 
5365
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5366
                    if (isupper(i))
 
5367
                      characterclass[i]++;
 
5368
                  index += sizeof(CLASS_UPPER) - 1;
 
5369
                }
 
5370
              else if (trio_equal_max(CLASS_XDIGIT, sizeof(CLASS_XDIGIT) - 1,
 
5371
                                      &format[index]))
 
5372
                {
 
5373
                  for (i = 0; i < MAX_CHARACTER_CLASS; i++)
 
5374
                    if (isxdigit(i))
 
5375
                      characterclass[i]++;
 
5376
                  index += sizeof(CLASS_XDIGIT) - 1;
 
5377
                }
 
5378
              else
 
5379
                {
 
5380
                  characterclass[(int)ch]++;
 
5381
                }
 
5382
              break;
 
5383
 
 
5384
            default:
 
5385
              characterclass[(int)ch]++;
 
5386
              break;
 
5387
            }
 
5388
          break;
 
5389
          
 
5390
#endif /* TRIO_EXTENSION */
 
5391
          
 
5392
        default:
 
5393
          characterclass[(int)ch]++;
 
5394
          break;
 
5395
        }
 
5396
    }
 
5397
  return 0;
 
5398
}
 
5399
 
 
5400
/*************************************************************************
 
5401
 * TrioReadNumber
 
5402
 *
 
5403
 * We implement our own number conversion in preference of strtol and
 
5404
 * strtoul, because we must handle 'long long' and thousand separators.
 
5405
 */
 
5406
TRIO_PRIVATE BOOLEAN_T
 
5407
TrioReadNumber
 
5408
TRIO_ARGS5((self, target, flags, width, base),
 
5409
           trio_class_t *self,
 
5410
           trio_uintmax_t *target,
 
5411
           trio_flags_t flags,
 
5412
           int width,
 
5413
           int base)
 
5414
{
 
5415
  trio_uintmax_t number = 0;
 
5416
  int digit;
 
5417
  int count;
 
5418
  BOOLEAN_T isNegative = FALSE;
 
5419
  BOOLEAN_T gotNumber = FALSE;
 
5420
  int j;
 
5421
 
 
5422
  assert(VALID(self));
 
5423
  assert(VALID(self->InStream));
 
5424
  assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
 
5425
 
 
5426
  if (internalDigitsUnconverted)
 
5427
    {
 
5428
      /* Lazy evaluation of digits array */
 
5429
      memset(internalDigitArray, -1, sizeof(internalDigitArray));
 
5430
      for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
 
5431
        {
 
5432
          internalDigitArray[(int)internalDigitsLower[j]] = j;
 
5433
          internalDigitArray[(int)internalDigitsUpper[j]] = j;
 
5434
        }
 
5435
      internalDigitsUnconverted = FALSE;
 
5436
    }
 
5437
  
 
5438
  TrioSkipWhitespaces(self);
 
5439
  
 
5440
  if (!(flags & FLAGS_UNSIGNED))
 
5441
    {
 
5442
      /* Leading sign */
 
5443
      if (self->current == '+')
 
5444
        {
 
5445
          self->InStream(self, NULL);
 
5446
        }
 
5447
      else if (self->current == '-')
 
5448
        {
 
5449
          self->InStream(self, NULL);
 
5450
          isNegative = TRUE;
 
5451
        }
 
5452
    }
 
5453
  
 
5454
  count = self->processed;
 
5455
  
 
5456
  if (flags & FLAGS_ALTERNATIVE)
 
5457
    {
 
5458
      switch (base)
 
5459
        {
 
5460
        case NO_BASE:
 
5461
        case BASE_OCTAL:
 
5462
        case BASE_HEX:
 
5463
        case BASE_BINARY:
 
5464
          if (self->current == '0')
 
5465
            {
 
5466
              self->InStream(self, NULL);
 
5467
              if (self->current)
 
5468
                {
 
5469
                  if ((base == BASE_HEX) &&
 
5470
                      (trio_to_upper(self->current) == 'X'))
 
5471
                    {
 
5472
                      self->InStream(self, NULL);
 
5473
                    }
 
5474
                  else if ((base == BASE_BINARY) &&
 
5475
                           (trio_to_upper(self->current) == 'B'))
 
5476
                    {
 
5477
                      self->InStream(self, NULL);
 
5478
                    }
 
5479
                }
 
5480
            }
 
5481
          else
 
5482
            return FALSE;
 
5483
          break;
 
5484
        default:
 
5485
          break;
 
5486
        }
 
5487
    }
 
5488
 
 
5489
  while (((width == NO_WIDTH) || (self->processed - count < width)) &&
 
5490
         (! ((self->current == EOF) || isspace(self->current))))
 
5491
    {
 
5492
      if (isascii(self->current))
 
5493
        {
 
5494
          digit = internalDigitArray[self->current];
 
5495
          /* Abort if digit is not allowed in the specified base */
 
5496
          if ((digit == -1) || (digit >= base))
 
5497
            break;
 
5498
        }
 
5499
      else if (flags & FLAGS_QUOTE)
 
5500
        {
 
5501
          /* Compare with thousands separator */
 
5502
          for (j = 0; internalThousandSeparator[j] && self->current; j++)
 
5503
            {
 
5504
              if (internalThousandSeparator[j] != self->current)
 
5505
                break;
 
5506
 
 
5507
              self->InStream(self, NULL);
 
5508
            }
 
5509
          if (internalThousandSeparator[j])
 
5510
            break; /* Mismatch */
 
5511
          else
 
5512
            continue; /* Match */
 
5513
        }
 
5514
      else
 
5515
        break;
 
5516
            
 
5517
      number *= base;
 
5518
      number += digit;
 
5519
      gotNumber = TRUE; /* we need at least one digit */
 
5520
 
 
5521
      self->InStream(self, NULL);
 
5522
    }
 
5523
 
 
5524
  /* Was anything read at all? */
 
5525
  if (!gotNumber)
 
5526
    return FALSE;
 
5527
  
 
5528
  if (target)
 
5529
    *target = (isNegative) ? -((trio_intmax_t)number) : number;
 
5530
  return TRUE;
 
5531
}
 
5532
 
 
5533
/*************************************************************************
 
5534
 * TrioReadChar
 
5535
 */
 
5536
TRIO_PRIVATE int
 
5537
TrioReadChar
 
5538
TRIO_ARGS4((self, target, flags, width),
 
5539
           trio_class_t *self,
 
5540
           char *target,
 
5541
           trio_flags_t flags,
 
5542
           int width)
 
5543
{
 
5544
  int i;
 
5545
  char ch;
 
5546
  trio_uintmax_t number;
 
5547
  
 
5548
  assert(VALID(self));
 
5549
  assert(VALID(self->InStream));
 
5550
 
 
5551
  for (i = 0;
 
5552
       (self->current != EOF) && (i < width);
 
5553
       i++)
 
5554
    {
 
5555
      ch = (char)self->current;
 
5556
      self->InStream(self, NULL);
 
5557
      if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
 
5558
        {
 
5559
          switch (self->current)
 
5560
            {
 
5561
            case '\\': ch = '\\'; break;
 
5562
            case 'a': ch = '\007'; break;
 
5563
            case 'b': ch = '\b'; break;
 
5564
            case 'f': ch = '\f'; break;
 
5565
            case 'n': ch = '\n'; break;
 
5566
            case 'r': ch = '\r'; break;
 
5567
            case 't': ch = '\t'; break;
 
5568
            case 'v': ch = '\v'; break;
 
5569
            default:
 
5570
              if (isdigit(self->current))
 
5571
                {
 
5572
                  /* Read octal number */
 
5573
                  if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
 
5574
                    return 0;
 
5575
                  ch = (char)number;
 
5576
                }
 
5577
              else if (trio_to_upper(self->current) == 'X')
 
5578
                {
 
5579
                  /* Read hexadecimal number */
 
5580
                  self->InStream(self, NULL);
 
5581
                  if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
 
5582
                    return 0;
 
5583
                  ch = (char)number;
 
5584
                }
 
5585
              else
 
5586
                {
 
5587
                  ch = (char)self->current;
 
5588
                }
 
5589
              break;
 
5590
            }
 
5591
        }
 
5592
      
 
5593
      if (target)
 
5594
        target[i] = ch;
 
5595
    }
 
5596
  return i + 1;
 
5597
}
 
5598
 
 
5599
/*************************************************************************
 
5600
 * TrioReadString
 
5601
 */
 
5602
TRIO_PRIVATE BOOLEAN_T
 
5603
TrioReadString
 
5604
TRIO_ARGS4((self, target, flags, width),
 
5605
           trio_class_t *self,
 
5606
           char *target,
 
5607
           trio_flags_t flags,
 
5608
           int width)
 
5609
{
 
5610
  int i;
 
5611
  
 
5612
  assert(VALID(self));
 
5613
  assert(VALID(self->InStream));
 
5614
 
 
5615
  TrioSkipWhitespaces(self);
 
5616
    
 
5617
  /*
 
5618
   * Continue until end of string is reached, a whitespace is encountered,
 
5619
   * or width is exceeded
 
5620
   */
 
5621
  for (i = 0;
 
5622
       ((width == NO_WIDTH) || (i < width)) &&
 
5623
       (! ((self->current == EOF) || isspace(self->current)));
 
5624
       i++)
 
5625
    {
 
5626
      if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
 
5627
        break; /* for */
 
5628
    }
 
5629
  if (target)
 
5630
    target[i] = NIL;
 
5631
  return TRUE;
 
5632
}
 
5633
 
 
5634
/*************************************************************************
 
5635
 * TrioReadWideChar
 
5636
 */
 
5637
#if TRIO_WIDECHAR
 
5638
TRIO_PRIVATE int
 
5639
TrioReadWideChar
 
5640
TRIO_ARGS4((self, target, flags, width),
 
5641
           trio_class_t *self,
 
5642
           trio_wchar_t *target,
 
5643
           trio_flags_t flags,
 
5644
           int width)
 
5645
{
 
5646
  int i;
 
5647
  int j;
 
5648
  int size;
 
5649
  int amount = 0;
 
5650
  trio_wchar_t wch;
 
5651
  char buffer[MB_LEN_MAX + 1];
 
5652
  
 
5653
  assert(VALID(self));
 
5654
  assert(VALID(self->InStream));
 
5655
 
 
5656
  for (i = 0;
 
5657
       (self->current != EOF) && (i < width);
 
5658
       i++)
 
5659
    {
 
5660
      if (isascii(self->current))
 
5661
        {
 
5662
          if (TrioReadChar(self, buffer, flags, 1) == 0)
 
5663
            return 0;
 
5664
          buffer[1] = NIL;
 
5665
        }
 
5666
      else
 
5667
        {
 
5668
          /*
 
5669
           * Collect a multibyte character, by enlarging buffer until
 
5670
           * it contains a fully legal multibyte character, or the
 
5671
           * buffer is full.
 
5672
           */
 
5673
          j = 0;
 
5674
          do
 
5675
            {
 
5676
              buffer[j++] = (char)self->current;
 
5677
              buffer[j] = NIL;
 
5678
              self->InStream(self, NULL);
 
5679
            }
 
5680
          while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
 
5681
        }
 
5682
      if (target)
 
5683
        {
 
5684
          size = mbtowc(&wch, buffer, sizeof(buffer));
 
5685
          if (size > 0)
 
5686
            target[i] = wch;
 
5687
        }
 
5688
      amount += size;
 
5689
      self->InStream(self, NULL);
 
5690
    }
 
5691
  return amount;
 
5692
}
 
5693
#endif /* TRIO_WIDECHAR */
 
5694
 
 
5695
/*************************************************************************
 
5696
 * TrioReadWideString
 
5697
 */
 
5698
#if TRIO_WIDECHAR
 
5699
TRIO_PRIVATE BOOLEAN_T
 
5700
TrioReadWideString
 
5701
TRIO_ARGS4((self, target, flags, width),
 
5702
           trio_class_t *self,
 
5703
           trio_wchar_t *target,
 
5704
           trio_flags_t flags,
 
5705
           int width)
 
5706
{
 
5707
  int i;
 
5708
  int size;
 
5709
  
 
5710
  assert(VALID(self));
 
5711
  assert(VALID(self->InStream));
 
5712
 
 
5713
  TrioSkipWhitespaces(self);
 
5714
 
 
5715
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
5716
  (void)mblen(NULL, 0);
 
5717
#endif
 
5718
  
 
5719
  /*
 
5720
   * Continue until end of string is reached, a whitespace is encountered,
 
5721
   * or width is exceeded
 
5722
   */
 
5723
  for (i = 0;
 
5724
       ((width == NO_WIDTH) || (i < width)) &&
 
5725
       (! ((self->current == EOF) || isspace(self->current)));
 
5726
       )
 
5727
    {
 
5728
      size = TrioReadWideChar(self, &target[i], flags, 1);
 
5729
      if (size == 0)
 
5730
        break; /* for */
 
5731
 
 
5732
      i += size;
 
5733
    }
 
5734
  if (target)
 
5735
    target[i] = WCONST('\0');
 
5736
  return TRUE;
 
5737
}
 
5738
#endif /* TRIO_WIDECHAR */
 
5739
 
 
5740
/*************************************************************************
 
5741
 * TrioReadGroup
 
5742
 *
 
5743
 * FIXME: characterclass does not work with multibyte characters
 
5744
 */
 
5745
TRIO_PRIVATE BOOLEAN_T
 
5746
TrioReadGroup
 
5747
TRIO_ARGS5((self, target, characterclass, flags, width),
 
5748
           trio_class_t *self,
 
5749
           char *target,
 
5750
           int *characterclass,
 
5751
           trio_flags_t flags,
 
5752
           int width)
 
5753
{
 
5754
  int ch;
 
5755
  int i;
 
5756
  
 
5757
  assert(VALID(self));
 
5758
  assert(VALID(self->InStream));
 
5759
 
 
5760
  ch = self->current;
 
5761
  for (i = 0;
 
5762
       ((width == NO_WIDTH) || (i < width)) &&
 
5763
       (! ((ch == EOF) ||
 
5764
           (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
 
5765
       i++)
 
5766
    {
 
5767
      if (target)
 
5768
        target[i] = (char)ch;
 
5769
      self->InStream(self, &ch);
 
5770
    }
 
5771
  
 
5772
  if (target)
 
5773
    target[i] = NIL;
 
5774
  return TRUE;
 
5775
}
 
5776
 
 
5777
/*************************************************************************
 
5778
 * TrioReadDouble
 
5779
 *
 
5780
 * FIXME:
 
5781
 *  add long double
 
5782
 *  handle base
 
5783
 */
 
5784
TRIO_PRIVATE BOOLEAN_T
 
5785
TrioReadDouble
 
5786
TRIO_ARGS4((self, target, flags, width),
 
5787
           trio_class_t *self,
 
5788
           trio_pointer_t target,
 
5789
           trio_flags_t flags,
 
5790
           int width)
 
5791
{
 
5792
  int ch;
 
5793
  char doubleString[512];
 
5794
  int index = 0;
 
5795
  int start;
 
5796
  int j;
 
5797
  BOOLEAN_T isHex = FALSE;
 
5798
 
 
5799
  doubleString[0] = 0;
 
5800
  
 
5801
  if ((width == NO_WIDTH) || (width > (int)sizeof(doubleString) - 1))
 
5802
    width = sizeof(doubleString) - 1;
 
5803
  
 
5804
  TrioSkipWhitespaces(self);
 
5805
  
 
5806
  /*
 
5807
   * Read entire double number from stream. trio_to_double requires
 
5808
   * a string as input, but InStream can be anything, so we have to
 
5809
   * collect all characters.
 
5810
   */
 
5811
  ch = self->current;
 
5812
  if ((ch == '+') || (ch == '-'))
 
5813
    {
 
5814
      doubleString[index++] = (char)ch;
 
5815
      self->InStream(self, &ch);
 
5816
      width--;
 
5817
    }
 
5818
 
 
5819
  start = index;
 
5820
  switch (ch)
 
5821
    {
 
5822
    case 'n':
 
5823
    case 'N':
 
5824
      /* Not-a-number */
 
5825
      if (index != 0)
 
5826
        break;
 
5827
      /* FALLTHROUGH */
 
5828
    case 'i':
 
5829
    case 'I':
 
5830
      /* Infinity */
 
5831
      while (isalpha(ch) && (index - start < width))
 
5832
        {
 
5833
          doubleString[index++] = (char)ch;
 
5834
          self->InStream(self, &ch);
 
5835
        }
 
5836
      doubleString[index] = NIL;
 
5837
 
 
5838
      /* Case insensitive string comparison */
 
5839
      if (trio_equal(&doubleString[start], INFINITE_UPPER) ||
 
5840
          trio_equal(&doubleString[start], LONG_INFINITE_UPPER))
 
5841
        {
 
5842
          if (flags & FLAGS_LONGDOUBLE)
 
5843
            {
 
5844
              if ((start == 1) && (doubleString[0] == '-'))
 
5845
                {
 
5846
                  *((trio_long_double_t *)target) = trio_ninf();
 
5847
                }
 
5848
              else
 
5849
                {
 
5850
                  *((trio_long_double_t *)target) = trio_pinf();
 
5851
                }
 
5852
            }
 
5853
          else
 
5854
            {
 
5855
              if ((start == 1) && (doubleString[0] == '-'))
 
5856
                {
 
5857
                  *((double *)target) = trio_ninf();
 
5858
                }
 
5859
              else
 
5860
                {
 
5861
                  *((double *)target) = trio_pinf();
 
5862
                }
 
5863
            }
 
5864
          return TRUE;
 
5865
        }
 
5866
      if (trio_equal(doubleString, NAN_UPPER))
 
5867
        {
 
5868
          /* NaN must not have a preceeding + nor - */
 
5869
          if (flags & FLAGS_LONGDOUBLE)
 
5870
            {
 
5871
              *((trio_long_double_t *)target) = trio_nan();
 
5872
            }
 
5873
          else
 
5874
            {
 
5875
              *((double *)target) = trio_nan();
 
5876
            }
 
5877
          return TRUE;
 
5878
        }
 
5879
      return FALSE;
 
5880
 
 
5881
    case '0':
 
5882
      doubleString[index++] = (char)ch;
 
5883
      self->InStream(self, &ch);
 
5884
      if (trio_to_upper(ch) == 'X')
 
5885
        {
 
5886
          isHex = TRUE;
 
5887
          doubleString[index++] = (char)ch;
 
5888
          self->InStream(self, &ch);
 
5889
        }
 
5890
      break;
 
5891
      
 
5892
    default:
 
5893
      break;
 
5894
    }
 
5895
  
 
5896
  while ((ch != EOF) && (index - start < width))
 
5897
    {
 
5898
      /* Integer part */
 
5899
      if (isHex ? isxdigit(ch) : isdigit(ch))
 
5900
        {
 
5901
          doubleString[index++] = (char)ch;
 
5902
          self->InStream(self, &ch);
 
5903
        }
 
5904
      else if (flags & FLAGS_QUOTE)
 
5905
        {
 
5906
          /* Compare with thousands separator */
 
5907
          for (j = 0; internalThousandSeparator[j] && self->current; j++)
 
5908
            {
 
5909
              if (internalThousandSeparator[j] != self->current)
 
5910
                break;
 
5911
 
 
5912
              self->InStream(self, &ch);
 
5913
            }
 
5914
          if (internalThousandSeparator[j])
 
5915
            break; /* Mismatch */
 
5916
          else
 
5917
            continue; /* Match */
 
5918
        }
 
5919
      else
 
5920
        break; /* while */
 
5921
    }
 
5922
  if (ch == '.')
 
5923
    {
 
5924
      /* Decimal part */
 
5925
      doubleString[index++] = (char)ch;
 
5926
      self->InStream(self, &ch);
 
5927
      while ((isHex ? isxdigit(ch) : isdigit(ch)) &&
 
5928
             (index - start < width))
 
5929
        {
 
5930
          doubleString[index++] = (char)ch;
 
5931
          self->InStream(self, &ch);
 
5932
        }
 
5933
      if (isHex ? (trio_to_upper(ch) == 'P') : (trio_to_upper(ch) == 'E'))
 
5934
        {
 
5935
          /* Exponent */
 
5936
          doubleString[index++] = (char)ch;
 
5937
          self->InStream(self, &ch);
 
5938
          if ((ch == '+') || (ch == '-'))
 
5939
            {
 
5940
              doubleString[index++] = (char)ch;
 
5941
              self->InStream(self, &ch);
 
5942
            }
 
5943
          while (isdigit(ch) && (index - start < width))
 
5944
            {
 
5945
              doubleString[index++] = (char)ch;
 
5946
              self->InStream(self, &ch);
 
5947
            }
 
5948
        }
 
5949
    }
 
5950
 
 
5951
  if ((index == start) || (*doubleString == NIL))
 
5952
    return FALSE;
 
5953
 
 
5954
  doubleString[index] = 0;
 
5955
  
 
5956
  if (flags & FLAGS_LONGDOUBLE)
 
5957
    {
 
5958
      *((trio_long_double_t *)target) = trio_to_long_double(doubleString, NULL);
 
5959
    }
 
5960
  else
 
5961
    {
 
5962
      *((double *)target) = trio_to_double(doubleString, NULL);
 
5963
    }
 
5964
  return TRUE;
 
5965
}
 
5966
 
 
5967
/*************************************************************************
 
5968
 * TrioReadPointer
 
5969
 */
 
5970
TRIO_PRIVATE BOOLEAN_T
 
5971
TrioReadPointer
 
5972
TRIO_ARGS3((self, target, flags),
 
5973
           trio_class_t *self,
 
5974
           trio_pointer_t *target,
 
5975
           trio_flags_t flags)
 
5976
{
 
5977
  trio_uintmax_t number;
 
5978
  char buffer[sizeof(internalNullString)];
 
5979
 
 
5980
  flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
 
5981
  
 
5982
  if (TrioReadNumber(self,
 
5983
                     &number,
 
5984
                     flags,
 
5985
                     POINTER_WIDTH,
 
5986
                     BASE_HEX))
 
5987
    {
 
5988
      /*
 
5989
       * The strange assignment of number is a workaround for a compiler
 
5990
       * warning
 
5991
       */
 
5992
      if (target)
 
5993
        *target = (char *)0 + number;
 
5994
      return TRUE;
 
5995
    }
 
5996
  else if (TrioReadString(self,
 
5997
                          (flags & FLAGS_IGNORE)
 
5998
                          ? NULL
 
5999
                          : buffer,
 
6000
                          0,
 
6001
                          sizeof(internalNullString) - 1))
 
6002
    {  
 
6003
      if (trio_equal_case(buffer, internalNullString))
 
6004
        {
 
6005
          if (target)
 
6006
            *target = NULL;
 
6007
          return TRUE;
 
6008
        }
 
6009
    }
 
6010
  return FALSE;
 
6011
}
 
6012
 
 
6013
/*************************************************************************
 
6014
 * TrioScanProcess
 
6015
 */
 
6016
TRIO_PRIVATE int
 
6017
TrioScanProcess
 
6018
TRIO_ARGS3((data, format, parameters),
 
6019
           trio_class_t *data,
 
6020
           TRIO_CONST char *format,
 
6021
           trio_parameter_t *parameters)
 
6022
{
 
6023
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
6024
  int charlen;
 
6025
  int cnt;
 
6026
#endif
 
6027
  int assignment;
 
6028
  int ch;
 
6029
  int index; /* Index of format string */
 
6030
  int i; /* Index of current parameter */
 
6031
  trio_flags_t flags;
 
6032
  int width;
 
6033
  int base;
 
6034
  trio_pointer_t pointer;
 
6035
 
 
6036
  assignment = 0;
 
6037
  i = 0;
 
6038
  index = 0;
 
6039
  data->InStream(data, &ch);
 
6040
 
 
6041
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
6042
  (void)mblen(NULL, 0);
 
6043
#endif
 
6044
 
 
6045
  while (format[index])
 
6046
    {
 
6047
#if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
 
6048
      if (! isascii(format[index]))
 
6049
        {
 
6050
          charlen = mblen(&format[index], MB_LEN_MAX);
 
6051
          if (charlen != -1)
 
6052
            {
 
6053
              /* Compare multibyte characters in format string */
 
6054
              for (cnt = 0; cnt < charlen - 1; cnt++)
 
6055
                {
 
6056
                  if (ch != format[index + cnt])
 
6057
                    {
 
6058
                      return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
6059
                    }
 
6060
                  data->InStream(data, &ch);
 
6061
                }
 
6062
              continue; /* while characters left in formatting string */
 
6063
            }
 
6064
        }
 
6065
#endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
 
6066
      
 
6067
      if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
 
6068
        {
 
6069
          return (assignment > 0) ? assignment : EOF;
 
6070
        }
 
6071
      
 
6072
      if (CHAR_IDENTIFIER == format[index])
 
6073
        {
 
6074
          if (CHAR_IDENTIFIER == format[index + 1])
 
6075
            {
 
6076
              /* Two % in format matches one % in input stream */
 
6077
              if (CHAR_IDENTIFIER == ch)
 
6078
                {
 
6079
                  data->InStream(data, &ch);
 
6080
                  index += 2;
 
6081
                  continue; /* while format chars left */
 
6082
                }
 
6083
              else
 
6084
                return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
6085
            }
 
6086
 
 
6087
          /* Skip the parameter entries */
 
6088
          while (parameters[i].type == FORMAT_PARAMETER)
 
6089
            i++;
 
6090
          
 
6091
          flags = parameters[i].flags;
 
6092
          /* Find width */
 
6093
          width = parameters[i].width;
 
6094
          if (flags & FLAGS_WIDTH_PARAMETER)
 
6095
            {
 
6096
              /* Get width from parameter list */
 
6097
              width = (int)parameters[width].data.number.as_signed;
 
6098
            }
 
6099
          /* Find base */
 
6100
          base = parameters[i].base;
 
6101
          if (flags & FLAGS_BASE_PARAMETER)
 
6102
            {
 
6103
              /* Get base from parameter list */
 
6104
              base = (int)parameters[base].data.number.as_signed;
 
6105
            }
 
6106
          
 
6107
          switch (parameters[i].type)
 
6108
            {
 
6109
            case FORMAT_INT:
 
6110
              {
 
6111
                trio_uintmax_t number;
 
6112
 
 
6113
                if (0 == base)
 
6114
                  base = BASE_DECIMAL;
 
6115
 
 
6116
                if (!TrioReadNumber(data,
 
6117
                                    &number,
 
6118
                                    flags,
 
6119
                                    width,
 
6120
                                    base))
 
6121
                  return assignment;
 
6122
 
 
6123
                if (!(flags & FLAGS_IGNORE))
 
6124
                  {
 
6125
                    assignment++;
 
6126
 
 
6127
                    pointer = parameters[i].data.pointer;
 
6128
#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 
6129
                    if (flags & FLAGS_SIZE_T)
 
6130
                      *(size_t *)pointer = (size_t)number;
 
6131
                    else
 
6132
#endif
 
6133
#if defined(QUALIFIER_PTRDIFF_T)
 
6134
                    if (flags & FLAGS_PTRDIFF_T)
 
6135
                      *(ptrdiff_t *)pointer = (ptrdiff_t)number;
 
6136
                    else
 
6137
#endif
 
6138
#if defined(QUALIFIER_INTMAX_T)
 
6139
                    if (flags & FLAGS_INTMAX_T)
 
6140
                      *(trio_intmax_t *)pointer = (trio_intmax_t)number;
 
6141
                    else
 
6142
#endif
 
6143
                    if (flags & FLAGS_QUAD)
 
6144
                      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
 
6145
                    else if (flags & FLAGS_LONG)
 
6146
                      *(long int *)pointer = (long int)number;
 
6147
                    else if (flags & FLAGS_SHORT)
 
6148
                      *(short int *)pointer = (short int)number;
 
6149
                    else
 
6150
                      *(int *)pointer = (int)number;
 
6151
                  }
 
6152
              }
 
6153
              break; /* FORMAT_INT */
 
6154
              
 
6155
            case FORMAT_STRING:
 
6156
#if TRIO_WIDECHAR
 
6157
              if (flags & FLAGS_WIDECHAR)
 
6158
                {
 
6159
                  if (!TrioReadWideString(data,
 
6160
                                          (flags & FLAGS_IGNORE)
 
6161
                                          ? NULL
 
6162
                                          : parameters[i].data.wstring,
 
6163
                                          flags,
 
6164
                                          width))
 
6165
                    return assignment;
 
6166
                }
 
6167
              else
 
6168
#endif
 
6169
                {
 
6170
                  if (!TrioReadString(data,
 
6171
                                      (flags & FLAGS_IGNORE)
 
6172
                                      ? NULL
 
6173
                                      : parameters[i].data.string,
 
6174
                                      flags,
 
6175
                                      width))
 
6176
                    return assignment;
 
6177
                }
 
6178
              if (!(flags & FLAGS_IGNORE))
 
6179
                assignment++;
 
6180
              break; /* FORMAT_STRING */
 
6181
 
 
6182
            case FORMAT_DOUBLE:
 
6183
              {
 
6184
                trio_pointer_t pointer;
 
6185
 
 
6186
                if (flags & FLAGS_IGNORE)
 
6187
                  {
 
6188
                    pointer = NULL;
 
6189
                  }
 
6190
                else
 
6191
                  {
 
6192
                    pointer = (flags & FLAGS_LONGDOUBLE)
 
6193
                      ? (trio_pointer_t)parameters[i].data.longdoublePointer
 
6194
                      : (trio_pointer_t)parameters[i].data.doublePointer;
 
6195
                  }
 
6196
                if (!TrioReadDouble(data, pointer, flags, width))
 
6197
                  {
 
6198
                    return assignment;
 
6199
                  }
 
6200
                if (!(flags & FLAGS_IGNORE))
 
6201
                  {
 
6202
                    assignment++;
 
6203
                  }
 
6204
                break; /* FORMAT_DOUBLE */
 
6205
              }
 
6206
            case FORMAT_GROUP:
 
6207
              {
 
6208
                int characterclass[MAX_CHARACTER_CLASS + 1];
 
6209
                int rc;
 
6210
 
 
6211
                /* Skip over modifiers */
 
6212
                while (format[index] != SPECIFIER_GROUP)
 
6213
                  {
 
6214
                    index++;
 
6215
                  }
 
6216
                /* Skip over group specifier */
 
6217
                index++;
 
6218
                
 
6219
                memset(characterclass, 0, sizeof(characterclass));
 
6220
                rc = TrioGetCharacterClass(format,
 
6221
                                           &index,
 
6222
                                           &flags,
 
6223
                                           characterclass);
 
6224
                if (rc < 0)
 
6225
                  return rc;
 
6226
 
 
6227
                if (!TrioReadGroup(data,
 
6228
                                   (flags & FLAGS_IGNORE)
 
6229
                                   ? NULL
 
6230
                                   : parameters[i].data.string,
 
6231
                                   characterclass,
 
6232
                                   flags,
 
6233
                                   parameters[i].width))
 
6234
                  return assignment;
 
6235
                if (!(flags & FLAGS_IGNORE))
 
6236
                  assignment++;
 
6237
              }
 
6238
              break; /* FORMAT_GROUP */
 
6239
 
 
6240
            case FORMAT_COUNT:
 
6241
              pointer = parameters[i].data.pointer;
 
6242
              if (NULL != pointer)
 
6243
                {
 
6244
                  int count = data->committed;
 
6245
                  if (ch != EOF)
 
6246
                    count--; /* a character is read, but is not consumed yet */
 
6247
#if defined(QUALIFIER_SIZE_T) || defined(QUALIFIER_SIZE_T_UPPER)
 
6248
                  if (flags & FLAGS_SIZE_T)
 
6249
                    *(size_t *)pointer = (size_t)count;
 
6250
                  else
 
6251
#endif
 
6252
#if defined(QUALIFIER_PTRDIFF_T)
 
6253
                  if (flags & FLAGS_PTRDIFF_T)
 
6254
                    *(ptrdiff_t *)pointer = (ptrdiff_t)count;
 
6255
                  else
 
6256
#endif
 
6257
#if defined(QUALIFIER_INTMAX_T)
 
6258
                  if (flags & FLAGS_INTMAX_T)
 
6259
                    *(trio_intmax_t *)pointer = (trio_intmax_t)count;
 
6260
                  else
 
6261
#endif
 
6262
                  if (flags & FLAGS_QUAD)
 
6263
                    {
 
6264
                      *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
 
6265
                    }
 
6266
                  else if (flags & FLAGS_LONG)
 
6267
                    {
 
6268
                      *(long int *)pointer = (long int)count;
 
6269
                    }
 
6270
                  else if (flags & FLAGS_SHORT)
 
6271
                    {
 
6272
                      *(short int *)pointer = (short int)count;
 
6273
                    }
 
6274
                  else
 
6275
                    {
 
6276
                      *(int *)pointer = (int)count;
 
6277
                    }
 
6278
                }
 
6279
              break; /* FORMAT_COUNT */
 
6280
              
 
6281
            case FORMAT_CHAR:
 
6282
#if TRIO_WIDECHAR
 
6283
              if (flags & FLAGS_WIDECHAR)
 
6284
                {
 
6285
                  if (TrioReadWideChar(data,
 
6286
                                       (flags & FLAGS_IGNORE)
 
6287
                                       ? NULL
 
6288
                                       : parameters[i].data.wstring,
 
6289
                                       flags,
 
6290
                                       (width == NO_WIDTH) ? 1 : width) == 0)
 
6291
                    return assignment;
 
6292
                }
 
6293
              else
 
6294
#endif
 
6295
                {
 
6296
                  if (TrioReadChar(data,
 
6297
                                   (flags & FLAGS_IGNORE)
 
6298
                                   ? NULL
 
6299
                                   : parameters[i].data.string,
 
6300
                                   flags,
 
6301
                                   (width == NO_WIDTH) ? 1 : width) == 0)
 
6302
                    return assignment;
 
6303
                }
 
6304
              if (!(flags & FLAGS_IGNORE))
 
6305
                assignment++;
 
6306
              break; /* FORMAT_CHAR */
 
6307
 
 
6308
            case FORMAT_POINTER:
 
6309
              if (!TrioReadPointer(data,
 
6310
                                   (flags & FLAGS_IGNORE)
 
6311
                                   ? NULL
 
6312
                                   : (trio_pointer_t *)parameters[i].data.pointer,
 
6313
                                   flags))
 
6314
                return assignment;
 
6315
              if (!(flags & FLAGS_IGNORE))
 
6316
                assignment++;
 
6317
              break; /* FORMAT_POINTER */
 
6318
 
 
6319
            case FORMAT_PARAMETER:
 
6320
              break; /* FORMAT_PARAMETER */
 
6321
 
 
6322
            default:
 
6323
              return TRIO_ERROR_RETURN(TRIO_EINVAL, index);
 
6324
            }
 
6325
          ch = data->current;
 
6326
          index = parameters[i].indexAfterSpecifier;
 
6327
          i++;
 
6328
        }
 
6329
      else /* Not an % identifier */
 
6330
        {
 
6331
          if (isspace((int)format[index]))
 
6332
            {
 
6333
              /* Whitespaces may match any amount of whitespaces */
 
6334
              ch = TrioSkipWhitespaces(data);
 
6335
            }
 
6336
          else if (ch == format[index])
 
6337
            {
 
6338
              data->InStream(data, &ch);
 
6339
            }
 
6340
          else
 
6341
            return assignment;
 
6342
          
 
6343
          index++;
 
6344
        }
 
6345
    }
 
6346
  return assignment;
 
6347
}
 
6348
 
 
6349
/*************************************************************************
 
6350
 * TrioScan
 
6351
 */
 
6352
TRIO_PRIVATE int
 
6353
TrioScan
 
6354
TRIO_ARGS6((source, sourceSize, InStream, format, arglist, argarray),
 
6355
           trio_pointer_t source,
 
6356
           size_t sourceSize,
 
6357
           void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
 
6358
           TRIO_CONST char *format,
 
6359
           va_list *arglist,
 
6360
           trio_pointer_t *argarray)
 
6361
{
 
6362
  int status;
 
6363
  trio_parameter_t parameters[MAX_PARAMETERS];
 
6364
  trio_class_t data;
 
6365
 
 
6366
  assert(VALID(InStream));
 
6367
  assert(VALID(format));
 
6368
 
 
6369
  memset(&data, 0, sizeof(data));
 
6370
  data.InStream = InStream;
 
6371
  data.location = (trio_pointer_t)source;
 
6372
  data.max = sourceSize;
 
6373
  data.error = 0;
 
6374
 
 
6375
#if defined(USE_LOCALE)
 
6376
  if (NULL == internalLocaleValues)
 
6377
    {
 
6378
      TrioSetLocale();
 
6379
    }
 
6380
#endif
 
6381
  
 
6382
  status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
 
6383
  if (status < 0)
 
6384
    return status;
 
6385
 
 
6386
  status = TrioScanProcess(&data, format, parameters);
 
6387
  if (data.error != 0)
 
6388
    {
 
6389
      status = data.error;
 
6390
    }
 
6391
  return status;
 
6392
}
 
6393
 
 
6394
/*************************************************************************
 
6395
 * TrioInStreamFile
 
6396
 */
 
6397
TRIO_PRIVATE void
 
6398
TrioInStreamFile
 
6399
TRIO_ARGS2((self, intPointer),
 
6400
           trio_class_t *self,
 
6401
           int *intPointer)
 
6402
{
 
6403
  FILE *file = (FILE *)self->location;
 
6404
 
 
6405
  assert(VALID(self));
 
6406
  assert(VALID(file));
 
6407
 
 
6408
  self->current = fgetc(file);
 
6409
  if (self->current == EOF)
 
6410
    {
 
6411
      self->error = (ferror(file))
 
6412
        ? TRIO_ERROR_RETURN(TRIO_ERRNO, 0)
 
6413
        : TRIO_ERROR_RETURN(TRIO_EOF, 0);
 
6414
    }
 
6415
  else
 
6416
    {
 
6417
      self->processed++;
 
6418
      self->committed++;
 
6419
    }
 
6420
  
 
6421
  if (VALID(intPointer))
 
6422
    {
 
6423
      *intPointer = self->current;
 
6424
    }
 
6425
}
 
6426
 
 
6427
/*************************************************************************
 
6428
 * TrioInStreamFileDescriptor
 
6429
 */
 
6430
TRIO_PRIVATE void
 
6431
TrioInStreamFileDescriptor
 
6432
TRIO_ARGS2((self, intPointer),
 
6433
           trio_class_t *self,
 
6434
           int *intPointer)
 
6435
{
 
6436
  int fd = *((int *)self->location);
 
6437
  int size;
 
6438
  unsigned char input;
 
6439
 
 
6440
  assert(VALID(self));
 
6441
 
 
6442
  size = read(fd, &input, sizeof(char));
 
6443
  if (size == -1)
 
6444
    {
 
6445
      self->error = TRIO_ERROR_RETURN(TRIO_ERRNO, 0);
 
6446
      self->current = EOF;
 
6447
    }
 
6448
  else
 
6449
    {
 
6450
      self->current = (size == 0) ? EOF : input;
 
6451
    }
 
6452
  if (self->current != EOF)
 
6453
    {
 
6454
      self->committed++;
 
6455
      self->processed++;
 
6456
    }
 
6457
  
 
6458
  if (VALID(intPointer))
 
6459
    {
 
6460
      *intPointer = self->current;
 
6461
    }
 
6462
}
 
6463
 
 
6464
/*************************************************************************
 
6465
 * TrioInStreamCustom
 
6466
 */
 
6467
TRIO_PRIVATE void
 
6468
TrioInStreamCustom
 
6469
TRIO_ARGS2((self, intPointer),
 
6470
           trio_class_t *self,
 
6471
           int *intPointer)
 
6472
{
 
6473
  trio_custom_t *data;
 
6474
  
 
6475
  assert(VALID(self));
 
6476
  assert(VALID(self->location));
 
6477
 
 
6478
  data = (trio_custom_t *)self->location;
 
6479
 
 
6480
  self->current = (data->stream.in == NULL)
 
6481
    ? NIL
 
6482
    : (data->stream.in)(data->closure);
 
6483
  
 
6484
  if (self->current == NIL)
 
6485
    {
 
6486
      self->current = EOF;
 
6487
    }
 
6488
  else
 
6489
    {
 
6490
      self->processed++;
 
6491
      self->committed++;
 
6492
    }
 
6493
  
 
6494
  if (VALID(intPointer))
 
6495
    {
 
6496
      *intPointer = self->current;
 
6497
    }
 
6498
}
 
6499
 
 
6500
/*************************************************************************
 
6501
 * TrioInStreamString
 
6502
 */
 
6503
TRIO_PRIVATE void
 
6504
TrioInStreamString
 
6505
TRIO_ARGS2((self, intPointer),
 
6506
           trio_class_t *self,
 
6507
           int *intPointer)
 
6508
{
 
6509
  unsigned char **buffer;
 
6510
 
 
6511
  assert(VALID(self));
 
6512
  assert(VALID(self->location));
 
6513
 
 
6514
  buffer = (unsigned char **)self->location;
 
6515
  self->current = (*buffer)[0];
 
6516
  if (self->current == NIL)
 
6517
    {
 
6518
      self->current = EOF;
 
6519
    }
 
6520
  else
 
6521
    {
 
6522
      (*buffer)++;
 
6523
      self->processed++;
 
6524
      self->committed++;
 
6525
    }
 
6526
  
 
6527
  if (VALID(intPointer))
 
6528
    {
 
6529
      *intPointer = self->current;
 
6530
    }
 
6531
}
 
6532
 
 
6533
/*************************************************************************
 
6534
 *
 
6535
 * Formatted scanning functions
 
6536
 *
 
6537
 ************************************************************************/
 
6538
 
 
6539
#if defined(TRIO_DOCUMENTATION)
 
6540
# include "doc/doc_scanf.h"
 
6541
#endif
 
6542
/** @addtogroup Scanf
 
6543
    @{
 
6544
*/
 
6545
 
 
6546
/*************************************************************************
 
6547
 * scanf
 
6548
 */
 
6549
 
 
6550
/**
 
6551
   Scan characters from standard input stream.
 
6552
 
 
6553
   @param format Formatting string.
 
6554
   @param ... Arguments.
 
6555
   @return Number of scanned characters.
 
6556
 */
 
6557
TRIO_PUBLIC int
 
6558
trio_scanf
 
6559
TRIO_VARGS2((format, va_alist),
 
6560
            TRIO_CONST char *format,
 
6561
            TRIO_VA_DECL)
 
6562
{
 
6563
  int status;
 
6564
  va_list args;
 
6565
 
 
6566
  assert(VALID(format));
 
6567
  
 
6568
  TRIO_VA_START(args, format);
 
6569
  status = TrioScan((trio_pointer_t)stdin, 0,
 
6570
                    TrioInStreamFile,
 
6571
                    format, &args, NULL);
 
6572
  TRIO_VA_END(args);
 
6573
  return status;
 
6574
}
 
6575
 
 
6576
TRIO_PUBLIC int
 
6577
trio_vscanf
 
6578
TRIO_ARGS2((format, args),
 
6579
           TRIO_CONST char *format,
 
6580
           va_list args)
 
6581
{
 
6582
  assert(VALID(format));
 
6583
  
 
6584
  return TrioScan((trio_pointer_t)stdin, 0,
 
6585
                  TrioInStreamFile,
 
6586
                  format, &args, NULL);
 
6587
}
 
6588
 
 
6589
TRIO_PUBLIC int
 
6590
trio_scanfv
 
6591
TRIO_ARGS2((format, args),
 
6592
           TRIO_CONST char *format,
 
6593
           trio_pointer_t *args)
 
6594
{
 
6595
  assert(VALID(format));
 
6596
  
 
6597
  return TrioScan((trio_pointer_t)stdin, 0,
 
6598
                  TrioInStreamFile,
 
6599
                  format, NULL, args);
 
6600
}
 
6601
 
 
6602
/*************************************************************************
 
6603
 * fscanf
 
6604
 */
 
6605
TRIO_PUBLIC int
 
6606
trio_fscanf
 
6607
TRIO_VARGS3((file, format, va_alist),
 
6608
            FILE *file,
 
6609
            TRIO_CONST char *format,
 
6610
            TRIO_VA_DECL)
 
6611
{
 
6612
  int status;
 
6613
  va_list args;
 
6614
 
 
6615
  assert(VALID(file));
 
6616
  assert(VALID(format));
 
6617
  
 
6618
  TRIO_VA_START(args, format);
 
6619
  status = TrioScan((trio_pointer_t)file, 0,
 
6620
                    TrioInStreamFile,
 
6621
                    format, &args, NULL);
 
6622
  TRIO_VA_END(args);
 
6623
  return status;
 
6624
}
 
6625
 
 
6626
TRIO_PUBLIC int
 
6627
trio_vfscanf
 
6628
TRIO_ARGS3((file, format, args),
 
6629
           FILE *file,
 
6630
           TRIO_CONST char *format,
 
6631
           va_list args)
 
6632
{
 
6633
  assert(VALID(file));
 
6634
  assert(VALID(format));
 
6635
  
 
6636
  return TrioScan((trio_pointer_t)file, 0,
 
6637
                  TrioInStreamFile,
 
6638
                  format, &args, NULL);
 
6639
}
 
6640
 
 
6641
TRIO_PUBLIC int
 
6642
trio_fscanfv
 
6643
TRIO_ARGS3((file, format, args),
 
6644
           FILE *file,
 
6645
           TRIO_CONST char *format,
 
6646
           trio_pointer_t *args)
 
6647
{
 
6648
  assert(VALID(file));
 
6649
  assert(VALID(format));
 
6650
  
 
6651
  return TrioScan((trio_pointer_t)file, 0,
 
6652
                  TrioInStreamFile,
 
6653
                  format, NULL, args);
 
6654
}
 
6655
 
 
6656
/*************************************************************************
 
6657
 * dscanf
 
6658
 */
 
6659
TRIO_PUBLIC int
 
6660
trio_dscanf
 
6661
TRIO_VARGS3((fd, format, va_alist),
 
6662
            int fd,
 
6663
            TRIO_CONST char *format,
 
6664
            TRIO_VA_DECL)
 
6665
{
 
6666
  int status;
 
6667
  va_list args;
 
6668
 
 
6669
  assert(VALID(format));
 
6670
  
 
6671
  TRIO_VA_START(args, format);
 
6672
  status = TrioScan((trio_pointer_t)&fd, 0,
 
6673
                    TrioInStreamFileDescriptor,
 
6674
                    format, &args, NULL);
 
6675
  TRIO_VA_END(args);
 
6676
  return status;
 
6677
}
 
6678
 
 
6679
TRIO_PUBLIC int
 
6680
trio_vdscanf
 
6681
TRIO_ARGS3((fd, format, args),
 
6682
           int fd,
 
6683
           TRIO_CONST char *format,
 
6684
           va_list args)
 
6685
{
 
6686
  assert(VALID(format));
 
6687
  
 
6688
  return TrioScan((trio_pointer_t)&fd, 0,
 
6689
                  TrioInStreamFileDescriptor,
 
6690
                  format, &args, NULL);
 
6691
}
 
6692
 
 
6693
TRIO_PUBLIC int
 
6694
trio_dscanfv
 
6695
TRIO_ARGS3((fd, format, args),
 
6696
           int fd,
 
6697
           TRIO_CONST char *format,
 
6698
           trio_pointer_t *args)
 
6699
{
 
6700
  assert(VALID(format));
 
6701
  
 
6702
  return TrioScan((trio_pointer_t)&fd, 0,
 
6703
                  TrioInStreamFileDescriptor,
 
6704
                  format, NULL, args);
 
6705
}
 
6706
 
 
6707
/*************************************************************************
 
6708
 * cscanf
 
6709
 */
 
6710
TRIO_PUBLIC int
 
6711
trio_cscanf
 
6712
TRIO_VARGS4((stream, closure, format, va_alist),
 
6713
            trio_instream_t stream,
 
6714
            trio_pointer_t closure,
 
6715
            TRIO_CONST char *format,
 
6716
            TRIO_VA_DECL)
 
6717
{
 
6718
  int status;
 
6719
  va_list args;
 
6720
  trio_custom_t data;
 
6721
 
 
6722
  assert(VALID(stream));
 
6723
  assert(VALID(format));
 
6724
  
 
6725
  TRIO_VA_START(args, format);
 
6726
  data.stream.in = stream;
 
6727
  data.closure = closure;
 
6728
  status = TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
 
6729
  TRIO_VA_END(args);
 
6730
  return status;
 
6731
}
 
6732
 
 
6733
TRIO_PUBLIC int
 
6734
trio_vcscanf
 
6735
TRIO_ARGS4((stream, closure, format, args),
 
6736
           trio_instream_t stream,
 
6737
           trio_pointer_t closure,
 
6738
           TRIO_CONST char *format,
 
6739
           va_list args)
 
6740
{
 
6741
  trio_custom_t data;
 
6742
  
 
6743
  assert(VALID(stream));
 
6744
  assert(VALID(format));
 
6745
 
 
6746
  data.stream.in = stream;
 
6747
  data.closure = closure;
 
6748
  return TrioScan(&data, 0, TrioInStreamCustom, format, &args, NULL);
 
6749
}
 
6750
 
 
6751
TRIO_PUBLIC int
 
6752
trio_cscanfv
 
6753
TRIO_ARGS4((stream, closure, format, args),
 
6754
           trio_instream_t stream,
 
6755
           trio_pointer_t closure,
 
6756
           TRIO_CONST char *format,
 
6757
           trio_pointer_t *args)
 
6758
{
 
6759
  trio_custom_t data;
 
6760
  
 
6761
  assert(VALID(stream));
 
6762
  assert(VALID(format));
 
6763
 
 
6764
  data.stream.in = stream;
 
6765
  data.closure = closure;
 
6766
  return TrioScan(&data, 0, TrioInStreamCustom, format, NULL, args);
 
6767
}
 
6768
 
 
6769
/*************************************************************************
 
6770
 * sscanf
 
6771
 */
 
6772
TRIO_PUBLIC int
 
6773
trio_sscanf
 
6774
TRIO_VARGS3((buffer, format, va_alist),
 
6775
            TRIO_CONST char *buffer,
 
6776
            TRIO_CONST char *format,
 
6777
            TRIO_VA_DECL)
 
6778
{
 
6779
  int status;
 
6780
  va_list args;
 
6781
 
 
6782
  assert(VALID(buffer));
 
6783
  assert(VALID(format));
 
6784
  
 
6785
  TRIO_VA_START(args, format);
 
6786
  status = TrioScan((trio_pointer_t)&buffer, 0,
 
6787
                    TrioInStreamString,
 
6788
                    format, &args, NULL);
 
6789
  TRIO_VA_END(args);
 
6790
  return status;
 
6791
}
 
6792
 
 
6793
TRIO_PUBLIC int
 
6794
trio_vsscanf
 
6795
TRIO_ARGS3((buffer, format, args),
 
6796
           TRIO_CONST char *buffer,
 
6797
           TRIO_CONST char *format,
 
6798
           va_list args)
 
6799
{
 
6800
  assert(VALID(buffer));
 
6801
  assert(VALID(format));
 
6802
  
 
6803
  return TrioScan((trio_pointer_t)&buffer, 0,
 
6804
                  TrioInStreamString,
 
6805
                  format, &args, NULL);
 
6806
}
 
6807
 
 
6808
TRIO_PUBLIC int
 
6809
trio_sscanfv
 
6810
TRIO_ARGS3((buffer, format, args),
 
6811
           TRIO_CONST char *buffer,
 
6812
           TRIO_CONST char *format,
 
6813
           trio_pointer_t *args)
 
6814
{
 
6815
  assert(VALID(buffer));
 
6816
  assert(VALID(format));
 
6817
  
 
6818
  return TrioScan((trio_pointer_t)&buffer, 0,
 
6819
                  TrioInStreamString,
 
6820
                  format, NULL, args);
 
6821
}
 
6822
 
 
6823
/** @} End of Scanf documentation module */
 
6824
 
 
6825
/*************************************************************************
 
6826
 * trio_strerror
 
6827
 */
 
6828
TRIO_PUBLIC TRIO_CONST char *
 
6829
trio_strerror
 
6830
TRIO_ARGS1((errorcode),
 
6831
           int errorcode)
 
6832
{
 
6833
  /* Textual versions of the error codes */
 
6834
  switch (TRIO_ERROR_CODE(errorcode))
 
6835
    {
 
6836
    case TRIO_EOF:
 
6837
      return "End of file";
 
6838
    case TRIO_EINVAL:
 
6839
      return "Invalid argument";
 
6840
    case TRIO_ETOOMANY:
 
6841
      return "Too many arguments";
 
6842
    case TRIO_EDBLREF:
 
6843
      return "Double reference";
 
6844
    case TRIO_EGAP:
 
6845
      return "Reference gap";
 
6846
    case TRIO_ENOMEM:
 
6847
      return "Out of memory";
 
6848
    case TRIO_ERANGE:
 
6849
      return "Invalid range";
 
6850
    case TRIO_ECUSTOM:
 
6851
      return "Custom error";
 
6852
    default:
 
6853
      return "Unknown";
 
6854
    }
 
6855
}