00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 #include <stdio.h>
00156 #include <string.h>
00157 #include <stdlib.h>
00158 #include <stdarg.h>
00159 #include <ctype.h>
00160 #include <limits.h>
00161
00162
00163
00164
00165 #if ! defined va_copy
00166 #if defined __va_copy
00167 #define va_copy __va_copy
00168 #else
00169 #define va_copy(dst, src) memcpy (&dst, &src, sizeof(va_list))
00170 #endif
00171 #endif
00172
00173 #if defined _16BIT_ || defined __TINY__ || defined __SMALL__ || defined __MEDIUM__ || defined __COMPACT__ || defined __LARGE__ || defined __HUGE__
00174 # define __DOS_16BIT__
00175 #endif
00176
00177
00178 #ifdef __DOS_16BIT__
00179 # define ALLOC_CHUNK 512
00180 # define ALLOC_SECURITY_MARGIN 100
00181 #else
00182 # define ALLOC_CHUNK 2048
00183 # define ALLOC_SECURITY_MARGIN 1024
00184 #endif
00185 #if ALLOC_CHUNK < ALLOC_SECURITY_MARGIN
00186 # error !!! ALLOC_CHUNK < ALLOC_SECURITY_MARGIN !!!
00187 #endif
00188
00189
00190
00191
00192
00193
00194 typedef struct {
00195 const char * src_string;
00196 char * buffer_base;
00197 char * dest_string;
00198 size_t buffer_len;
00199 size_t real_len;
00200 size_t pseudo_len;
00201 size_t maxlen;
00202 va_list vargs;
00203 char * sprintf_string;
00204 FILE * fprintf_file;
00205 char flavour;
00206 } xprintf_struct;
00207
00208
00209
00210
00211
00212
00213
00214 static
00215 int
00216 realloc_buff( xprintf_struct * s,
00217 size_t len
00218 )
00219 {
00220 char * ptr;
00221
00222 if ( len + ALLOC_SECURITY_MARGIN + s->real_len > s->buffer_len )
00223 {
00224 len += s->real_len + ALLOC_CHUNK;
00225 ptr = (char *)realloc( (void *)(s->buffer_base), len );
00226 if ( ptr == NULL )
00227 {
00228 s->buffer_base = NULL;
00229 return EOF;
00230 }
00231
00232 s->dest_string = ptr + (size_t)( s->dest_string - s->buffer_base );
00233 s->buffer_base = ptr;
00234 s->buffer_len = len;
00235
00236 (s->buffer_base)[(s->buffer_len)-1] = 1;
00237 }
00238
00239 return 0;
00240 }
00241
00242
00243
00244
00245
00246
00247 static
00248 int
00249 usual_char( xprintf_struct * s )
00250 {
00251 size_t len;
00252
00253 len = strcspn( s->src_string, "%" );
00254
00255
00256
00257 if ( realloc_buff(s,len) == EOF )
00258 return EOF;
00259
00260 memcpy( s->dest_string, s->src_string, len );
00261 s->src_string += len;
00262 s->dest_string += len;
00263 s->real_len += len;
00264 s->pseudo_len += len;
00265
00266 return 0;
00267 }
00268
00269
00270
00271
00272
00273
00274 static
00275 int
00276 print_it( xprintf_struct * s,
00277 size_t approx_len,
00278 const char * format_string,
00279 ...
00280 )
00281 {
00282 va_list varg;
00283 int vsprintf_len;
00284 size_t len;
00285
00286 if ( realloc_buff(s,approx_len) == EOF )
00287 return EOF;
00288
00289 va_start( varg, format_string );
00290 vsprintf_len = vsprintf( s->dest_string, format_string, varg );
00291 va_end( varg );
00292
00293 if ( (s->buffer_base)[(s->buffer_len)-1] != 1 )
00294 {
00295 fprintf( stderr, "ERROR in xnprintf library: overflow" );
00296 exit( -1 );
00297 }
00298
00299 if ( vsprintf_len == EOF )
00300 return EOF;
00301
00302 s->pseudo_len += vsprintf_len;
00303 len = strlen( s->dest_string );
00304 s->real_len += len;
00305 s->dest_string += len;
00306
00307 return 0;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 static
00323 int
00324 type_s( xprintf_struct * s,
00325 int width,
00326 int prec,
00327 const char * format_string,
00328 #ifdef __DOS_16BIT__
00329 const char far * arg_string,
00330 int modifier
00331 #else
00332 const char * arg_string
00333 #endif
00334 )
00335 {
00336 size_t string_len;
00337
00338 if ( arg_string == NULL )
00339 return print_it( s, 6, "(null)", 0 );
00340
00341
00342
00343 string_len = 0;
00344 while ( arg_string[string_len]!=0 && (unsigned int)prec!=string_len )
00345 string_len++;
00346
00347 if ( width != -1 )
00348 if ( string_len < (unsigned int)width )
00349 string_len = (unsigned int)width;
00350
00351 #ifdef __DOS_16BIT__
00352 switch( modifier )
00353 {
00354 case 'N': return print_it( s, string_len, format_string, (const char near*)arg_string );
00355 case 'F': return print_it( s, string_len, format_string, (const char far*)arg_string );
00356 }
00357
00358 return print_it( s, string_len, format_string, (const char*)arg_string );
00359 #else
00360 return print_it( s, string_len, format_string, arg_string );
00361 #endif
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372 static
00373 int
00374 getint( const char * * string )
00375 {
00376 int i;
00377
00378 i = 0;
00379
00380 while ( isdigit(**string) != 0 )
00381 {
00382 i = (i*10) + (**string-'0');
00383 (*string)++;
00384 }
00385
00386 if ( i<0 || i>32767 )
00387 i = 32767;
00388
00389 return i;
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 static
00406 int
00407 dispatch( xprintf_struct * s )
00408 {
00409 const char * initial_ptr;
00410 char format_string[24];
00411 char * format_ptr;
00412 int flag_plus, flag_minus, flag_space, flag_sharp, flag_zero;
00413 int width;
00414 int prec;
00415 int modifier;
00416 char type;
00417 int approx_width;
00418
00419
00420 #define SRCTXT (s->src_string)
00421 #define DESTTXT (s->dest_string)
00422
00423
00424 #define INCOHERENT() do {SRCTXT=initial_ptr; if (1) return 0;} while (0)
00425 #define INCOHERENT_TEST() do {if(*SRCTXT==0) INCOHERENT();} while (0)
00426
00427
00428 if ( *SRCTXT != '%' )
00429 return usual_char( s );
00430
00431
00432 SRCTXT++;
00433
00434
00435
00436 if ( *SRCTXT == '%' )
00437 {
00438 if ( realloc_buff(s,1) == EOF )
00439 return EOF;
00440 *DESTTXT = '%';
00441 DESTTXT++;
00442 SRCTXT++;
00443 (s->real_len)++;
00444 (s->pseudo_len)++;
00445 return 0;
00446 }
00447
00448
00449 initial_ptr = SRCTXT;
00450
00451
00452
00453 flag_plus = 0; flag_minus = 0; flag_space = 0;
00454 flag_sharp = 0; flag_zero = 0;
00455
00456 for ( ; ; SRCTXT++ )
00457 {
00458 if ( *SRCTXT == ' ' ) { flag_space = 1; continue; }
00459 if ( *SRCTXT == '+' ) { flag_plus = 1; continue; }
00460 if ( *SRCTXT == '-' ) { flag_minus = 1; continue; }
00461 if ( *SRCTXT == '#' ) { flag_sharp = 1; continue; }
00462 if ( *SRCTXT == '0' ) { flag_zero = 1; continue; }
00463 break;
00464 }
00465
00466 INCOHERENT_TEST();
00467
00468
00469 if ( *SRCTXT == '*' )
00470 {
00471 SRCTXT++;
00472 width = va_arg( s->vargs, int );
00473 if ( (unsigned int)width > 0x3fffU )
00474 width = 0x3fff;
00475 }
00476 else if ( isdigit(*SRCTXT) != 0 )
00477 {
00478 width = getint( &SRCTXT );
00479 }
00480 else
00481 width = -1;
00482
00483 INCOHERENT_TEST();
00484
00485
00486 if ( *SRCTXT == '.' )
00487 {
00488 SRCTXT++;
00489 if ( *SRCTXT == '*' )
00490 {
00491 prec = va_arg( s->vargs, int );
00492 if ( (unsigned int)prec >= 0x3fffU )
00493 prec = 0x3fff;
00494 }
00495 else
00496 {
00497 if ( isdigit(*SRCTXT) == 0 )
00498 INCOHERENT();
00499 prec = getint( &SRCTXT );
00500 }
00501 INCOHERENT_TEST();
00502 }
00503 else
00504 prec = -1;
00505
00506
00507 if ( *SRCTXT == 'L' || *SRCTXT == 'h' || *SRCTXT == 'l'
00508 #ifdef __DOS_16BIT__
00509 || *SRCTXT == 'F' || *SRCTXT == 'N'
00510 #endif
00511 )
00512 {
00513 modifier = *SRCTXT;
00514 SRCTXT++;
00515 if ( modifier=='l' && *SRCTXT=='l' )
00516 {
00517 SRCTXT++;
00518 modifier = 'L';
00519 }
00520 INCOHERENT_TEST();
00521 }
00522 else
00523 {
00524 modifier = -1;
00525 }
00526
00527
00528 type = *SRCTXT;
00529 if ( strchr("diouxXfegEGcspn",type) == NULL )
00530 INCOHERENT();
00531 SRCTXT++;
00532
00533
00534 format_string[0] = '%';
00535 format_ptr = &(format_string[1]);
00536
00537 if ( flag_plus != 0 ) { *format_ptr = '+'; format_ptr++; }
00538 if ( flag_minus != 0 ) { *format_ptr = '-'; format_ptr++; }
00539 if ( flag_space != 0 ) { *format_ptr = ' '; format_ptr++; }
00540 if ( flag_sharp != 0 ) { *format_ptr = '#'; format_ptr++; }
00541 if ( flag_zero != 0 ) { *format_ptr = '0'; format_ptr++; }
00542
00543 if ( width != -1 )
00544 {
00545 sprintf( format_ptr, "%i", width );
00546 format_ptr += strlen( format_ptr );
00547 }
00548
00549 if ( prec != -1 )
00550 {
00551 *format_ptr = '.';
00552 format_ptr++;
00553 sprintf( format_ptr, "%i", prec );
00554 format_ptr += strlen( format_ptr );
00555 }
00556
00557 if ( modifier != -1 )
00558 {
00559 *format_ptr = modifier;
00560 format_ptr++;
00561 }
00562
00563 *format_ptr = type;
00564 format_ptr++;
00565 *format_ptr = 0;
00566
00567
00568 approx_width = width + prec;
00569 if ( approx_width < 0 )
00570 approx_width = 0;
00571
00572 switch ( type )
00573 {
00574
00575 case 'd':
00576 case 'i':
00577 case 'o':
00578 case 'u':
00579 case 'x':
00580 case 'X': switch ( modifier )
00581 {
00582 case -1 : return print_it( s, approx_width, format_string, va_arg(s->vargs,int) );
00583 case 'l': return print_it( s, approx_width, format_string, va_arg(s->vargs,long int) );
00584 case 'h': return print_it( s, approx_width, format_string, va_arg(s->vargs, int) );
00585 default : INCOHERENT();
00586 }
00587
00588
00589 case 'c': if ( modifier != -1 )
00590 if ( print_it(s,approx_width,format_string,va_arg(s->vargs,int)) != EOF )
00591 INCOHERENT();
00592
00593
00594 case 'e':
00595 case 'f':
00596 case 'g':
00597 case 'E':
00598 case 'G': switch ( modifier )
00599 {
00600 case -1 :
00601 case 'l': return print_it( s, approx_width, format_string, va_arg(s->vargs,double) );
00602 case 'L': return print_it( s, approx_width, format_string, va_arg(s->vargs,long double) );
00603 default: INCOHERENT();
00604 }
00605
00606 #ifdef __DOS_16BIT__
00607
00608 case 's': switch ( modifier )
00609 {
00610 case -1 : return type_s( s, width, prec, format_string, (const char far*)va_arg(s->vargs,const char*), modifier );
00611 case 'N': return type_s( s, width, prec, format_string, (const char far*)va_arg(s->vargs,const char near*), modifier );
00612 case 'F': return type_s( s, width, prec, format_string, (const char far*)va_arg(s->vargs,const char far*), modifier );
00613 default : INCOHERENT();
00614 }
00615
00616
00617 case 'p': switch ( modifier )
00618 {
00619 case -1 : return print_it( s, approx_width, format_string, va_arg(s->vargs,void*) );
00620 case 'N': return print_it( s, approx_width, format_string, va_arg(s->vargs,void near*) );
00621 case 'F': return print_it( s, approx_width, format_string, va_arg(s->vargs,void far*) );
00622 default: INCOHERENT();
00623 }
00624
00625
00626 case 'n': {
00627 int far * p;
00628
00629 switch ( modifier )
00630 {
00631 case -1 : p = (int far*)va_arg( s->vargs, int* );
00632 break;
00633 case 'N': p = (int far*)va_arg( s->vargs, int near* );
00634 break;
00635 case 'F': p = (int far*)va_arg( s->vargs, int far* );
00636 break;
00637 default : INCOHERENT();
00638 }
00639
00640 if ( p != NULL )
00641 {
00642 *p = s->pseudo_len;
00643 return 0;
00644 }
00645 return EOF;
00646 }
00647
00648 #else
00649
00650 case 's': return type_s( s, width, prec, format_string, va_arg(s->vargs,const char*) );
00651
00652
00653 case 'p': if ( modifier == -1 )
00654 return print_it( s, approx_width, format_string, va_arg(s->vargs,void *) );
00655 INCOHERENT();
00656
00657
00658 case 'n': if ( modifier == -1 )
00659 {
00660 int * p;
00661 p = va_arg( s->vargs, int * );
00662 if ( p != NULL )
00663 {
00664 *p = s->pseudo_len;
00665 return 0;
00666 }
00667 return EOF;
00668 }
00669 INCOHERENT();
00670
00671 #endif
00672 }
00673
00674 INCOHERENT();
00675
00676 #undef INCOHERENT
00677 #undef INCOHERENT_TEST
00678 #undef SRCTXT
00679 #undef DESTTXT
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692 static
00693 int
00694 core( xprintf_struct * s )
00695 {
00696 size_t len, save_len;
00697 char * dummy_base;
00698
00699
00700 if ( (int)(s->maxlen) <= 0 )
00701 return EOF;
00702 s->maxlen--;
00703
00704
00705 if ( s->src_string == NULL )
00706 s->src_string = "(null)";
00707
00708
00709 s->buffer_base = NULL;
00710 s->buffer_len = 0;
00711 s->real_len = 0;
00712 s->pseudo_len = 0;
00713 if ( realloc_buff(s,0) == EOF )
00714 return EOF;
00715 s->dest_string = s->buffer_base;
00716
00717
00718 for (;;)
00719 {
00720
00721 if ( *(s->src_string) == 0 )
00722 {
00723 *(s->dest_string) = 0;
00724 len = s->real_len + 1;
00725 break;
00726 }
00727
00728 if ( dispatch(s) == EOF )
00729 goto free_EOF;
00730
00731
00732 if ( s->real_len >= s->maxlen )
00733 {
00734 (s->buffer_base)[s->maxlen] = 0;
00735 len = s->maxlen + 1;
00736 break;
00737 }
00738 }
00739
00740
00741 dummy_base = s->buffer_base;
00742 save_len = 0;
00743
00744
00745 switch ( s->flavour )
00746 {
00747
00748 case 's': memcpy( s->sprintf_string, s->buffer_base, len );
00749 break;
00750
00751
00752 case 'p': if ( puts(s->buffer_base) == EOF )
00753 goto free_EOF;
00754 break;
00755
00756
00757 case 'f' : if ( fwrite(s->buffer_base,1,len-1,s->fprintf_file) != len-1 )
00758 goto free_EOF;
00759 break;
00760
00761
00762 default : dummy_base = (s->buffer_base) + (s->real_len);
00763 save_len = s->real_len;
00764 }
00765
00766
00767
00768
00769
00770
00771 while( *(s->src_string) != 0 )
00772 {
00773 s->real_len = 0;
00774 s->dest_string = dummy_base;
00775 if ( dispatch(s) == EOF )
00776 goto free_EOF;
00777 }
00778
00779 if ( s->flavour == 'a' )
00780 {
00781 s->buffer_base = (char *)realloc( (void *)(s->buffer_base), save_len+1 );
00782 if ( s->buffer_base == NULL )
00783 return EOF;
00784 return s->pseudo_len;
00785 }
00786
00787 free( s->buffer_base );
00788 return s->pseudo_len;
00789
00790 free_EOF:
00791 if ( s->buffer_base != NULL )
00792 free( s->buffer_base );
00793 return EOF;
00794 }
00795
00796
00797 int
00798 _xn_nprintf( int maxlen,
00799 const char * format_string,
00800 ...
00801 )
00802 {
00803 xprintf_struct s;
00804 va_list vargs;
00805 int retval;
00806
00807 va_start( vargs, format_string );
00808
00809 s.src_string = format_string;
00810 s.maxlen = (size_t)maxlen;
00811
00812 va_copy(s.vargs, vargs);
00813 s.flavour = 'p';
00814
00815 retval = core( &s );
00816 va_end( vargs );
00817 return retval;
00818 }
00819
00820
00821 int
00822 _xn_vnprintf( int maxlen,
00823 const char * format_string,
00824 va_list vargs
00825 )
00826 {
00827 xprintf_struct s;
00828
00829 s.src_string = format_string;
00830 s.maxlen = (size_t)maxlen;
00831
00832 va_copy(s.vargs, vargs);
00833 s.flavour = 'p';
00834
00835 return core( &s );
00836 }
00837
00838
00839 int
00840 _xn_snprintf( char * dest_string,
00841 int maxlen,
00842 const char * format_string,
00843 ...
00844 )
00845 {
00846 xprintf_struct s;
00847 va_list vargs;
00848 int retval;
00849
00850 if ( dest_string == NULL )
00851 return EOF;
00852
00853 va_start( vargs, format_string );
00854
00855
00856 memset(&s, 0, sizeof(s));
00857
00858 s.src_string = format_string;
00859 s.maxlen = (size_t)maxlen;
00860
00861 va_copy(s.vargs, vargs);
00862 s.sprintf_string = dest_string;
00863 s.flavour = 's';
00864
00865 retval = core( &s );
00866 va_end( vargs );
00867 if ( retval == EOF )
00868 if ( maxlen > 0 )
00869 dest_string[0] = 0;
00870
00871 return retval;
00872 }
00873
00874
00875 int
00876 _xn_vsnprintf( char * dest_string,
00877 int maxlen,
00878 const char * format_string,
00879 va_list vargs
00880 )
00881 {
00882 xprintf_struct s;
00883 int retval;
00884
00885 if ( dest_string == NULL )
00886 return EOF;
00887
00888 s.src_string = format_string;
00889 s.maxlen = (size_t)maxlen;
00890
00891 va_copy(s.vargs, vargs);
00892 s.sprintf_string = dest_string;
00893 s.flavour = 's';
00894
00895 retval = core( &s );
00896 if ( retval == EOF )
00897 if ( maxlen > 0 )
00898 dest_string[0] = 0;
00899
00900 return retval;
00901 }
00902
00903
00904 int
00905 _xn_fnprintf( FILE * file,
00906 int maxlen,
00907 const char * format_string,
00908 ...
00909 )
00910 {
00911 xprintf_struct s;
00912 va_list vargs;
00913 int retval;
00914
00915 va_start( vargs, format_string );
00916
00917 s.src_string = format_string;
00918 s.maxlen = (size_t)maxlen;
00919
00920 va_copy(s.vargs, vargs);
00921 s.fprintf_file = file;
00922 s.flavour = 'f';
00923
00924 retval = core( &s );
00925 va_end( vargs );
00926 return retval;
00927 }
00928
00929
00930 int
00931 _xn_vfnprintf( FILE * file,
00932 int maxlen,
00933 const char * format_string,
00934 va_list vargs
00935 )
00936 {
00937 xprintf_struct s;
00938
00939 s.src_string = format_string;
00940 s.maxlen = (size_t)maxlen;
00941
00942 va_copy(s.vargs, vargs);
00943 s.fprintf_file = file;
00944 s.flavour = 'f';
00945
00946 return core( &s );
00947 }
00948
00949
00950 int
00951 _xn_asprintf( char ** ptr,
00952 const char * format_string,
00953 ...
00954 )
00955 {
00956 xprintf_struct s;
00957 va_list vargs;
00958 int retval;
00959
00960 va_start( vargs, format_string );
00961
00962 s.src_string = format_string;
00963
00964 va_copy(s.vargs, vargs);
00965 s.flavour = 'a';
00966 s.maxlen = (size_t)INT_MAX;
00967
00968 retval = core( &s );
00969 va_end( vargs );
00970 if ( retval != EOF )
00971 {
00972 *ptr = NULL;
00973 return EOF;
00974 }
00975
00976 *ptr = s.buffer_base;
00977 return retval;
00978 }
00979
00980
00981 int
00982 _xn_vasprintf( char ** ptr,
00983 const char * format_string,
00984 va_list vargs
00985 )
00986 {
00987 xprintf_struct s;
00988 int retval;
00989
00990
00991 memset(&s, 0x0, sizeof(s));
00992
00993 s.src_string = format_string;
00994
00995 va_copy(s.vargs, vargs);
00996 s.flavour = 'a';
00997 s.maxlen = (size_t)INT_MAX;
00998
00999 retval = core( &s );
01000 if ( retval == EOF )
01001 {
01002 *ptr = NULL;
01003 return EOF;
01004 }
01005
01006 *ptr = s.buffer_base;
01007 return retval;
01008 }
01009
01010
01011 int
01012 _xn_asnprintf( char ** ptr,
01013 int maxlen,
01014 const char * format_string,
01015 ...
01016 )
01017 {
01018 xprintf_struct s;
01019 va_list vargs;
01020 int retval;
01021
01022 va_start( vargs, format_string );
01023
01024 s.src_string = format_string;
01025
01026 va_copy(s.vargs, vargs);
01027 s.flavour = 'a';
01028 s.maxlen = (size_t)maxlen;
01029
01030 retval = core( &s );
01031 va_end( vargs );
01032 if ( retval != EOF )
01033 {
01034 *ptr = NULL;
01035 return EOF;
01036 }
01037
01038 *ptr = s.buffer_base;
01039 return retval;
01040 }
01041
01042
01043 int
01044 _xn_vasnprintf( char ** ptr,
01045 int maxlen,
01046 const char * format_string,
01047 va_list vargs
01048 )
01049 {
01050 xprintf_struct s;
01051 int retval;
01052
01053 s.src_string = format_string;
01054
01055 va_copy(s.vargs, vargs);
01056 s.flavour = 'a';
01057 s.maxlen = (size_t)maxlen;
01058
01059 retval = core( &s );
01060 if ( retval == EOF )
01061 {
01062 *ptr = NULL;
01063 return EOF;
01064 }
01065
01066 *ptr = s.buffer_base;
01067 return retval;
01068 }
01069
01070
01071