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