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