1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <kapp/main.h>
28 #include <kapp/args.h>
29 #include <klib/printf.h>
30 #include <klib/symbol.h>
31 #include <klib/text.h>
32 #include <klib/time.h>
33 #include <klib/log.h>
34 #include <klib/out.h>
35 #include <klib/rc.h>
36 #include <kfg/config.h>
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <va_copy.h>
43 #include <time.h>
44
45 static
test_vprintf(const char * expected,const char * fmt,va_list args)46 rc_t test_vprintf ( const char *expected, const char *fmt, va_list args )
47 {
48 rc_t rc;
49 size_t num_writ;
50 char buff [ 4096 ];
51
52 rc = string_vprintf ( buff, sizeof buff, & num_writ, fmt, args );
53 if ( rc != 0 )
54 {
55 /* report return code */
56 pLogErr ( klogErr, rc, "string_vprintf returned non-zero rc with format '$(fmt)'", "fmt=%s", fmt );
57 }
58 else
59 {
60 size_t buff_size;
61
62 /* verify results. they are:
63 1. string itself
64 2. number of characters in "num_writ"
65 */
66
67 if ( strcmp ( buff, expected ) != 0 )
68 {
69 /* set an appropriate return code */
70 rc = RC ( rcExe, rcString, rcFormatting, rcData, rcIncorrect );
71
72 /* report discrepancy */
73 pLogErr ( klogErr, rc,
74 "string_vprintf result differs from expected:\n"
75 " format - '$(format)'\n"
76 " expected - '$(expected)'\n"
77 " observed - '$(observed)'"
78 , "format=%s,expected=%s,observed=%s"
79 , fmt
80 , expected
81 , buff
82 );
83 }
84
85 buff_size = strlen ( buff );
86 if ( buff_size != num_writ )
87 {
88 /* report discrepancy */
89 pLogMsg ( klogErr,
90 "string_vprintf size differs from expected:\n"
91 " expected - $(expected)\n"
92 " observed - $(observed)"
93 , "expected=%zu,observed=%zu"
94 , buff_size
95 , num_writ
96 );
97 }
98 #if 1
99 rc = 0;
100 #endif
101 }
102
103 return rc;
104 }
105
106 static
test_printf(const char * expected,const char * fmt,...)107 rc_t test_printf ( const char *expected, const char *fmt, ... )
108 {
109 rc_t rc;
110 va_list args;
111 va_start ( args, fmt );
112 rc = test_vprintf ( expected, fmt, args );
113 va_end ( args );
114 return rc;
115 }
116
117
118 /* NEW TESTING STRATEGY
119
120 6a. size modifier
121 a. NULL ( not given )
122 b. 't' for 8-bit integer
123 c. 'h' for 16 bit integer or 32-bit float
124 d. 'l' for 64-bit integer or long double
125 E. 'z' for size of size_t ( 32 or 64 bit depending upon architecture )
126 6b. time modifier ( do this later )
127
128 So, you'll want functions for each stage. The driving function will invoke
129 the stages with parameters and values.
130 */
131
132 static
final(const char * flags,int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)133 rc_t final ( const char *flags, int32_t *field_width, int32_t *precision,
134 char size_modifier, char storage_class, va_list args )
135 {
136 rc_t rc;
137 uint32_t i, j;
138 va_list arg_copy;
139 char stdcfmt [ 32 ], fmt [ 32 ], expected [ 4096 ];
140
141 /* initialize counters */
142 i = 0;
143
144 /* build format string */
145 fmt [ i ++ ] = '%';
146
147 if ( flags != NULL )
148 i += sprintf ( & fmt [ i ], "%s", flags );
149 if ( field_width != NULL )
150 {
151 if ( field_width [ 0 ] == -1 )
152 fmt [ i ++ ] = '*';
153 else
154 i += sprintf ( & fmt [ i ], "%u", field_width [ 0 ] );
155 }
156 if ( precision != NULL )
157 {
158 fmt [ i ++ ] = '.';
159
160 if ( precision [ 0 ] == -1 )
161 fmt [ i ++ ] = '*';
162 else
163 i += sprintf ( & fmt [ i ], "%u", precision [ 0 ] );
164 }
165 fmt[i]=0;
166
167 /* duplicate format string */
168 strcpy ( stdcfmt, fmt );
169 j = i;
170
171 /* size modifiers */
172 if ( size_modifier != 0 )
173 {
174 fmt [ i ++ ] = size_modifier;
175
176 switch ( size_modifier )
177 {
178 case 't':
179 #if WINDOWS
180 return 0; /* hh does not work as we expect on Windows */
181 #endif
182 stdcfmt [ j ++ ] = 'h';
183 stdcfmt [ j ++ ] = 'h';
184 break;
185 case 'z':
186 if ( sizeof ( size_t ) != sizeof ( uint32_t ) )
187 stdcfmt [ j ++ ] = 'l';
188 break;
189 case 'l':
190 if ( sizeof ( long int ) == sizeof ( int32_t ) )
191 stdcfmt [ j ++ ] = size_modifier;
192 /* no break */
193 default:
194 stdcfmt [ j ++ ] = size_modifier;
195 }
196 }
197
198 /* storage class/formatting */
199 fmt [ i ++ ] = storage_class;
200 stdcfmt [ j ++ ] = storage_class;
201
202 /* terminate format strings with NUL */
203 fmt [ i ] = 0;
204 stdcfmt [ j ] = 0;
205
206 /* generate expected string */
207 va_copy ( arg_copy, args );
208 vsnprintf ( expected, sizeof expected, stdcfmt, arg_copy );
209 va_end ( arg_copy );
210
211 /* execute test */
212 va_copy ( arg_copy, args );
213 rc = test_vprintf ( expected, fmt, arg_copy );
214 va_end ( arg_copy );
215
216 return rc;
217 }
218
thousands_flag(char * flags,uint32_t num_flags,int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)219 static rc_t thousands_flag ( char *flags, uint32_t num_flags, int32_t *field_width, int32_t *precision,
220 char size_modifier, char storage_class, va_list args)
221 {
222 #if 1
223 /* built-in sprintf can't handle this */
224 return final ( flags, field_width, precision, size_modifier, storage_class, args );
225 #else
226 rc_t rc;
227
228 /* with nothing */
229 rc = final ( flags, field_width, precision, size_modifier, storage_class, args );
230 if ( rc != 0 )
231 return rc;
232
233 /* with thousands */
234 flags [ num_flags ] = ',';
235 flags [ num_flags + 1 ] = 0;
236 rc = final ( flags, field_width, precision, size_modifier, storage_class, args );
237
238 return rc;
239 #endif
240
241 }
alternate_flag(char * flags,uint32_t num_flags,int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)242 static rc_t alternate_flag ( char *flags, uint32_t num_flags, int32_t *field_width, int32_t *precision,
243 char size_modifier, char storage_class, va_list args)
244 {
245 rc_t rc;
246
247
248 /* with nothing */
249 rc = thousands_flag ( flags, num_flags, field_width, precision, size_modifier, storage_class, args );
250 if ( rc != 0 )
251 return rc;
252
253 /* with alternate */
254 flags [ num_flags ] = '#';
255 flags [ num_flags + 1 ] = 0;
256 rc = thousands_flag ( flags, num_flags + 1, field_width, precision, size_modifier, storage_class, args );
257
258 return rc;
259 }
260
alignment_flag(char * flags,uint32_t num_flags,int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)261 static rc_t alignment_flag ( char *flags, uint32_t num_flags, int32_t *field_width, int32_t *precision,
262 char size_modifier, char storage_class, va_list args)
263 {
264 rc_t rc;
265
266 /* with nothing */
267 rc = alternate_flag ( flags, num_flags, field_width, precision, size_modifier, storage_class, args );
268 if ( rc != 0 )
269 return rc;
270
271 /* with left-align */
272 flags [ num_flags ] = '-';
273 flags [ num_flags + 1 ] = 0;
274 rc = alternate_flag ( flags, num_flags + 1, field_width, precision, size_modifier, storage_class, args );
275 if ( rc != 0 )
276 return rc;
277
278 /* with zer-padding left-fill */
279 flags [ num_flags ] = '0';
280 flags [ num_flags + 1 ] = 0;
281 rc = alternate_flag ( flags, num_flags + 1, field_width, precision, size_modifier, storage_class, args );
282 if ( rc != 0 )
283 return rc;
284
285 /* with both left-align and zero-padded left fill */
286 flags [ num_flags ] = '0';
287 flags [ num_flags + 1 ] = '-';
288 flags [ num_flags + 2 ] = 0;
289 rc = alternate_flag ( flags, num_flags + 2, field_width, precision, size_modifier, storage_class, args );
290
291 return rc;
292 }
293
sign_flag(int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)294 static rc_t sign_flag ( int32_t *field_width, int32_t *precision,
295 char size_modifier, char storage_class, va_list args)
296 {
297 rc_t rc;
298 char flags [ 16 ];
299
300 /* with nothing */
301 flags [ 0 ] = 0;
302 rc = alignment_flag ( flags, 0, field_width, precision, size_modifier, storage_class, args );
303 if ( rc != 0 )
304 return rc;
305
306 /* with space */
307 flags [ 0 ] = ' ';
308 flags [ 1 ] = 0;
309 rc = alignment_flag ( flags, 1, field_width, precision, size_modifier, storage_class, args );
310 if ( rc != 0 )
311 return rc;
312
313 /* with forces + */
314 flags [ 0 ] = '+';
315 flags [ 1 ] = 0;
316 rc = alignment_flag ( flags, 1, field_width, precision, size_modifier, storage_class, args );
317 if ( rc != 0 )
318 return rc;
319
320 /* with both */
321 flags [ 0 ] = ' ';
322 flags [ 1 ] = '+';
323 flags [ 2 ] = 0;
324 rc = alignment_flag ( flags, 2, field_width, precision, size_modifier, storage_class, args );
325
326 return rc;
327 }
328
329 /* apply field width */
do_field_width(int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)330 static rc_t do_field_width ( int32_t *field_width, int32_t *precision,
331 char size_modifier, char storage_class, va_list args)
332 {
333 rc_t rc;
334 uint32_t i;
335
336 rc = sign_flag ( NULL, precision, size_modifier, storage_class, args );
337
338 for ( i = 0 ; field_width [ i ] != -2 && rc == 0 ; ++ i )
339 rc = sign_flag ( & field_width [ i ], precision, size_modifier, storage_class, args );
340
341 return rc;
342 }
343
344 /* apply precision */
do_precision(int32_t * field_width,int32_t * precision,char size_modifier,char storage_class,va_list args)345 static rc_t do_precision ( int32_t *field_width, int32_t *precision,
346 char size_modifier, char storage_class, va_list args)
347 {
348 rc_t rc;
349 uint32_t i;
350
351 rc = do_field_width ( field_width, NULL, size_modifier, storage_class, args );
352
353 for ( i = 0 ; precision [ i ] != -2 && rc == 0; ++i )
354 rc = do_field_width ( field_width, & precision [ i ], size_modifier, storage_class, args );
355
356 return rc;
357 }
358
359
do_size_modifier(int32_t * field_width,int32_t * precision,const char * size_modifier,char storage_class,va_list args)360 static rc_t do_size_modifier ( int32_t *field_width, int32_t *precision,
361 const char *size_modifier, char storage_class, va_list args )
362 {
363 rc_t rc = 0;
364 uint32_t i;
365
366 for ( i = 0 ; size_modifier [ i ] != 0 && rc == 0; ++ i )
367 {
368 char modifier = size_modifier [ i ];
369 if ( modifier == ' ' )
370 modifier = 0;
371 rc = do_precision ( field_width, precision, modifier, storage_class, args );
372 }
373
374 return rc;
375 }
376
377
do_storage_class(int32_t * field_width,int32_t * precision,const char * size_modifier,const char * storage_class,va_list args)378 static rc_t do_storage_class ( int32_t *field_width, int32_t *precision,
379 const char *size_modifier, const char *storage_class, va_list args )
380 {
381 rc_t rc = 0;
382 uint32_t i;
383
384 for ( i = 0 ; storage_class [ i ] != 0 && rc == 0; ++ i )
385 rc = do_size_modifier ( field_width, precision, size_modifier, storage_class [ i ], args );
386
387 return rc;
388 }
389
390
make_initial_test(int32_t * field_width,int32_t * precision,const char * size_modifier,const char * storage_class,...)391 static rc_t make_initial_test ( int32_t *field_width, int32_t *precision,
392 const char *size_modifier, const char *storage_class, ... )
393 {
394 rc_t rc;
395
396 va_list args;
397 va_start ( args, storage_class );
398
399 rc = do_storage_class ( field_width, precision, size_modifier, storage_class, args );
400
401 va_end ( args );
402 return rc;
403 }
404
405 static
run(const char * progname)406 rc_t run ( const char *progname )
407 {
408 rc_t rc = 0;
409 int32_t i;
410
411 int32_t field_width [ ] = { 2, 5, 9, 10, -2 };
412 int32_t precision [ ] = { 1, 3, 8, 12, -2 };
413 char c [ ] = { "aA!@0{;>" };
414
415 int32_t ext_value [ ] = { -1, -2 };
416 int32_t randValue, randValue_2, randValue_3;
417 double randValue_f;
418
419
420 for ( i = 0 ; i < 8 ; ++ i )
421 {
422 /* create random number */
423 srand ( time ( NULL ) );
424
425
426 /* signed integer */
427 if ( rc == 0 )
428 {
429 randValue = rand ();
430 randValue_2 = rand () % 10;
431 randValue_3 = rand () % 5;
432
433 rc = make_initial_test ( field_width, precision, " ht", "di", randValue );
434 if ( rc == 0 )
435 rc = make_initial_test ( ext_value, precision, " ht", "di", randValue_2, randValue );
436 if ( rc == 0 )
437 rc = make_initial_test ( field_width, ext_value, " ht", "di", randValue_3, randValue );
438
439 if ( rc == 0 )
440 rc = make_initial_test ( field_width, precision, "l", "di", ( int64_t ) randValue );
441 if ( rc == 0 )
442 rc = make_initial_test ( ext_value, precision, "l", "di", randValue_2, ( int64_t ) randValue );
443 if ( rc == 0 )
444 rc = make_initial_test ( field_width, ext_value, "l", "di", randValue_3, ( int64_t ) randValue );
445 }
446
447 /* unsigned integer */
448 if ( rc == 0 )
449 {
450 rc = make_initial_test ( field_width, precision, " ht", "uxXo", randValue );
451 if ( rc == 0 )
452 rc = make_initial_test ( ext_value, precision, " ht", "uxXo", randValue_2, randValue );
453 if ( rc == 0 )
454 rc = make_initial_test ( field_width, ext_value, " ht", "uxXo", randValue_3, randValue );
455
456 if ( rc == 0 )
457 rc = make_initial_test ( field_width, precision, "l", "uxXo", ( uint64_t ) randValue );
458 if ( rc == 0 )
459 rc = make_initial_test ( ext_value, precision, "l", "uxXo", randValue_2, ( uint64_t )randValue );
460 if ( rc == 0 )
461 rc = make_initial_test ( field_width, ext_value, "l", "uxXo", randValue_3, ( uint64_t ) randValue );
462
463 if ( rc == 0 )
464 rc = make_initial_test ( field_width, precision, "z", "uxXo", ( size_t ) randValue );
465 if ( rc == 0 )
466 rc = make_initial_test ( ext_value, precision, "z", "uxXo", randValue_2, ( size_t ) randValue );
467 if ( rc == 0 )
468 rc = make_initial_test ( field_width, ext_value, "z", "uxXo", randValue_3, ( size_t ) randValue );
469 }
470
471 /* float */
472 if ( rc == 0 )
473 {
474
475 randValue_f = ( double ) randValue / ( ( randValue % 100 ) + 1 );
476
477 /*** could use some floating point random numbers here */
478 #if 0
479 rc = make_initial_test ( field_width, precision, " ", "feg", randValue );
480 if ( rc == 0 )
481 rc = make_initial_test ( ext_value, precision, " ", "feg", randValue_2, randValue );
482 if ( rc == 0 )
483 rc = make_initial_test ( field_width, ext_value, " ", "feg", randValue_3, randValue );
484 #endif
485
486 if ( rc == 0 )
487 rc = make_initial_test ( field_width, precision, " ", "feg", randValue_f );
488 if ( rc == 0 )
489 rc = make_initial_test ( ext_value, precision, " ", "feg", randValue_2, randValue_f );
490 if ( rc == 0 )
491 rc = make_initial_test ( field_width, ext_value, " ", "feg", randValue_3, randValue_f );
492 }
493
494 /* character */
495 if ( rc == 0 )
496 {
497 rc = make_initial_test ( field_width, precision, " ", "c", c [ i ] );
498 if ( rc == 0 )
499 rc = test_printf ( "I like 1 embedded % character", "I like %u embedded %% character", 1 );
500 }
501
502 /* text string */
503 if ( rc == 0 )
504 {
505 rc = make_initial_test ( field_width, precision, " ", "s", "Kurt is having a fit" );
506 #if !defined(__SunOS) && !defined(__sun__) && !defined(__DragonFly__)
507 /* Solaris printf doesn't cope with NULLs */
508 #if 0
509 /* The standard says this result is undefined, we shouldn't test for it, it is not consistent */
510 rc = make_initial_test ( field_width, precision, " ", "s", NULL );
511 #endif
512 #endif
513 rc = make_initial_test ( field_width, precision, " ", "s", "" );
514 rc = make_initial_test ( field_width, precision, " ", "s", "OK" );
515 rc = make_initial_test ( field_width, precision, " ", "s", "1234567890" );
516 rc = make_initial_test ( field_width, precision, " ", "s", "\"`~!@#$%^&*()-_=+[]{}|\\';:?/.,<>" );
517 }
518
519 }
520
521 /* hand written tests */
522
523 {
524
525 int8_t t [ ] = { -128, -67, 0, 4, 56, 100, 127 };
526 int16_t h [ ] = { -32768, -2546, -398, -89, 0, 34, 123, 5736, 32767 };
527 int32_t v [ ] = { -2147483648, -45287957, -100001, 45, 0, 106, 7234, 546963874, 2147483647 };
528
529 /*** naked integer literals have type "int" in C, meaning they
530 can't be more than 32 bits. By adding "L" to the end of the
531 literal numeral, the compiler will read them as "long int",
532 which is in fact 64 bits on this machine. on a 32-bit machine,
533 you need type "long long int".
534
535 you can make use of a pre-processor symbol to do this properly - I'll do it below.
536 */
537 int64_t l [ ] = { INT64_C(-9223372036854775807) - INT64_C(1), INT64_C(-67283678467328376), INT64_C(-2837640198), INT64_C(0), INT64_C(187267509872), INT64_C(9223372036854775807) };
538
539 /* d, i */
540
541 /* 8 bit */
542 test_printf ( "-000128", "%07:0td", t );
543 test_printf ( " -67" , "%5:1td", t );
544 test_printf ( "0" , "%:2td", t );
545 test_printf ( "4 " , "%-5:3td", t );
546 test_printf ( " 56" , "% .1:4td", t );
547 test_printf ( "100 " , "%-4.2:5td", t );
548 test_printf ( "127 " , "%-05:6td", t );
549 /* 16 bit */
550 test_printf ( "-32768" , "%.2:0hd", h );
551 test_printf ( "-2546 " , "%-07:1hd", h );
552 test_printf ( "-398" , "% :2hd", h );
553 test_printf ( "-0089" , "%05:3hd", h );
554 test_printf ( "0000" , "%04:4hd", h );
555 test_printf ( "+34" , "%+:5hd", h );
556 test_printf ( "+0123" , "% +05:6hd", h );
557 test_printf ( "5736 " , "%-05:7hd", h );
558 test_printf ( " 32767", "%10:8hd", h );
559 /* 32 bit */
560 test_printf ( "-2,147,483,648", "%,:0d", v );
561 test_printf ( "-0045287957" , "%011:1d", v );
562 test_printf ( "-100001 " , "%-8:2d", v );
563 test_printf ( "45" , "%0:3d", v );
564 test_printf ( "0" , "%,:4d", v );
565 test_printf ( "106" , "%:5d", v );
566 test_printf ( "0,007,234" , "%,09:6d", v );
567 test_printf ( "546963874" , "%.3:7d", v );
568 test_printf ( "2147483647" , "%10:8d", v );
569 /* 64 bit */
570 test_printf ( "-9223372036854775808" , "%:0ld", l );
571 test_printf ( "-67,283,678,467,328,376" , "%,:1ld", l );
572 test_printf ( "-2837640198 " , "%-20:2ld", l );
573 test_printf ( "+0" , "%+:3ld", l );
574 test_printf ( "00000000187267509872" , "%020:4ld", l );
575 test_printf ( "9223372036854775807" , "%.2:5ld", l );
576
577 }
578
579
580 {
581 /* uxXo */
582
583 uint8_t u_t [ ] = { 0, 128, 255};
584 uint16_t u_h [ ] = { 0, 128, 5378, 65535};
585 uint32_t u_v [ ] = { 0, 847, 7859, 376859, 86742874, 4294967295 };
586 uint64_t u_l [ ] = { 0, 178, 178364, 1783940987, 17836479208762, UINT64_C(18446744073709551615) };
587
588
589 /* 8 bit */
590 test_printf ( " 0", "%5:0tu", u_t );
591 test_printf ( "80" , "%:1tx", u_t );
592 test_printf ( "0x80" , "%#:1tx", u_t );
593 test_printf ( "377" , "%:2to", u_t );
594 test_printf ( "0377" , "%#:2to", u_t );
595 /* 16 bit */
596 test_printf ( "0" , "%#:0hX", u_h );
597 test_printf ( "00128" , "%05:1hu", u_h );
598 test_printf ( "0x1502" , "%-#3:2hx", u_h );
599 test_printf ( "000177777", "%#09:3ho", u_h );
600 /* 32 bit */
601 test_printf ( "00000" , "%05:0u", u_v );
602 test_printf ( "34f" , "%:1x", u_v );
603 test_printf ( "0X1EB3" , "%#6:2X", u_v );
604 test_printf ( "1340033" , "%:3o", u_v );
605 test_printf ( "86742874 ", "%-#15:4u", u_v );
606 test_printf ( "ffffffff" , "%0:5x", u_v );
607 /* 64 bit */
608 test_printf ( "0 " , "%-5:0lX", u_l );
609 test_printf ( "0262 " , "%#-5:1lo", u_l );
610 test_printf ( "178364" , "%.4:2lu", u_l );
611 test_printf ( "0x006a54c77b" , "%#012:3lx", u_l );
612 test_printf ( "1038E101DD3A" , "%.5:4lX", u_l );
613 test_printf ( "18446744073709551615", "%:5lu", u_l );
614
615 }
616
617
618 {
619 /* float */
620
621 float f [ ] = { -2.1474836, -45.287957, -10000.1, 0.45, 0, 1.06 };
622 double lf [ ] = { -9223372036854775808.0, -28.37640198 };
623
624 /* 32 bit */
625 test_printf ( " -2.15" , "%7.2:0hf", f );
626 test_printf ( "-00045.288" , "%010.3:1hf" , f );
627 test_printf ( "-10000.099609" , "%:2hf", f );
628 test_printf ( "0" , "%.0:3hf", f );
629 test_printf ( "0.000" , "%-5.3:4hf", f );
630 test_printf ( "1.060000 " , "%-012:5hf", f );
631 /* 64 bit */
632 test_printf ( "-9223372036854775808.000000" , "%:0f", lf );
633 test_printf ( "-28.37640198000000069101", "%2.20:1f", lf );
634 }
635
636
637
638 /* s */
639 test_printf ( "There are too many tests" , "%:s" , "There are too many tests" );
640 test_printf ( "a" , "%:6s" , "There are too many tests" );
641
642 test_printf ( "There" , "%:/5s" , "There are too many tests" );
643 test_printf ( "too m" , "%:*/5s" , 10, "There are too many tests" );
644 test_printf ( "There" , "%:/*s" , 5,"There are too many tests" );
645 test_printf ( " too many tests" , "%:9/16s", "There are too many tests" );
646 test_printf ( "s" , "%:$/5s" , "There are too many tests" );
647 test_printf ( "tests" , "%:19/$s", "There are too many tests" );
648
649 test_printf ( "There" , "%:0-4s", "There are too many tests" );
650 test_printf ( "There are too many tests" , "%:-s" , "There are too many tests" );
651 test_printf ( "too many tests" , "%:10-s", "There are too many tests" );
652 test_printf ( "There are" , "%:-8s" , "There are too many tests" );
653
654 test_printf ( "e are too many tests" , "%:*-s" , 4 , "There are too many tests" );
655 test_printf ( "e are too " , "%:4-*s", 13, "There are too many tests" );
656 test_printf ( "There are t" , "%:-*s" , 10, "There are too many tests" );
657 test_printf ( "ere a" , "%:*-6s", 2 , "There are too many tests" );
658
659 test_printf ( "s" , "%:$s" , "There are too many tests" );
660 test_printf ( "s" , "%:$-s" , "There are too many tests" );
661 test_printf ( "s" , "%:$-2s", "There are too many tests" );
662 test_printf ( "There are too many tests" , "%:-$s" , "There are too many tests" );
663 test_printf ( "re are too many tests" , "%:3-$s", "There are too many tests" );
664
665 /* with field width, precision, and flags */
666 test_printf ( "There are too many tests" , "%5:s" , "There are too many tests" );
667 test_printf ( " a" , "%20:6s" , "There are too many tests" );
668 test_printf ( "There " , "%-10:/5s" , "There are too many tests" );
669 test_printf ( " too m" , "%*:*/5s" , 10, 10, "There are too many tests" );
670 test_printf ( "The" , "%.3:/*s" , 5,"There are too many tests" );
671 test_printf ( " too" , "%*.4:9/16s" , 2, "There are too many tests" );
672
673 test_printf ( "There" , "%-:0-4s", "There are too many tests" );
674 test_printf ( "There are too many tests " , "%-30:-s", "There are too many tests" );
675 test_printf ( "too " , "%-10.4:10-s" , "There are too many tests" );
676 test_printf ( "There" , "%.*:-8s" , 5, "There are too many tests" );
677 test_printf ( "" , "%s", "" );
678
679 {
680 String S;
681 CONST_STRING ( & S, "My Bonnie lies over the ocean" );
682 test_printf ( "My Bo", "%:0-4S", & S );
683 }
684
685 {
686 String str1, str2, str3;
687 KSymbol *sym1, *sym2, *sym3;
688
689 CONST_STRING ( & str1, "outer" );
690 CONST_STRING ( & str2, "inner" );
691 CONST_STRING ( & str3, "leaf" );
692
693 KSymbolMake ( & sym1, & str1, 0, NULL );
694 KSymbolMake ( & sym2, & str2, 0, NULL );
695 KSymbolMake ( & sym3, & str3, 0, NULL );
696
697 sym2 -> dad = sym1;
698 sym3 -> dad = sym2;
699
700 test_printf ( "outer:inner:leaf", "%N", sym3 );
701 test_printf ( " outer:inner:leaf", "%20N", sym3 );
702 test_printf ( "outer:inner:leaf ", "%-20N", sym3 );
703 test_printf ( "outer:inner:leaf ", "%-20.2N", sym3 );
704
705 KSymbolWhack ( & sym3 -> n, NULL );
706 KSymbolWhack ( & sym2 -> n, NULL );
707 KSymbolWhack ( & sym1 -> n, NULL );
708 }
709
710 test_printf ( "version 1", "version %V", 0x1000000 );
711 test_printf ( "version ", "version %.V", 0x1000000 );
712 test_printf ( "version 1", "version %5V", 0x1000000 );
713 test_printf ( "version 1.2", "version %V", 0x1020000 );
714 test_printf ( "version 1.2", "version %5V", 0x1020000 );
715 test_printf ( "version 1.2.3", "version %V", 0x1020003 );
716 test_printf ( "version 1.2.3", "version %5V", 0x1020003 );
717 test_printf ( "version 1.2.3 ", "version %-6V", 0x1020003 );
718 test_printf ( "version 1.0", "version %.2V", 0x1000000 );
719 test_printf ( "version 1.0.0", "version %.3V", 0x1000000 );
720 test_printf ( "version 1.0.0", "version %.4V", 0x1000000 );
721 test_printf ( "version 1.0", "version %#.2V", 0x1000000 );
722
723 /* RC can't be tested due to embedded filename and lineno */
724 #if 0
725 rc = RC ( rcExe, rcString, rcFormatting, rcData, rcNoErr );
726 test_printf ( "?", "%#R", rc );
727 #endif
728
729 {
730 KTime t;
731 t . year = 2011;
732 t . month = 9;
733 t . day = 28;
734 t . weekday = 5;
735 t . tzoff = -5 * 60;
736 t . hour = 15;
737 t . minute = 2;
738 t . second = 16;
739 t . dst = true;
740
741 test_printf ( "3:02:16 PM", "%T", & t );
742 test_printf ( "03:02:16 PM", "%0T", & t );
743 test_printf ( "Fri Oct 29 2011 3:02:16 PM", "%lT", & t );
744 test_printf ( "Fri Oct 29 2011 3:02:16 PM -5", "%zT", & t );
745 test_printf ( "Oct 29 2011", "%hT", & t );
746 }
747 { /* insufficient buffer; here we have to bypass test_printf since we need a custom buffer size */
748 char buff[10];
749 size_t num_writ;
750 rc = string_printf ( buff, 1, &num_writ, "%s", "0123456789" );
751 if ( rc == 0 )
752 {
753 pLogErr ( klogErr, rc, "string_vprintf returned zero rc with insufficient buffer", "");
754 rc = -1;
755 }
756 else
757 {
758 rc = 0;
759 }
760 }
761
762 #if LINUX
763 test_printf ( "Success", "%!", 0 );
764 test_printf ( "Operation not permitted", "%!", 1 );
765 #endif
766
767 return rc;
768
769 }
770
771
772 /* Version EXTERN
773 * return 4-part version code: 0xMMmmrrrr, where
774 * MM = major release
775 * mm = minor release
776 * rrrr = bug-fix release
777 */
KAppVersion(void)778 ver_t CC KAppVersion ( void )
779 {
780 return 0;
781 }
782
783
784 /* Usage
785 * This function is called when the command line argument
786 * handling sees -? -h or --help
787 */
UsageSummary(const char * progname)788 rc_t CC UsageSummary ( const char *progname )
789 {
790 return KOutMsg (
791 "\n"
792 "Usage:\n"
793 " %s [Options]\n"
794 "\n"
795 "Summary:\n"
796 " Simple test of printf.\n"
797 , progname );
798 }
799
800 const char UsageDefaultName[] = "time-test";
801
Usage(const Args * args)802 rc_t CC Usage ( const Args *args )
803 {
804 const char * progname = UsageDefaultName;
805 const char * fullpath = UsageDefaultName;
806 rc_t rc;
807
808 if (args == NULL)
809 rc = RC (rcApp, rcArgv, rcAccessing, rcSelf, rcNull);
810 else
811 rc = ArgsProgram (args, &fullpath, &progname);
812
813 UsageSummary (progname);
814
815 KOutMsg ("Options:\n");
816
817 HelpOptionsStandard();
818
819 HelpVersion (fullpath, KAppVersion());
820
821 return rc;
822 }
823
824
825 /* KMain
826 */
KMain(int argc,char * argv[])827 rc_t CC KMain ( int argc, char *argv [] )
828 {
829 Args *args;
830 rc_t rc = ArgsMakeAndHandle ( & args, argc, argv, 0 );
831 if ( rc == 0 )
832 {
833 KConfigDisableUserSettings();
834 rc = run ( argv [ 0 ] );
835 ArgsWhack ( args );
836 }
837
838 return rc;
839 }
840