source: libcfa/src/iostream.cfa@ 64c4b4d

Last change on this file since 64c4b4d was 3db78b89, checked in by Michael Brooks <mlbrooks@…>, 2 years ago

Fix string reading bug: Manipulator ignore should not write to its output argument.

The prior test expectation was wrong.
The test was not following its rule that it should expect
the CFA library to show scanf-analogous behaviour.

Note, the corresponding expectation in collections/string-istream-manip was already correct.

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