source: libcfa/src/iostream.cfa@ 73d0a84c

Last change on this file since 73d0a84c was 2fa0237, checked in by Michael Brooks <mlbrooks@…>, 2 years ago

Fix cstring input length interpretation issue that had a buffer overflow case.

The cases added to the manipulatorsInput test are runnable against an old libcfa build. In this setup, the test fails with an illustration of the bug.

The testing in this commit drives the following inputs through a length-8 buffer.

  • 123456
  • 123456789

The obviously-missing cases, like 1234567, will be added later.
They will accompany fixes for further bugs not solved yet.

  • Property mode set to 100644
File size: 37.7 KB
Line 
1
2//
3// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
4//
5// The contents of this file are covered under the licence agreement in the
6// file "LICENCE" distributed with Cforall.
7//
8// iostream.cfa --
9//
10// Author : Peter A. Buhr
11// Created On : Wed May 27 17:56:53 2015
12// Last Modified By : Peter A. Buhr
13// Last Modified On : Sat Sep 2 14:42:01 2023
14// Update Count : 1561
15//
16
17#include "iostream.hfa"
18
19#include <stdio.h>
20#include <stdbool.h> // true/false
21#include <stdint.h> // UINT64_MAX
22#include <float.h> // DBL_DIG, LDBL_DIG
23#include <complex.h> // creal, cimag
24//#include <stdio.h>
25
26extern "C" {
27extern size_t strlen (const char *__s) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1)));
28extern int strcmp (const char *__s1, const char *__s2) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__pure__)) __attribute__ ((__nonnull__ (1, 2)));
29extern char *strcpy (char *__restrict __dest, const char *__restrict __src) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
30extern void *memcpy (void *__restrict __dest, const void *__restrict __src, size_t __n) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1, 2)));
31} // extern "C"
32
33#include "math.hfa" // isfinite, floor, ceiling_div
34#include "bitmanip.hfa" // high1
35
36#pragma GCC visibility push(default)
37
38
39// *********************************** ostream ***********************************
40
41
42forall( ostype & | basic_ostream( ostype ) ) {
43 ostype & ?|?( ostype & os, bool b ) {
44 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
45 fmt( os, "%s", b ? "true" : "false" );
46 return os;
47 } // ?|?
48 OSTYPE_VOID_IMPL( bool )
49
50 ostype & ?|?( ostype & os, char c ) {
51 fmt( os, "%c", c );
52 if ( c == '\n' ) setNL$( os, true );
53 return nosep( os );
54 } // ?|?
55 OSTYPE_VOID_IMPL( char )
56
57 ostype & ?|?( ostype & os, signed char sc ) {
58 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
59 fmt( os, "%'hhd", sc );
60 return os;
61 } // ?|?
62 OSTYPE_VOID_IMPL( signed char )
63
64 ostype & ?|?( ostype & os, unsigned char usc ) {
65 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
66 fmt( os, "%'hhu", usc );
67 return os;
68 } // ?|?
69 OSTYPE_VOID_IMPL( unsigned char )
70
71 ostype & ?|?( ostype & os, short int si ) {
72 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
73 fmt( os, "%'hd", si );
74 return os;
75 } // ?|?
76 OSTYPE_VOID_IMPL( short int )
77
78 ostype & ?|?( ostype & os, unsigned short int usi ) {
79 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
80 fmt( os, "%'hu", usi );
81 return os;
82 } // ?|?
83 OSTYPE_VOID_IMPL( unsigned short int )
84
85 ostype & ?|?( ostype & os, int i ) {
86 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
87 fmt( os, "%'d", i );
88 return os;
89 } // ?|?
90 OSTYPE_VOID_IMPL( int )
91
92 ostype & ?|?( ostype & os, unsigned int ui ) {
93 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
94 fmt( os, "%'u", ui );
95 return os;
96 } // ?|?
97 OSTYPE_VOID_IMPL( unsigned int )
98
99 ostype & ?|?( ostype & os, long int li ) {
100 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
101 fmt( os, "%'ld", li );
102 return os;
103 } // ?|?
104 OSTYPE_VOID_IMPL( long int )
105
106 ostype & ?|?( ostype & os, unsigned long int uli ) {
107 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
108 fmt( os, "%'lu", uli );
109 return os;
110 } // ?|?
111 OSTYPE_VOID_IMPL( unsigned long int )
112
113 ostype & ?|?( ostype & os, long long int lli ) {
114 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
115 fmt( os, "%'lld", lli );
116 return os;
117 } // ?|?
118 OSTYPE_VOID_IMPL( long long int )
119
120 ostype & ?|?( ostype & os, unsigned long long int ulli ) {
121 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
122 fmt( os, "%'llu", ulli );
123 return os;
124 } // ?|?
125 OSTYPE_VOID_IMPL( unsigned long long int )
126
127 #if defined( __SIZEOF_INT128__ )
128 // UINT64_MAX 18_446_744_073_709_551_615_ULL
129 #define P10_UINT64 10_000_000_000_000_000_000_ULL // 19 zeroes
130
131 static inline void base10_128( ostype & os, unsigned int128 val ) {
132 #if defined(__GNUC__) && __GNUC_PREREQ(7,0) // gcc version >= 7
133 if ( val > P10_UINT64 ) {
134 #else
135 if ( (uint64_t)(val >> 64) != 0 || (uint64_t)val > P10_UINT64 ) { // patch gcc 5 & 6 -O3 bug
136 #endif // __GNUC_PREREQ(7,0)
137 base10_128( os, val / P10_UINT64 ); // recursive
138 fmt( os, "%.19lu", (uint64_t)(val % P10_UINT64) );
139 } else {
140 fmt( os, "%lu", (uint64_t)val );
141 } // if
142 } // base10_128
143
144 static inline void base10_128( ostype & os, int128 val ) {
145 if ( val < 0 ) {
146 fmt( os, "-" ); // leading negative sign
147 val = -val;
148 } // if
149 base10_128( os, (unsigned int128)val ); // print zero/positive value
150 } // base10_128
151
152 ostype & ?|?( ostype & os, int128 llli ) {
153 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
154 base10_128( os, llli );
155 return os;
156 } // ?|?
157 OSTYPE_VOID_IMPL( int128 )
158
159 ostype & ?|?( ostype & os, unsigned int128 ullli ) {
160 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
161 base10_128( os, ullli );
162 return os;
163 } // ?|?
164 OSTYPE_VOID_IMPL( unsigned int128 )
165 #endif // __SIZEOF_INT128__
166
167 #define PRINT_WITH_DP( os, format, val, ... ) \
168 { \
169 enum { size = 48 }; \
170 char buf[size]; \
171 int len = snprintf( buf, size, format, ##__VA_ARGS__, val ); \
172 fmt( os, "%s", buf ); \
173 if ( isfinite( val ) ) { /* if number, print decimal point when no fraction or exponent */ \
174 for ( i; 0 ~ @ ) { \
175 if ( i == len ) { fmt( os, "." ); break; } \
176 if ( buf[i] == '.' || buf[i] == 'e' || buf[i] == 'E' || \
177 buf[i] == 'p' || buf[i] == 'P' ) break; /* decimal point or scientific ? */ \
178 } /* for */ \
179 } /* if */ \
180 }
181
182 ostype & ?|?( ostype & os, float f ) {
183 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
184 PRINT_WITH_DP( os, "%'g", f );
185 return os;
186 } // ?|?
187 OSTYPE_VOID_IMPL( float )
188
189 ostype & ?|?( ostype & os, double d ) {
190 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
191 PRINT_WITH_DP( os, "%'.*lg", d, DBL_DIG );
192 return os;
193 } // ?|?
194 OSTYPE_VOID_IMPL( double )
195
196 ostype & ?|?( ostype & os, long double ld ) {
197 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
198 PRINT_WITH_DP( os, "%'.*Lg", ld, LDBL_DIG );
199 return os;
200 } // ?|?
201 OSTYPE_VOID_IMPL( long double )
202
203 ostype & ?|?( ostype & os, float _Complex fc ) {
204 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
205// os | crealf( fc ) | nonl;
206 PRINT_WITH_DP( os, "%'g", crealf( fc ) );
207 PRINT_WITH_DP( os, "%'+g", cimagf( fc ) );
208 fmt( os, "i" );
209 return os;
210 } // ?|?
211 OSTYPE_VOID_IMPL( float _Complex )
212
213 ostype & ?|?( ostype & os, double _Complex dc ) {
214 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
215// os | creal( dc ) | nonl;
216 PRINT_WITH_DP( os, "%'.*lg", creal( dc ), DBL_DIG );
217 PRINT_WITH_DP( os, "%'+.*lg", cimag( dc ), DBL_DIG );
218 fmt( os, "i" );
219 return os;
220 } // ?|?
221 OSTYPE_VOID_IMPL( double _Complex )
222
223 ostype & ?|?( ostype & os, long double _Complex ldc ) {
224 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
225// os | creall( ldc ) || nonl;
226 PRINT_WITH_DP( os, "%'.*Lg", creall( ldc ), LDBL_DIG );
227 PRINT_WITH_DP( os, "%'+.*Lg", cimagl( ldc ), LDBL_DIG );
228 fmt( os, "i" );
229 return os;
230 } // ?|?
231 OSTYPE_VOID_IMPL( long double _Complex )
232
233 ostype & ?|?( ostype & os, const char s[] ) {
234 enum { Open = 1, Close, OpenClose };
235 static const unsigned char mask[256] @= { // 256 covers all Latin-1 characters
236 // opening delimiters, no space after
237 ['('] : Open, ['['] : Open, ['{'] : Open,
238 ['='] : Open, ['$'] : Open, [(unsigned char)'£'] : Open, [(unsigned char)'¥'] : Open,
239 [(unsigned char)'¡'] : Open, [(unsigned char)'¿'] : Open, [(unsigned char)'«'] : Open,
240 // closing delimiters, no space before
241 [','] : Close, ['.'] : Close, [';'] : Close, ['!'] : Close, ['?'] : Close,
242 ['%'] : Close, [(unsigned char)'¢'] : Close, [(unsigned char)'»'] : Close,
243 [')'] : Close, [']'] : Close, ['}'] : Close,
244 // opening-closing delimiters, no space before or after
245 ['\''] : OpenClose, ['`'] : OpenClose, ['"'] : OpenClose, [':'] : OpenClose,
246 [' '] : OpenClose, ['\f'] : OpenClose, ['\n'] : OpenClose, ['\r'] : OpenClose, ['\t'] : OpenClose, ['\v'] : OpenClose, // isspace
247 }; // mask
248
249 if ( s == 0p ) { fmt( os, "%s", "0p" ); return os; } // null pointer
250 if ( s[0] == '\0' ) { nosep( os ); return os; } // null string => no leading/trailing separator
251
252 // first character IS NOT spacing or closing punctuation => add left separator
253 unsigned char ch = s[0]; // must make unsigned
254 if ( sepPrt$( os ) && mask[ ch ] != Close && mask[ ch ] != OpenClose ) {
255 fmt( os, "%s", sepGetCur$( os ) );
256 } // if
257
258 // if string starts line, must reset to determine open state because separator is off
259 sepReset$( os ); // reset separator
260
261 // last character IS spacing or opening punctuation => turn off separator for next item
262 int len = strlen( s );
263 ch = s[len - 1]; // must make unsigned
264 fmt( os, "%s", s ); // fmt resets seperator, but reset it again
265 if ( sepPrt$( os ) && mask[ ch ] != Open && mask[ ch ] != OpenClose ) {
266 sep( os );
267 } else {
268 nosep( os );
269 } // if
270 if ( ch == '\n' ) setNL$( os, true ); // check *AFTER* sepPrt$ call above as it resets NL flag
271 return os;
272// return write( os, s, len );
273 } // ?|?
274 OSTYPE_VOID_IMPL( const char * )
275
276// ostype & ?|?( ostype & os, const char16_t s[] ) {
277// if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
278// fmt( os, "%ls", s );
279// return os;
280// } // ?|?
281
282// #if ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 ) // char32_t == wchar_t => ambiguous
283// ostype & ?|?( ostype & os, const char32_t s[] ) {
284// if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
285// fmt( os, "%ls", s );
286// return os;
287// } // ?|?
288// #endif // ! ( __ARM_ARCH_ISA_ARM == 1 && __ARM_32BIT_STATE == 1 )
289
290// ostype & ?|?( ostype & os, const wchar_t s[] ) {
291// if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
292// fmt( os, "%ls", s );
293// return os;
294// } // ?|?
295
296 ostype & ?|?( ostype & os, const void * p ) {
297 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
298 fmt( os, "%p", p );
299 return os;
300 } // ?|?
301 OSTYPE_VOID_IMPL( const void * )
302
303 // manipulators
304 ostype & ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
305 return manip( os );
306 } // ?|?
307 void ?|?( ostype & os, ostype & (* manip)( ostype & ) ) {
308 manip( os );
309 if ( getPrt$( os ) ) ends( os ); // something printed ?
310 setPrt$( os, false ); // turn off
311 } // ?|?
312
313 ostype & nl( ostype & os ) {
314 (ostype &)(os | '\n');
315 setPrt$( os, false ); // turn off
316 setNL$( os, true );
317 return nosep( os ); // prepare for next line
318 } // nl
319
320 ostype & nonl( ostype & os ) {
321 setPrt$( os, false ); // turn off
322 return os;
323 } // nonl
324
325 ostype & nlOn( ostype & os ) {
326 nlOn( os ); // call void returning
327 return os;
328 } // nlOn
329
330 ostype & nlOff( ostype & os ) {
331 nlOff( os ); // call void returning
332 return os;
333 } // nlOff
334
335 ostype & sepVal( ostype & os ) {
336 return (ostype &)(os | sepGet( os ));
337 } // sepVal
338
339 ostype & sepTupleVal( ostype & os ) {
340 return os | sepGetTuple( os );
341 } // sepTupleVal
342
343 ostype & sep( ostype & os ) {
344 sep( os ); // call void returning
345 return os;
346 } // sep
347
348 ostype & nosep( ostype & os ) {
349 nosep( os ); // call void returning
350 return os;
351 } // nosep
352
353 ostype & sepOn( ostype & os ) {
354 sepOn( os ); // call void returning
355 return os;
356 } // sepOn
357
358 ostype & sepOff( ostype & os ) {
359 sepOff( os ); // call void returning
360 return os;
361 } // sepOff
362} // distribution
363
364// tuples
365forall( ostype &, T, Params... | writeable( T, ostype ) | { ostype & ?|?( ostype &, Params ); } ) {
366 ostype & ?|?( ostype & os, T arg, Params rest ) {
367 (ostype &)(os | arg); // print first argument
368 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator
369 (ostype &)(os | rest); // print remaining arguments
370 sepSetCur$( os, sepGet( os ) ); // switch to regular separator
371 return os;
372 } // ?|?
373 void ?|?( ostype & os, T arg, Params rest ) {
374 // (ostype &)(?|?( os, arg, rest )); ends( os );
375 (ostype &)(os | arg); // print first argument
376 sepSetCur$( os, sepGetTuple( os ) ); // switch to tuple separator
377 (ostype &)(os | rest); // print remaining arguments
378 sepSetCur$( os, sepGet( os ) ); // switch to regular separator
379 ends( os );
380 } // ?|?
381} // distribution
382
383// writes the range [begin, end) to the given stream
384forall( ostype &, elt_type | writeable( elt_type, ostype ), iterator_type | iterator( iterator_type, elt_type ) ) {
385 void write( iterator_type begin, iterator_type end, ostype & os ) {
386 void print( elt_type i ) { os | i; }
387 for_each( begin, end, print );
388 } // ?|?
389
390 void write_reverse( iterator_type begin, iterator_type end, ostype & os ) {
391 void print( elt_type i ) { os | i; }
392 for_each_reverse( begin, end, print );
393 } // ?|?
394} // distribution
395
396// *********************************** manipulators ***********************************
397
398// *********************************** integral ***********************************
399
400static const char * shortbin[] = { "0", "1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
401static const char * longbin[] = { "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" };
402
403// Default prefix for non-decimal prints is 0b, 0, 0x.
404#define INTEGRAL_FMT_IMPL( T, IFMTNP, IFMTP ) \
405forall( ostype & | basic_ostream( ostype ) ) { \
406 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
407 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
408\
409 if ( f.base == 'b' || f.base == 'B' ) { /* bespoke binary format */ \
410 int bits = high1( f.val ); /* position of most significant bit */ \
411 if ( bits == 0 ) bits = 1; /* 0 value => force one bit to print */ \
412 int spaces; \
413 if ( ! f.flags.left ) { /* right justified ? */ \
414 /* Note, base prefix then zero padding or spacing then prefix. */ \
415 if ( f.flags.pc ) { \
416 spaces = f.wd - f.pc; \
417 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
418 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \
419 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
420 spaces = f.pc - bits; \
421 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
422 } else { \
423 spaces = f.wd - bits; \
424 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
425 if ( f.flags.pad0 ) { \
426 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
427 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
428 } else { \
429 if ( spaces > 0 ) fmt( os, "%*s", spaces, " " ); /* space pad */ \
430 if ( ! f.flags.nobsdp ) { fmt( os, "0%c", f.base ); } \
431 } /* if */ \
432 } /* if */ \
433 } else { \
434 if ( ! f.flags.nobsdp ) fmt( os, "0%c", f.base ); \
435 if ( f.flags.pc ) { \
436 spaces = f.pc - bits; \
437 if ( spaces > 0 ) fmt( os, "%0*d", spaces, 0 ); /* zero pad */ \
438 spaces = f.wd - f.pc; \
439 } else { /* pad0 flag ignored with left flag */ \
440 spaces = f.wd - bits; \
441 } /* if */ \
442 if ( ! f.flags.nobsdp ) { spaces -= 2; } /* base prefix takes space */ \
443 } /* if */ \
444 int shift = floor( bits - 1, 4 ); \
445 typeof( f.val ) temp = f.val; \
446 fmt( os, "%s", shortbin[(temp >> shift) & 0xf] ); \
447 for () { \
448 shift -= 4; \
449 if ( shift < 0 ) break; \
450 temp = f.val; \
451 fmt( os, "%s", longbin[(temp >> shift) & 0xf] ); \
452 } /* for */ \
453 if ( f.flags.left && spaces > 0 ) fmt( os, "%*s", spaces, " " ); \
454 return os; \
455 } /* if */ \
456\
457 char fmtstr[sizeof(IFMTP)]; /* sizeof includes '\0' */ \
458 if ( ! f.flags.pc ) memcpy( &fmtstr, IFMTNP, sizeof(IFMTNP) ); \
459 else memcpy( &fmtstr, IFMTP, sizeof(IFMTP) ); \
460 int star = 5; /* position before first '*' */ \
461\
462 /* Insert flags into spaces before '*', from right to left. */ \
463 if ( ! f.flags.nobsdp ) { fmtstr[star] = '#'; star -= 1; } \
464 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; } \
465 if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \
466 if ( f.flags.pad0 && ! f.flags.pc ) { fmtstr[star] = '0'; star -= 1; } \
467 fmtstr[star] = '\''; star -= 1; /* locale */ \
468 fmtstr[star] = '%'; \
469\
470 /* Special case printing 0 in hexadecimal as printf does not put the base. */ \
471 if ( (f.base == 'x' | f.base == 'X') && ! f.flags.nobsdp && f.val == 0 ) { \
472 fmt( os, f.base == 'x' ? "0x" : "0X" ); \
473 f.wd -= 2; \
474 if ( f.wd < 0 ) f.wd = 1; \
475 } /* if */ \
476\
477 if ( ! f.flags.pc ) { /* no precision */ \
478 fmtstr[sizeof(IFMTNP)-2] = f.base; /* sizeof includes '\0' */ \
479 /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \
480 fmt( os, &fmtstr[star], f.wd, f.val ); \
481 } else { /* precision */ \
482 fmtstr[sizeof(IFMTP)-2] = f.base; /* sizeof includes '\0' */ \
483 /* printf( "%s %c\n", &fmtstr[star], f.base ); */ \
484 fmt( os, &fmtstr[star], f.wd, f.pc, f.val ); \
485 } /* if */ \
486 return os; \
487 } /* ?|? */ \
488 OSTYPE_VOID_IMPL( _Ostream_Manip(T) ) \
489} // distribution
490
491INTEGRAL_FMT_IMPL( signed char, " *hh ", " *.*hh " )
492INTEGRAL_FMT_IMPL( unsigned char, " *hh ", " *.*hh " )
493INTEGRAL_FMT_IMPL( signed short int, " *h ", " *.*h " )
494INTEGRAL_FMT_IMPL( unsigned short int, " *h ", " *.*h " )
495INTEGRAL_FMT_IMPL( signed int, " * ", " *.* " )
496INTEGRAL_FMT_IMPL( unsigned int, " * ", " *.* " )
497INTEGRAL_FMT_IMPL( signed long int, " *l ", " *.*l " )
498INTEGRAL_FMT_IMPL( unsigned long int, " *l ", " *.*l " )
499INTEGRAL_FMT_IMPL( signed long long int, " *ll ", " *.*ll " )
500INTEGRAL_FMT_IMPL( unsigned long long int, " *ll ", " *.*ll " )
501
502
503#if defined( __SIZEOF_INT128__ )
504// Default prefix for non-decimal prints is 0b, 0, 0x.
505forall( ostype & | basic_ostream( ostype ) )
506static inline void base_128( ostype & os, unsigned int128 val, unsigned int128 power, _Ostream_Manip(uint64_t) & f, unsigned int maxdig, unsigned int bits, unsigned int cnt = 0 ) {
507 int wd = 1; // f.wd is never 0 because 0 implies left-pad
508 if ( val > power ) { // subdivide value into printable 64-bit values
509 base_128( os, val / power, power, f, maxdig, bits, cnt + 1 ); // recursive
510 f.val = val % power;
511 if ( cnt == 1 && f.flags.left ) { wd = f.wd; f.wd = maxdig; } // copy f.wd and reset for printing middle chunk
512 // printf( "R val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n",
513 // f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 );
514 (ostype &)(os | f);
515 if ( cnt == 1 ) {
516 if ( f.flags.left ) { wd -= maxdig; f.wd = wd < 0 ? 1 : wd; } // update and restore f.wd for printing end chunk
517 nosep( os ); // no seperator between chunks
518 } // if
519 } else { // print start chunk
520 f.val = val;
521 // f.pc is unsigned => use wd
522 if ( f.flags.pc && f.pc > maxdig * cnt ) { wd = f.pc - maxdig * cnt; f.pc = wd < 0 ? 0 : wd; }
523 else { f.flags.pc = false; f.pc = 0; }
524
525 if ( ! f.flags.left ) { // right justify
526 wd = f.wd - maxdig * cnt;
527 f.wd = wd < 0 ? 1 : wd;
528 wd = maxdig;
529 } else { // left justify
530 if ( cnt != 0 ) { // value >= 2^64 ?
531 unsigned int dig, bs = 0;
532 // compute size of prefix digits and base
533 if ( f.base == 'd' || f.base == 'u' ) { // no base prefix
534 dig = ceil( log10( f.val ) ); // use floating-point
535 if ( f.base == 'd' && (f.flags.neg || f.flags.sign) ) bs = 1; // sign ?
536 } else {
537 dig = ceiling_div( high1( f.val ), bits );
538 if ( ! f.flags.nobsdp ) { // base prefix ?
539 if ( f.base == 'o' ) {
540 // 0 prefix for octal is not added for precision with leading zero
541 if ( f.pc <= dig ) bs = 1; // 1 character prefix
542 } else bs = 2; // 2 character prefix
543 } // if
544 } // if
545 wd = f.wd - (f.pc > dig ? f.pc : dig) - bs; // precision > leading digits ?
546 if ( wd < 0 ) wd = 1;
547 f.wd = 1;
548 } // if
549 // all manipulators handled implicitly for value < 2^64
550 } // if
551 // prior checks ensure wd not negative
552
553 if ( f.flags.neg ) f.val = -f.val;
554 // printf( "L val:%#lx(%lu) wd:%u pc:%u base:%c neg:%d pc:%d left:%d nobsdp:%d sign:%d pad0:%d\n",
555 // f.val, f.val, f.wd, f.pc, f.base, f.flags.neg, f.flags.pc, f.flags.left, f.flags.nobsdp, f.flags.sign, f.flags.pad0 );
556 (ostype &)(os | f);
557
558 // remaining middle and end chunks are padded with 0s on the left
559 if ( ! f.flags.left ) { f.flags.pad0 = true; f.flags.pc = false; } // left pad with 0s
560 else { f.pc = maxdig; f.flags.pc = true; } // left pad with precision
561
562 if ( cnt != 0 ) nosep( os ); // no seperator between chunks
563 f.wd = wd; // reset f.wd for next chunk
564 f.flags.sign = false; // no leading +/- sign
565 f.flags.nobsdp = true; // no leading base prefix
566 } // if
567} // base_128
568
569#define INTEGRAL_FMT_IMPL128( T ) \
570forall( ostype & | basic_ostream( ostype ) ) { \
571 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
572 _Ostream_Manip(uint64_t) fmt; \
573 fmt.[wd, pc, base, all] = f.[wd, pc, base, all]; \
574 if ( f.base == 'b' | f.base == 'B' ) { \
575 base_128( os, f.val, (unsigned int128)1 << 64, fmt, 64, 1 ); \
576 } else if ( f.base == 'o' ) { \
577 base_128( os, f.val, (unsigned int128)1 << 63, fmt, 21, 3 ); \
578 } else if ( f.base == 'd' || f.base == 'u' ) { \
579 if ( f.base == 'd' && f.val < 0 ) { f.val = -f.val; fmt.flags.neg = true; } \
580 base_128( os, f.val, (unsigned int128)10_000_000_000_000_000_000UL, fmt, 19, 0 ); \
581 } else { \
582 base_128( os, f.val, (unsigned int128)1 << 64, fmt, 16, 4 ); \
583 } /* if */ \
584 return os; \
585 } /* ?|? */ \
586 OSTYPE_VOID_IMPL( _Ostream_Manip(T) ) \
587} // distribution
588
589INTEGRAL_FMT_IMPL128( int128 )
590INTEGRAL_FMT_IMPL128( unsigned int128 )
591#endif // __SIZEOF_INT128__
592
593// *********************************** floating point ***********************************
594
595static const char *suffixes[] = {
596 "y", "z", "a", "f", "p", "n", "u", "m", "",
597 "K", "M", "G", "T", "P", "E", "Z", "Y"
598};
599#define SUFFIXES_START (-24) /* Smallest power for which there is a suffix defined. */
600#define SUFFIXES_END (SUFFIXES_START + (int)((sizeof(suffixes) / sizeof(char *) - 1) * 3))
601
602#define PRINT_WITH_DP2( os, format, ... ) \
603 { \
604 if ( ! f.flags.eng ) { \
605 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
606 if ( isfinite( f.val ) && ! f.flags.nobsdp ) { /* if number, print decimal point when no fraction or exponent */ \
607 for ( i = 0; i < len && buf[i] != '.' && buf[i] != 'e' && buf[i] != 'E' && \
608 buf[i] != 'p' && buf[i] != 'P'; i += 1 ); /* decimal point or scientific ? */ \
609 if ( i == len ) { \
610 if ( ! f.flags.left ) { \
611 buf[i] = '.'; buf[i + 1] = '\0'; \
612 if ( buf[0] == ' ' ) bufbeg = 1; /* decimal point within width */ \
613 } else { \
614 for ( i = 0; i < len && buf[i] != ' '; i += 1 ); /* trailing blank ? */ \
615 buf[i] = '.'; \
616 if ( i == len ) buf[i + 1] = '\0'; \
617 } /* if */ \
618 } /* if */ \
619 } /* if */ \
620 } else { \
621 int exp10, len2; \
622 eng( f.val, f.pc, exp10 ); /* changes arguments */ \
623 /* printf( "%g %d %d %d %s\n", f.val, f.wd, f.pc, exp10, format ); */ \
624 if ( ! f.flags.left && f.wd > 1 ) { \
625 /* Exponent size: 'e', optional minus sign, number of digits: log10(0) => undefined */ \
626 f.wd -= 1 + (exp10 < 0 ? 1 : 0) + lrint( floor( exp10 == 0 ? 0 : log10( abs( exp10 ) ) ) ) + 1; \
627 if ( f.wd < 1 ) f.wd = 1; \
628 } /* if */ \
629 len = snprintf( buf, size, format, ##__VA_ARGS__ ); \
630 if ( f.flags.left ) { \
631 for ( len -= 1; len > 0 && buf[len] == ' '; len -= 1 ); \
632 len += 1; \
633 } /* if */ \
634 if ( ! f.flags.nobsdp || (exp10 < SUFFIXES_START) || (exp10 > SUFFIXES_END) ) { \
635 len2 = snprintf( &buf[len], size - len, "e%d", (int)exp10 /* ambiguity with function exp10 */ ); \
636 } else { \
637 len2 = snprintf( &buf[len], size - len, "%s", suffixes[(exp10 - SUFFIXES_START) / 3] ); \
638 } /* if */ \
639 if ( f.flags.left && len + len2 < f.wd ) buf[len + len2] = ' '; \
640 } /* if */ \
641 fmt( os, "%s", &buf[bufbeg] ); \
642 }
643
644#define FLOATING_POINT_FMT_IMPL( T, DFMTNP, DFMTP ) \
645forall( ostype & | basic_ostream( ostype ) ) { \
646 static void eng( T &value, int & pc, int & exp10 ) { \
647 exp10 = lrint( floor( log10( abs( value ) ) ) ); /* round to desired precision */ \
648 if ( exp10 < 0 ) exp10 -= 2; \
649 exp10 = floor( exp10, 3 ); \
650 value *= pow( 10.0, -exp10 ); \
651 if ( pc <= 3 ) pc = 3; \
652 } /* eng */ \
653\
654 ostype & ?|?( ostype & os, _Ostream_Manip(T) f ) { \
655 enum { size = 48 }; \
656 char buf[size]; \
657 int bufbeg = 0, i, len; \
658\
659 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) ); \
660 char fmtstr[sizeof(DFMTP) + 8]; /* sizeof includes '\0' */ \
661 if ( ! f.flags.pc ) memcpy( &fmtstr, DFMTNP, sizeof(DFMTNP) ); \
662 else memcpy( &fmtstr, DFMTP, sizeof(DFMTP) ); \
663 int star = 5; /* position before first '*' */ \
664\
665 /* Insert flags into spaces before '*', from right to left. */ \
666 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; } \
667 if ( f.flags.sign ) { fmtstr[star] = '+'; star -= 1; } \
668 if ( f.flags.pad0 ) { fmtstr[star] = '0'; star -= 1; } \
669 fmtstr[star] = '\''; star -= 1; /* locale */ \
670 fmtstr[star] = '%'; \
671\
672 if ( ! f.flags.pc ) { /* no precision */ \
673 fmtstr[sizeof(DFMTNP)-2] = f.base; /* sizeof includes '\0' */ \
674 /* printf( "%g %d %s\n", f.val, f.wd, &fmtstr[star] ); */ \
675 PRINT_WITH_DP2( os, &fmtstr[star], f.wd, f.val ) \
676 } else { /* precision */ \
677 fmtstr[sizeof(DFMTP)-2] = f.base; /* sizeof includes '\0' */ \
678 /* printf( "%g %d %d %s\n", f.val, f.wd, f.pc, &fmtstr[star] ); */ \
679 PRINT_WITH_DP2( os, &fmtstr[star], f.wd, f.pc, f.val ) \
680 } /* if */ \
681 return os; \
682 } /* ?|? */ \
683\
684 OSTYPE_VOID_IMPL( _Ostream_Manip(T) ) \
685} // distribution
686
687FLOATING_POINT_FMT_IMPL( double, " * ", " *.* " )
688FLOATING_POINT_FMT_IMPL( long double, " *L ", " *.*L " )
689
690// *********************************** character ***********************************
691
692forall( ostype & | basic_ostream( ostype ) ) {
693 ostype & ?|?( ostype & os, _Ostream_Manip(char) f ) {
694 if ( f.base != 'c' ) { // bespoke binary/octal/hex format
695 _Ostream_Manip(unsigned char) fmtuc @= { f.val, f.wd, f.pc, f.base, {'\0'} };
696 fmtuc.flags.pc = f.flags.pc;
697 fmtuc.flags.nobsdp = f.flags.nobsdp;
698// os | fmtuc | nonl;
699 (ostype &)(os | fmtuc);
700 return os;
701 } // if
702
703 if ( sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
704
705 #define CFMTNP "% * "
706 char fmtstr[sizeof(CFMTNP)]; // sizeof includes '\0'
707 memcpy( &fmtstr, CFMTNP, sizeof(CFMTNP) );
708 int star = 1; // position before first '*'
709
710 // Insert flags into spaces before '*', from right to left.
711 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; }
712 fmtstr[star] = '%';
713
714 fmtstr[sizeof(CFMTNP)-2] = f.base; // sizeof includes '\0'
715 // printf( "%d %s\n", f.wd, &fmtstr[star] );
716 fmt( os, &fmtstr[star], f.wd, f.val );
717 return os;
718 } // ?|?
719 OSTYPE_VOID_IMPL( _Ostream_Manip(char) )
720} // distribution
721
722// *********************************** C string ***********************************
723
724forall( ostype & | basic_ostream( ostype ) ) {
725 ostype & ?|?( ostype & os, _Ostream_Manip(const char *) f ) {
726 if ( ! f.val ) return os; // null pointer ?
727
728 if ( f.base != 's' ) { // bespoke binary/octal/hex format
729 _Ostream_Manip(unsigned char) fmtuc @= { 0, f.wd, f.pc, f.base, {'\0'} };
730 fmtuc.flags.pc = f.flags.pc;
731 fmtuc.flags.nobsdp = f.flags.nobsdp;
732 for ( i; 0 ~ @ : @; f.val[i] != '\0' ) {
733 fmtuc.val = f.val[i];
734// os | fmtuc | nonl;
735 (ostype &)(os | fmtuc);
736 } // for
737 return os;
738 } // if
739
740 if ( f.val[0] != '\0' && // null string => no leading separator
741 sepPrt$( os ) ) fmt( os, "%s", sepGetCur$( os ) );
742
743 #define SFMTNP "% * "
744 #define SFMTP "% *.* "
745 char fmtstr[sizeof(SFMTP)]; // sizeof includes '\0'
746 if ( ! f.flags.pc ) memcpy( &fmtstr, SFMTNP, sizeof(SFMTNP) );
747 else memcpy( &fmtstr, SFMTP, sizeof(SFMTP) );
748 int star = 1; // position before first '*'
749
750 // Insert flags into spaces before '*', from right to left.
751 if ( f.flags.left ) { fmtstr[star] = '-'; star -= 1; }
752 fmtstr[star] = '%';
753
754 if ( ! f.flags.pc ) { // no precision
755 // printf( "%d %s\n", f.wd, &fmtstr[star] );
756 fmtstr[sizeof(SFMTNP)-2] = f.base; // sizeof includes '\0'
757 fmt( os, &fmtstr[star], f.wd, f.val );
758 } else { // precision
759 fmtstr[sizeof(SFMTP)-2] = f.base; // sizeof includes '\0'
760 // printf( "%d %d %s\n", f.wd, f.pc, &fmtstr[star] );
761 fmt( os, &fmtstr[star], f.wd, f.pc, f.val );
762 } // if
763 if ( f.val[0] == '\0' ) { nosep( os ); } // null string => no trailing separator
764 return os;
765 } // ?|?
766 OSTYPE_VOID_IMPL( _Ostream_Manip(const char *) )
767} // distribution
768
769
770// *********************************** istream ***********************************
771
772
773forall( istype & | basic_istream( istype ) ) {
774 istype & ?|?( istype & is, bool & b ) {
775 char val[6];
776 fmt( is, "%5s", val );
777 if ( strcmp( val, "true" ) == 0 ) b = true;
778 else if ( strcmp( val, "false" ) == 0 ) b = false;
779 else {
780 fprintf( stderr, "invalid Boolean constant\n" );
781 abort(); // cannot use abort stream
782 } // if
783 return is;
784 } // ?|?
785 ISTYPE_VOID_IMPL( bool & )
786
787 istype & ?|?( istype & is, char & c ) {
788 char temp;
789 for () {
790 fmt( is, "%c", &temp ); // must pass pointer through varg to fmt
791 // do not overwrite parameter with newline unless appropriate
792 if ( temp != '\n' || getANL$( is ) ) { c = temp; break; }
793 if ( eof( is ) ) break;
794 } // for
795 return is;
796 } // ?|?
797 ISTYPE_VOID_IMPL( char & )
798
799 istype & ?|?( istype & is, signed char & sc ) {
800 fmt( is, "%hhi", &sc );
801 return is;
802 } // ?|?
803 ISTYPE_VOID_IMPL( signed char & )
804
805 istype & ?|?( istype & is, unsigned char & usc ) {
806 fmt( is, "%hhi", &usc );
807 return is;
808 } // ?|?
809 ISTYPE_VOID_IMPL( unsigned char & )
810
811 istype & ?|?( istype & is, short int & si ) {
812 fmt( is, "%hi", &si );
813 return is;
814 } // ?|?
815 ISTYPE_VOID_IMPL( short int & )
816
817 istype & ?|?( istype & is, unsigned short int & usi ) {
818 fmt( is, "%hi", &usi );
819 return is;
820 } // ?|?
821 ISTYPE_VOID_IMPL( unsigned short int & )
822
823 istype & ?|?( istype & is, int & i ) {
824 fmt( is, "%i", &i );
825 return is;
826 } // ?|?
827 ISTYPE_VOID_IMPL( int & )
828
829 istype & ?|?( istype & is, unsigned int & ui ) {
830 fmt( is, "%i", &ui );
831 return is;
832 } // ?|?
833 ISTYPE_VOID_IMPL( unsigned int & )
834
835 istype & ?|?( istype & is, long int & li ) {
836 fmt( is, "%li", &li );
837 return is;
838 } // ?|?
839 ISTYPE_VOID_IMPL( long int & )
840
841 istype & ?|?( istype & is, unsigned long int & ulli ) {
842 fmt( is, "%li", &ulli );
843 return is;
844 } // ?|?
845 ISTYPE_VOID_IMPL( unsigned long int & )
846
847 istype & ?|?( istype & is, long long int & lli ) {
848 fmt( is, "%lli", &lli );
849 return is;
850 } // ?|?
851 ISTYPE_VOID_IMPL( long long int & )
852
853 istype & ?|?( istype & is, unsigned long long int & ulli ) {
854 fmt( is, "%lli", &ulli );
855 return is;
856 } // ?|?
857 ISTYPE_VOID_IMPL( unsigned long long int & )
858
859 #if defined( __SIZEOF_INT128__ )
860 istype & ?|?( istype & is, int128 & llli ) {
861 return (istype &)(is | (unsigned int128 &)llli);
862 } // ?|?
863 ISTYPE_VOID_IMPL( int128 & )
864
865 istype & ?|?( istype & is, unsigned int128 & ullli ) {
866 char s[40];
867 bool sign = false;
868
869 if ( fmt( is, " %[-]", s ) == 1 ) sign = true; // skip whitespace, negative sign ?
870 // If the input is too large, the value returned is undefined. If there is no input, no value is returned
871 if ( fmt( is, "%39[0-9]%*[0-9]", s ) == 1 ) { // take first 39 characters, ignore remaining
872 ullli = 0;
873 for ( i; 0 ~ @ : @; s[i] != '\0' ) {
874 ullli = ullli * 10 + s[i] - '0';
875 } // for
876 if ( sign ) ullli = -ullli;
877 } else if ( sign ) ungetc( is, '-' ); // return minus when no digits
878 return is;
879 } // ?|?
880 ISTYPE_VOID_IMPL( unsigned int128 & )
881 #endif // __SIZEOF_INT128__
882
883 istype & ?|?( istype & is, float & f ) {
884 fmt( is, "%f", &f );
885 return is;
886 } // ?|?
887 ISTYPE_VOID_IMPL( float & )
888
889 istype & ?|?( istype & is, double & d ) {
890 fmt( is, "%lf", &d );
891 return is;
892 } // ?|?
893 ISTYPE_VOID_IMPL( double & )
894
895 istype & ?|?( istype & is, long double & ld ) {
896 fmt( is, "%Lf", &ld );
897 return is;
898 } // ?|?
899 ISTYPE_VOID_IMPL( long double & )
900
901 istype & ?|?( istype & is, float _Complex & fc ) {
902 float re, im;
903 fmt( is, "%f%fi", &re, &im );
904 fc = re + im * _Complex_I;
905 return is;
906 } // ?|?
907 ISTYPE_VOID_IMPL( float _Complex & )
908
909 istype & ?|?( istype & is, double _Complex & dc ) {
910 double re, im;
911 fmt( is, "%lf%lfi", &re, &im );
912 dc = re + im * _Complex_I;
913 return is;
914 } // ?|?
915 ISTYPE_VOID_IMPL( double _Complex & )
916
917 istype & ?|?( istype & is, long double _Complex & ldc ) {
918 long double re, im;
919 fmt( is, "%Lf%Lfi", &re, &im );
920 ldc = re + im * _Complex_I;
921 return is;
922 } // ?|?
923 ISTYPE_VOID_IMPL( long double _Complex & )
924
925 istype & ?|?( istype & is, const char fmt[] ) {
926 fmt( is, fmt, "" );
927 return is;
928 } // ?|?
929 ISTYPE_VOID_IMPL( const char * )
930
931 // manipulators
932 istype & ?|?( istype & is, istype & (* manip)( istype & ) ) {
933 return manip( is );
934 } // ?|?
935
936 void ?|?( istype & is, istype & (* manip)( istype & ) ) {
937 manip( is ); ends( is );
938 } // ?|?
939
940 istype & nl( istype & is ) {
941 fmt( is, "%*[^\n]" ); // ignore characters to newline
942 if ( ! eof( is ) && getANL$( is ) ) fmt( is, "%*c" ); // read newline
943 return is;
944 } // nl
945
946 istype & nlOn( istype & is ) {
947 nlOn( is ); // call void returning
948 return is;
949 } // nlOn
950
951 istype & nlOff( istype & is ) {
952 nlOff( is ); // call void returning
953 return is;
954 } // nlOff
955} // distribution
956
957// *********************************** manipulators ***********************************
958
959forall( istype & | basic_istream( istype ) ) {
960 istype & ?|?( istype & is, _Istream_Cskip f ) {
961 // printf( "skip %s %d\n", f.scanset, f.wd );
962 if ( f.scanset ) fmt( is, f.scanset, "" ); // no input arguments
963 else for ( f.wd ) fmt( is, "%*c" );
964 return is;
965 }
966 ISTYPE_VOID_IMPL( _Istream_Cskip )
967
968 istype & ?|?( istype & is, _Istream_Cstr f ) {
969 const char * scanset = f.scanset;
970 if ( f.flags.delimiter ) scanset = f.delimiter; // getline ?
971
972 size_t len = 0;
973 if ( scanset ) len = strlen( scanset );
974 char fmtstr[len + 16];
975 int start = 1;
976 fmtstr[0] = '%';
977 if ( f.flags.ignore ) { fmtstr[1] = '*'; start += 1; }
978 // no maximum width necessary because text ignored => width is read width
979 if ( f.wd != -1 ) {
980 // wd is buffer bytes available (for input chars + null terminator)
981 // rwd is count of input chars
982 int rwd = f.flags.rwd ? f.wd : (f.wd - 1);
983 start += sprintf( &fmtstr[start], "%d", rwd );
984 }
985
986 if ( ! scanset ) {
987 // %s, %*s, %ws, %*ws
988 fmtstr[start] = 's'; fmtstr[start + 1] = '\0';
989 // printf( "cstr %s\n", fmtstr );
990 } else {
991 // incl %[xxx], %*[xxx], %w[xxx], %*w[xxx]
992 // excl %[^xxx], %*[^xxx], %w[^xxx], %*w[^xxx]
993 fmtstr[start] = '['; start += 1;
994 if ( f.flags.inex ) { fmtstr[start] = '^'; start += 1; }
995 strcpy( &fmtstr[start], scanset ); // copy includes '\0'
996 len += start;
997 fmtstr[len] = ']'; fmtstr[len + 1] = '\0';
998 // printf( "incl/excl %s\n", fmtstr );
999 } // if
1000
1001 int check = f.wd - 2;
1002 if ( ! f.flags.rwd ) f.s[check] = '\0'; // insert sentinel
1003 len = fmt( is, fmtstr, f.s );
1004 //fprintf( stderr, "KK %s %zd %d %c %s\n", fmtstr, len, check, f.s[check], f.s );
1005
1006 if ( ! f.flags.rwd && f.s[check] != '\0' ) // sentinel overwritten ?
1007 throw (cstring_length){ &cstring_length_vt };
1008
1009 if ( f.flags.delimiter ) { // getline ?
1010 if ( len == 0 ) f.s[0] = '\0'; // empty read => argument unchanged => set empty
1011 if ( ! eof( is ) ) { // ignore delimiter, may not be present because of width
1012 char delimiter;
1013 fmt( is, "%c", &delimiter );
1014 if ( delimiter != f.delimiter[0] ) ungetc( is, delimiter );
1015 } // if
1016 } //if
1017 return is;
1018 } // ?|?
1019 ISTYPE_VOID_IMPL( _Istream_Cstr )
1020
1021 istype & ?|?( istype & is, _Istream_Char f ) {
1022 fmt( is, "%*c" ); // argument variable unused
1023 return is;
1024 } // ?|?
1025 ISTYPE_VOID_IMPL( _Istream_Char )
1026} // distribution
1027
1028#define INPUT_FMT_IMPL( T, CODE ) \
1029forall( istype & | basic_istream( istype ) ) { \
1030 istype & ?|?( istype & is, _Istream_Manip(T) f ) { \
1031 enum { size = 16 }; \
1032 char fmtstr[size]; \
1033 if ( f.wd == -1 ) { \
1034 snprintf( fmtstr, size, "%%%s%s", f.ignore ? "*" : "", CODE ); \
1035 } else { \
1036 snprintf( fmtstr, size, "%%%s%d%s", f.ignore ? "*" : "", f.wd, CODE ); \
1037 } /* if */ \
1038 /* printf( "%d %s %p\n", f.wd, fmtstr, &f.val ); */ \
1039 fmt( is, fmtstr, &f.val ); \
1040 return is; \
1041 } /* ?|? */ \
1042 ISTYPE_VOID_IMPL( _Istream_Manip(T) ) \
1043} // distribution
1044
1045INPUT_FMT_IMPL( signed char, "hhi" )
1046INPUT_FMT_IMPL( unsigned char, "hhi" )
1047INPUT_FMT_IMPL( signed short int, "hi" )
1048INPUT_FMT_IMPL( unsigned short int, "hi" )
1049INPUT_FMT_IMPL( signed int, "i" )
1050INPUT_FMT_IMPL( unsigned int, "i" )
1051INPUT_FMT_IMPL( signed long int, "li" )
1052INPUT_FMT_IMPL( unsigned long int, "li" )
1053INPUT_FMT_IMPL( signed long long int, "lli" )
1054INPUT_FMT_IMPL( unsigned long long int, "lli" )
1055
1056INPUT_FMT_IMPL( float, "f" )
1057INPUT_FMT_IMPL( double, "lf" )
1058INPUT_FMT_IMPL( long double, "Lf" )
1059
1060forall( istype & | basic_istream( istype ) ) {
1061 istype & ?|?( istype & is, _Istream_Manip(float _Complex) fc ) {
1062 float re, im;
1063 _Istream_Manip(float) fmtuc @= { re, fc.wd, fc.ignore };
1064 is | fmtuc;
1065 &fmtuc.val = &im;
1066 is | fmtuc;
1067 if ( ! fc.ignore ) fc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
1068 return is;
1069 } // ?|?
1070 ISTYPE_VOID_IMPL( _Istream_Manip(float _Complex) )
1071
1072 istype & ?|?( istype & is, _Istream_Manip(double _Complex) dc ) {
1073 double re, im;
1074 _Istream_Manip(double) fmtuc @= { re, dc.wd, dc.ignore };
1075 is | fmtuc;
1076 &fmtuc.val = &im;
1077 is | fmtuc;
1078 if ( ! dc.ignore ) dc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
1079 return is;
1080 } // ?|?
1081 ISTYPE_VOID_IMPL( _Istream_Manip(double _Complex) )
1082
1083 istype & ?|?( istype & is, _Istream_Manip(long double _Complex) ldc ) {
1084 long double re, im;
1085 _Istream_Manip(long double) fmtuc @= { re, ldc.wd, ldc.ignore };
1086 is | fmtuc;
1087 &fmtuc.val = &im;
1088 is | fmtuc;
1089 if ( ! ldc.ignore ) ldc.val = re + im * _Complex_I; // re/im are uninitialized for ignore
1090 return is;
1091 } // ?|?
1092 ISTYPE_VOID_IMPL( _Istream_Manip(long double _Complex) )
1093} // distribution
1094
1095
1096// Local Variables: //
1097// tab-width: 4 //
1098// compile-command: "cfa iostream.cfa" //
1099// End: //
Note: See TracBrowser for help on using the repository browser.