11 #include </home/solar/src/pdclib/functions/_PDCLIB/digits.c>
13 /* Using an integer's bits as flags for both the conversion flags and length
26 #define E_intmax 1<<10
28 #define E_ptrdiff 1<<12
29 #define E_double 1<<13
33 void parse_out( const char * spec, va_list ap );
37 int base; /* base to which the value shall be converted */
38 int flags; /* flags and length modifiers */
39 size_t n; /* maximum number of characters to be written */
40 size_t i; /* number of characters already written */
41 size_t this; /* number of output chars in the current conversion */
42 char * s; /* target buffer */
43 size_t width; /* width of current field */
44 int prec; /* precision of current field */
47 /* x - the character to be delivered
48 i - pointer to number of characters already delivered in this call
49 n - pointer to maximum number of characters to be delivered in this call
50 s - the buffer into which the character shall be delivered
53 #define DELIVER( x ) if ( status->i < status->n ) status->s[status->i] = x; ++(status->i)
55 /* TODO: Left / right alignment - requires track-keeping of width and printed chars.
56 "Father function", die für right alignment "tail recursive" gerufen wird, und
57 "after" für left alignment? Parameter als struct?
60 static void int2base( int value, struct status_t * status )
63 if ( ( value / status->base ) != 0 )
65 int2base( value / status->base, status );
69 char preface[3] = "\0\0";
71 if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) )
73 preface[ preidx++ ] = '0';
74 if ( status->base == 16 )
76 preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X';
81 preface[ preidx++ ] = '-';
85 if ( status->flags & E_plus )
87 preface[ preidx++ ] = '+';
89 else if ( status->flags & E_space )
91 preface[ preidx++ ] = ' ';
94 if ( ! ( ( status->flags & E_minus ) || ( status->flags & E_zero ) ) )
96 while ( ( status->this + preidx ) < status->width )
103 while ( preface[ preidx ] != '\0' )
105 DELIVER( preface[ preidx++ ] );
108 if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
110 while ( status->this < status->width )
121 if ( status->flags & E_lower )
123 DELIVER( _PDCLIB_digits[ value % status->base ] );
127 DELIVER( toupper( _PDCLIB_digits[ value % status->base ] ) );
131 static void padwrap( int value, struct status_t * status )
133 int2base( value, status );
134 if ( status->flags & E_minus )
136 while ( status->this < status->width )
142 if ( status->i == status->n )
144 status->s[status->i] = '\0';
148 void parse_out( const char * spec, va_list ap )
150 /* TODO: '%' handled correctly? */
151 struct status_t status = { 0, 0, 0, 0, 0, NULL, 0, EOF };
152 /* First come 0..n flags */
153 while ( ! ( status.flags & E_done ) )
158 status.flags |= E_minus;
161 status.flags |= E_plus;
164 status.flags |= E_alt;
167 status.flags |= E_space;
170 status.flags |= E_zero;
173 status.flags |= E_done;
179 /* Retrieve width value from argument stack */
180 if ( ( status.width = va_arg( ap, int ) ) < 0 )
182 /* Negative value is '-' flag plus absolute value */
183 status.flags |= E_minus;
190 /* If a width is given, strtol() will return its value. If not given,
191 strtol() will return zero. In both cases, endptr will point to the
192 rest of the conversion specifier.
195 status.width = (int)strtol( spec, &endptr, 10 );
200 if ( *(++spec) == '*' )
202 /* Retrieve precision value from argument stack. A negative value
203 is as if no precision is given - as precision is initalized to
204 EOF (negative), there is no need for testing for negative here.
206 status.prec = va_arg( ap, int );
211 status.prec = (int)strtol( spec, &endptr, 10 );
215 /* We step one character ahead in any case, and step back only if we find
216 there has been no length modifier (or step ahead another character if it
217 has been "hh" or "ll").
224 status.flags |= E_char;
229 status.flags |= E_short;
235 status.flags |= E_llong;
240 status.flags |= E_long;
244 status.flags |= E_intmax;
247 status.flags |= E_size;
250 status.flags |= E_ptrdiff;
253 status.flags |= E_double;
263 /* int2base( 10, value, true ) */
266 /* int2base( 8, value, true ) */
269 /* uint2base( 10, value, true ) */
272 /* uint2base( 16, value, true ) */
275 /* uint2base( 16, value, false ) */
292 /* uint2base( 16, (intptr_t)value, true ) */
295 // conversion specifier
304 static void int2base( int value, int base, struct status_t * status )
316 #define E_intmax 1<<10
318 #define E_ptrdiff 1<<12
319 #define E_double 1<<13
320 #define E_lower 1<<14
333 #define TESTCASE( _flags, _n, _width, _prec, _value, _base, _expect ) \
334 status.flags = _flags | E_term; \
337 status.width = _width; \
338 status.prec = _prec; \
339 status.base = _base; \
341 memset( status.s, '\0', 20 ); \
342 padwrap( _value, &status ); \
343 printf( "Output '%s', RC %d \t- ", status.s, status.i ); \
344 rc = snprintf( buffer, _n, _expect, _value ); \
345 printf( "Expect '%s', RC %d\n", buffer, rc );
349 struct status_t status;
351 char * buffer = malloc( 20 );
352 status.s = malloc( 20 );
353 TESTCASE( E_plus, 5, 0, 0, 1234, 10, "%+d" );
354 TESTCASE( E_space, 3, 0, 0, 1234, 10, "% d" );
355 TESTCASE( E_space, 3, 0, 0, -1234, 10, "% d" );
356 TESTCASE( E_plus, 3, 0, 0, -1234, 10, "%+d" );
357 TESTCASE( E_done, 4, 0, 0, 65535, 16, "%X" );
358 TESTCASE( E_lower | E_alt, 4, 0, 0, 65534, 16, "%#x" );
359 TESTCASE( E_done, 4, 0, 0, 62, 8, "%o" );
360 TESTCASE( E_alt, 4, 0, 0, 62, 8, "%#o" );
361 TESTCASE( E_done, 6, 6, 0, 1234, 10, "%6d" );
362 TESTCASE( E_minus, 6, 6, 0, 1234, 10, "%-6d" );
363 TESTCASE( E_minus, 6, 2, 0, 1234, 10, "%-2d" );
364 TESTCASE( E_done, 6, 2, 0, 1234, 10, "%2d" );
365 TESTCASE( E_zero, 6, 6, 0, -1234, 10, "%06d" );
366 TESTCASE( E_zero, 7, 7, 0, -65535, 16, "%07X" );
367 TESTCASE( E_zero | E_minus, 6, 6, 0, 1234, 10, "%-06d" );
368 TESTCASE( E_plus, 6, 6, 0, 1234, 10, "%+6d" );
369 TESTCASE( E_space, 6, 6, 0, 1234, 10, "% 6d" );
370 TESTCASE( E_space, 6, 6, 0, -1234, 10, "% 6d" );
371 TESTCASE( E_space | E_minus, 6, 6, 0, -1234, 10, "%- 6d" );