|
|
1.1 root 1: /* xpprintf.c */
2:
3: /* Deuce's vs[n]printf() replacement */
4:
5: /* $Id: xpprintf.c,v 1.34 2006/12/21 21:32:12 deuce Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This library is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU Lesser General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU Lesser General Public License for more details: lgpl.txt or *
18: * http://www.fsf.org/copyleft/lesser.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include <stdarg.h>
39: #include <stdio.h>
40: #include <string.h>
41: #include <stdlib.h>
42: #if defined(_WIN32)
43: #include <malloc.h> /* alloca() on Win32 */
44: #endif
45:
46: #include "xpprintf.h"
47:
48: /* MSVC Sucks - can't tell the required len of a *printf() */
49: #define MAX_ARG_LEN 1024 /* MAX_ARG_LEN is the maximum length
50: * possible as a result of a format
51: * which is not %s
52: */
53:
54: /* Maximum length of a format specifier including the % */
55: #define MAX_FORMAT_LEN 256
56:
57: void xp_asprintf_free(char *format)
58: {
59: free(format);
60: }
61:
62: int xp_printf_get_type(const char *format)
63: {
64: const char *p;
65: int modifier=0;
66: int j;
67: int correct_type;
68:
69: if(!*(size_t *)format)
70: return(0);
71: p=format+*(size_t *)format;
72: if(*p!='%')
73: return(0);
74: p++;
75:
76: /*
77: * Skip flags (zero or more)
78: */
79: j=1;
80: while(j) {
81: switch(*p) {
82: case '#':
83: p++;
84: break;
85: case '-':
86: p++;
87: break;
88: case '+':
89: p++;
90: break;
91: case ' ':
92: p++;
93: break;
94: case '0':
95: p++;
96: break;
97: case '\'':
98: p++;
99: break;
100: default:
101: j=0;
102: break;
103: }
104: }
105: if(*p=='*')
106: return(XP_PRINTF_TYPE_INT);
107: while(*p>= '0' && *p <= '9')
108: p++;
109: if(*p=='.') {
110: p++;
111: if(*p=='*')
112: return(XP_PRINTF_TYPE_INT);
113: }
114: while(*p>= '0' && *p <= '9')
115: p++;
116: switch(*p) {
117: case 'h':
118: modifier='h';
119: p++;
120: if(*p=='h') {
121: p++;
122: modifier+='h'<<8;
123: }
124: break;
125: case 'l':
126: modifier='h';
127: p++;
128: if(*p=='l') {
129: p++;
130: modifier+='l'<<8;
131: }
132: break;
133: case 'j':
134: modifier='j';
135: p++;
136: break;
137: case 't':
138: modifier='t';
139: p++;
140: break;
141: case 'z':
142: modifier='z';
143: p++;
144: break;
145: case 'L':
146: modifier='L';
147: p++;
148: break;
149: }
150: /*
151: * The next char is now the type... if type is auto,
152: * set type to what it SHOULD be
153: */
154: switch(*p) {
155: /* INT types */
156: case 'd':
157: case 'i':
158: switch(modifier) {
159: case 'h'|'h'<<8:
160: correct_type=XP_PRINTF_TYPE_SCHAR;
161: break;
162: case 'h':
163: correct_type=XP_PRINTF_TYPE_SHORT;
164: break;
165: case 'l':
166: correct_type=XP_PRINTF_TYPE_LONG;
167: break;
168: #if defined(XP_PRINTF_TYPE_ULONGLONG)
169: case 'l'|'l'<<8:
170: correct_type=XP_PRINTF_TYPE_LONGLONG;
171: break;
172: #endif
173: case 'j':
174: correct_type=XP_PRINTF_TYPE_INTMAX;
175: break;
176: case 't':
177: correct_type=XP_PRINTF_TYPE_PTRDIFF;
178: break;
179: case 'z':
180: /*
181: * ToDo this is a signed type of same size
182: * as size_t
183: */
184: correct_type=XP_PRINTF_TYPE_LONG;
185: break;
186: default:
187: correct_type=XP_PRINTF_TYPE_INT;
188: break;
189: }
190: break;
191: case 'o':
192: case 'u':
193: case 'x':
194: case 'X':
195: switch(modifier) {
196: case 'h'|'h'<<8:
197: correct_type=XP_PRINTF_TYPE_UCHAR;
198: break;
199: case 'h':
200: correct_type=XP_PRINTF_TYPE_USHORT;
201: break;
202: case 'l':
203: correct_type=XP_PRINTF_TYPE_ULONG;
204: break;
205: #if defined(XP_PRINTF_TYPE_ULONGLONG)
206: case 'l'|'l'<<8:
207: correct_type=XP_PRINTF_TYPE_ULONGLONG;
208: break;
209: #endif
210: case 'j':
211: correct_type=XP_PRINTF_TYPE_UINTMAX;
212: break;
213: case 't':
214: /*
215: * ToDo this is an unsigned type of same size
216: * as ptrdiff_t
217: */
218: correct_type=XP_PRINTF_TYPE_ULONG;
219: break;
220: case 'z':
221: correct_type=XP_PRINTF_TYPE_SIZET;
222: break;
223: default:
224: correct_type=XP_PRINTF_TYPE_UINT;
225: break;
226: }
227: break;
228: case 'a':
229: case 'A':
230: case 'e':
231: case 'E':
232: case 'f':
233: case 'F':
234: case 'g':
235: case 'G':
236: switch(modifier) {
237: case 'L':
238: correct_type=XP_PRINTF_TYPE_LONGDOUBLE;
239: break;
240: case 'l':
241: default:
242: correct_type=XP_PRINTF_TYPE_DOUBLE;
243: break;
244: }
245: break;
246: case 'C':
247: /* ToDo wide chars... not yet supported */
248: correct_type=XP_PRINTF_TYPE_CHAR;
249: break;
250: case 'c':
251: switch(modifier) {
252: case 'l':
253: /* ToDo wide chars... not yet supported */
254: default:
255: correct_type=XP_PRINTF_TYPE_CHAR;
256: }
257: break;
258: case 'S':
259: /* ToDo wide chars... not yet supported */
260: correct_type=XP_PRINTF_TYPE_CHARP;
261: break;
262: case 's':
263: switch(modifier) {
264: case 'l':
265: /* ToDo wide chars... not yet supported */
266: default:
267: correct_type=XP_PRINTF_TYPE_CHARP;
268: }
269: break;
270: case 'p':
271: correct_type=XP_PRINTF_TYPE_VOIDP;
272: break;
273: }
274: return(correct_type);
275: }
276:
277: /*
278: * Performs the next replacement in format using the variable
279: * specified as the only vararg which is currently the type
280: * specified in type (defined in xpprintf.h).
281: *
282: * Does not currently support the $ argument selector.
283: *
284: * Currently, the type is not overly usefull, but this could be used for
285: * automatic type conversions (ie: int to char *). Right now it just assures
286: * that the type passed to sprintf() is the type passed to
287: * xp_asprintf_next().
288: */
289: char *xp_asprintf_next(char *format, int type, ...)
290: {
291: va_list vars;
292: char *p;
293: char *newbuf;
294: int i,j;
295: unsigned int ui;
296: long int l;
297: unsigned long int ul;
298: #if defined(XP_PRINTF_TYPE_LONGLONG)
299: long long int ll;
300: unsigned long long int ull;
301: #endif
302: double d;
303: long double ld;
304: char* cp;
305: void* pntr;
306: size_t s;
307: unsigned long offset=0;
308: unsigned long offset2=0;
309: size_t format_len;
310: size_t this_format_len;
311: char entry_buf[MAX_ARG_LEN];
312: char *entry;
313: char this_format[MAX_FORMAT_LEN];
314: char *fmt;
315: int modifier=0;
316: int correct_type=0;
317: char num_str[128]; /* More than enough room for a 256-bit int */
318: size_t width=0;
319: size_t precision=0;
320:
321: /*
322: * Check if we're already done...
323: */
324: if(!*(size_t *) format)
325: return(format);
326:
327: p=format+*(size_t *)format;
328: offset=p-format;
329: format_len=*(size_t *)(format+sizeof(size_t))+sizeof(size_t)*2+1;
330: this_format[0]=0;
331: fmt=this_format;
332: *(fmt++)=*(p++);
333:
334: /*
335: * Skip flags (zero or more)
336: */
337: j=1;
338: while(j) {
339: switch(*p) {
340: case '#':
341: *(fmt++)=*(p++);
342: break;
343: case '-':
344: *(fmt++)=*(p++);
345: break;
346: case '+':
347: *(fmt++)=*(p++);
348: break;
349: case ' ':
350: *(fmt++)=*(p++);
351: break;
352: case '0':
353: *(fmt++)=*(p++);
354: break;
355: case '\'':
356: *(fmt++)=*(p++);
357: break;
358: default:
359: j=0;
360: break;
361: }
362: }
363:
364: /*
365: * If width is '*' then the argument is an int
366: * which specifies the width.
367: */
368: if(*p=='*') { /* The argument is this width */
369: va_start(vars, type);
370: i=sprintf(entry_buf,"%d", va_arg(vars, int));
371: va_end(vars);
372: if(i > 1) {
373: /*
374: * We must calculate this before we go mucking about
375: * with format and p
376: */
377: offset2=p-format;
378: newbuf=(char *)realloc(format, format_len+i-1 /* -1 for the '*' that's already there */);
379: if(newbuf==NULL)
380: return(NULL);
381: format=newbuf;
382: p=format+offset2;
383: /*
384: * Move trailing end to make space... leaving the * where it
385: * is so it can be overwritten
386: */
387: memmove(p+i, p+1, format-p+format_len);
388: memcpy(p, entry_buf, i);
389: }
390: else
391: *p=entry_buf[0];
392: p=format+offset;
393: *(size_t *)format=p-format;
394: return(format);
395: }
396: /* Skip width */
397: if(*p >= '0' && *p <= '9')
398: width=strtoul(p, NULL, 10);
399: while(*p >= '0' && *p <= '9')
400: *(fmt++)=*(p++);
401: /* Check for precision */
402: if(*p=='.') {
403: *(fmt++)=*(p++);
404: /*
405: * If the precision is '*' then the argument is an int which
406: * specifies the precision.
407: */
408: if(*p=='*') {
409: va_start(vars, type);
410: i=sprintf(entry_buf,"%d", va_arg(vars, int));
411: va_end(vars);
412: if(i > 1) {
413: /*
414: * We must calculate this before we go mucking about
415: * with format and p
416: */
417: offset2=p-format;
418: newbuf=(char *)realloc(format, format_len+i-1 /* -1 for the '*' that's already there */);
419: if(newbuf==NULL)
420: return(NULL);
421: format=newbuf;
422: p=format+offset2;
423: /*
424: * Move trailing end to make space... leaving the * where it
425: * is so it can be overwritten
426: */
427: memmove(p+i, p+1, format-p+format_len);
428: memcpy(p, entry_buf, i);
429: }
430: else
431: *p=entry_buf[0];
432: p=format+offset;
433: *(size_t *)format=p-format;
434: return(format);
435: }
436: /* Skip precision */
437: if(*p >= '0' && *p <= '9')
438: precision=strtoul(p, NULL, 10);
439: while(*p >= '0' && *p <= '9')
440: *(fmt++)=*(p++);
441: }
442:
443: /* Skip/Translate length modifiers */
444: /*
445: * ToDo: This could (should?) convert the standard ll modifier
446: * to the MSVC equivilant (I64 or something?)
447: * if you do this, the calculations using this_format_len will need
448: * rewriting.
449: */
450: switch(*p) {
451: case 'h':
452: modifier='h';
453: *(fmt++)=*(p++);
454: if(*p=='h') {
455: *(fmt++)=*(p++);
456: modifier+='h'<<8;
457: }
458: break;
459: case 'l':
460: modifier='h';
461: *(fmt++)=*(p++);
462: if(*p=='l') {
463: *(fmt++)=*(p++);
464: modifier+='l'<<8;
465: }
466: break;
467: case 'j':
468: modifier='j';
469: *(fmt++)=*(p++);
470: break;
471: case 't':
472: modifier='t';
473: *(fmt++)=*(p++);
474: break;
475: case 'z':
476: modifier='z';
477: *(fmt++)=*(p++);
478: break;
479: case 'L':
480: modifier='L';
481: *(fmt++)=*(p++);
482: break;
483: }
484:
485: /*
486: * The next char is now the type... if type is auto,
487: * set type to what it SHOULD be
488: */
489: if(type==XP_PRINTF_TYPE_AUTO || type & XP_PRINTF_CONVERT) {
490: switch(*p) {
491: /* INT types */
492: case 'd':
493: case 'i':
494: switch(modifier) {
495: case 'h'|'h'<<8:
496: correct_type=XP_PRINTF_TYPE_SCHAR;
497: break;
498: case 'h':
499: correct_type=XP_PRINTF_TYPE_SHORT;
500: break;
501: case 'l':
502: correct_type=XP_PRINTF_TYPE_LONG;
503: break;
504: #if defined(XP_PRINTF_TYPE_LONGLONG)
505: case 'l'|'l'<<8:
506: correct_type=XP_PRINTF_TYPE_LONGLONG;
507: break;
508: #endif
509: case 'j':
510: correct_type=XP_PRINTF_TYPE_INTMAX;
511: break;
512: case 't':
513: correct_type=XP_PRINTF_TYPE_PTRDIFF;
514: break;
515: case 'z':
516: /*
517: * ToDo this is a signed type of same size
518: * as size_t
519: */
520: correct_type=XP_PRINTF_TYPE_LONG;
521: break;
522: default:
523: correct_type=XP_PRINTF_TYPE_INT;
524: break;
525: }
526: break;
527: case 'o':
528: case 'u':
529: case 'x':
530: case 'X':
531: switch(modifier) {
532: case 'h'|'h'<<8:
533: correct_type=XP_PRINTF_TYPE_UCHAR;
534: break;
535: case 'h':
536: correct_type=XP_PRINTF_TYPE_USHORT;
537: break;
538: case 'l':
539: correct_type=XP_PRINTF_TYPE_ULONG;
540: break;
541: #if defined(XP_PRINTF_TYPE_LONGLONG)
542: case 'l'|'l'<<8:
543: correct_type=XP_PRINTF_TYPE_ULONGLONG;
544: break;
545: #endif
546: case 'j':
547: correct_type=XP_PRINTF_TYPE_UINTMAX;
548: break;
549: case 't':
550: /*
551: * ToDo this is an unsigned type of same size
552: * as ptrdiff_t
553: */
554: correct_type=XP_PRINTF_TYPE_ULONG;
555: break;
556: case 'z':
557: correct_type=XP_PRINTF_TYPE_SIZET;
558: break;
559: default:
560: correct_type=XP_PRINTF_TYPE_UINT;
561: break;
562: }
563: break;
564: case 'a':
565: case 'A':
566: case 'e':
567: case 'E':
568: case 'f':
569: case 'F':
570: case 'g':
571: case 'G':
572: switch(modifier) {
573: case 'L':
574: correct_type=XP_PRINTF_TYPE_LONGDOUBLE;
575: break;
576: case 'l':
577: default:
578: correct_type=XP_PRINTF_TYPE_DOUBLE;
579: break;
580: }
581: break;
582: case 'C':
583: /* ToDo wide chars... not yet supported */
584: correct_type=XP_PRINTF_TYPE_CHAR;
585: break;
586: case 'c':
587: switch(modifier) {
588: case 'l':
589: /* ToDo wide chars... not yet supported */
590: default:
591: correct_type=XP_PRINTF_TYPE_CHAR;
592: }
593: break;
594: case 'S':
595: /* ToDo wide chars... not yet supported */
596: correct_type=XP_PRINTF_TYPE_CHARP;
597: break;
598: case 's':
599: switch(modifier) {
600: case 'l':
601: /* ToDo wide chars... not yet supported */
602: default:
603: correct_type=XP_PRINTF_TYPE_CHARP;
604: }
605: break;
606: case 'p':
607: correct_type=XP_PRINTF_TYPE_VOIDP;
608: break;
609: }
610: }
611: if(type==XP_PRINTF_TYPE_AUTO)
612: type=correct_type;
613:
614: /*
615: * Copy the arg to the passed type.
616: */
617: va_start(vars, type);
618: switch(type & ~XP_PRINTF_CONVERT) {
619: case XP_PRINTF_TYPE_CHAR:
620: case XP_PRINTF_TYPE_INT: /* Also includes char and short */
621: i=va_arg(vars, int);
622: break;
623: case XP_PRINTF_TYPE_UINT: /* Also includes char and short */
624: /*
625: * ToDo: If it's a %c, and the value is 0, should it output [null]
626: * or should it terminate the string?
627: */
628: ui=va_arg(vars, unsigned int);
629: break;
630: case XP_PRINTF_TYPE_LONG:
631: l=va_arg(vars, long);
632: break;
633: case XP_PRINTF_TYPE_ULONG:
634: ul=va_arg(vars, unsigned long int);
635: break;
636: #if defined(XP_PRINTF_TYPE_LONGLONG)
637: case XP_PRINTF_TYPE_LONGLONG:
638: ll=va_arg(vars, long long int);
639: break;
640: case XP_PRINTF_TYPE_ULONGLONG:
641: ull=va_arg(vars, unsigned long long int);
642: break;
643: #endif
644: case XP_PRINTF_TYPE_CHARP:
645: cp=va_arg(vars, char*);
646: break;
647: case XP_PRINTF_TYPE_DOUBLE:
648: d=va_arg(vars, double);
649: break;
650: case XP_PRINTF_TYPE_LONGDOUBLE:
651: ld=va_arg(vars, long double);
652: break;
653: case XP_PRINTF_TYPE_VOIDP:
654: pntr=va_arg(vars, void*);
655: break;
656: case XP_PRINTF_TYPE_SIZET:
657: s=va_arg(vars, size_t);
658: break;
659: }
660: va_end(vars);
661:
662: if(type & XP_PRINTF_CONVERT) {
663: type=type & ~XP_PRINTF_CONVERT;
664: if(type != correct_type) {
665: switch(correct_type) {
666: case XP_PRINTF_TYPE_CHAR:
667: switch(type) {
668: case XP_PRINTF_TYPE_CHAR:
669: case XP_PRINTF_TYPE_INT:
670: i=i;
671: break;
672: case XP_PRINTF_TYPE_UINT:
673: i=ui;
674: break;
675: case XP_PRINTF_TYPE_LONG:
676: i=l;
677: break;
678: case XP_PRINTF_TYPE_ULONG:
679: i=ul;
680: break;
681: #if defined(XP_PRINTF_TYPE_LONGLONG)
682: case XP_PRINTF_TYPE_LONGLONG:
683: i=ll;
684: break;
685: case XP_PRINTF_TYPE_ULONGLONG:
686: i=ull;
687: break;
688: #endif
689: case XP_PRINTF_TYPE_CHARP:
690: if(cp)
691: i=*cp;
692: else
693: i=0;
694: break;
695: case XP_PRINTF_TYPE_DOUBLE:
696: i=(int)d;
697: break;
698: case XP_PRINTF_TYPE_LONGDOUBLE:
699: i=(int)ld;
700: break;
701: case XP_PRINTF_TYPE_VOIDP:
702: i=(int)pntr;
703: break;
704: case XP_PRINTF_TYPE_SIZET:
705: i=s;
706: break;
707: }
708: break;
709: case XP_PRINTF_TYPE_INT:
710: switch(type) {
711: case XP_PRINTF_TYPE_CHAR:
712: case XP_PRINTF_TYPE_INT:
713: i=i;
714: break;
715: case XP_PRINTF_TYPE_UINT:
716: i=ui;
717: break;
718: case XP_PRINTF_TYPE_LONG:
719: i=l;
720: break;
721: case XP_PRINTF_TYPE_ULONG:
722: i=ul;
723: break;
724: #if defined(XP_PRINTF_TYPE_LONGLONG)
725: case XP_PRINTF_TYPE_LONGLONG:
726: i=ll;
727: break;
728: case XP_PRINTF_TYPE_ULONGLONG:
729: i=ull;
730: break;
731: #endif
732: case XP_PRINTF_TYPE_CHARP:
733: i=strtol(cp, NULL, 0);
734: break;
735: case XP_PRINTF_TYPE_DOUBLE:
736: i=(int)d;
737: break;
738: case XP_PRINTF_TYPE_LONGDOUBLE:
739: i=(int)ld;
740: break;
741: case XP_PRINTF_TYPE_VOIDP:
742: i=(int)pntr;
743: break;
744: case XP_PRINTF_TYPE_SIZET:
745: i=s;
746: break;
747: }
748: break;
749: case XP_PRINTF_TYPE_UINT:
750: switch(type) {
751: case XP_PRINTF_TYPE_CHAR:
752: case XP_PRINTF_TYPE_INT:
753: ui=i;
754: break;
755: case XP_PRINTF_TYPE_UINT:
756: ui=ui;
757: break;
758: case XP_PRINTF_TYPE_LONG:
759: ui=l;
760: break;
761: case XP_PRINTF_TYPE_ULONG:
762: ui=ul;
763: break;
764: #if defined(XP_PRINTF_TYPE_LONGLONG)
765: case XP_PRINTF_TYPE_LONGLONG:
766: ui=ll;
767: break;
768: case XP_PRINTF_TYPE_ULONGLONG:
769: ui=ull;
770: break;
771: #endif
772: case XP_PRINTF_TYPE_CHARP:
773: ui=strtoul(cp, NULL, 0);
774: break;
775: case XP_PRINTF_TYPE_DOUBLE:
776: ui=(unsigned)d;
777: break;
778: case XP_PRINTF_TYPE_LONGDOUBLE:
779: ui=(unsigned)ld;
780: break;
781: case XP_PRINTF_TYPE_VOIDP:
782: ui=(unsigned int)pntr;
783: break;
784: case XP_PRINTF_TYPE_SIZET:
785: ui=s;
786: break;
787: }
788: break;
789: case XP_PRINTF_TYPE_LONG:
790: switch(type) {
791: case XP_PRINTF_TYPE_CHAR:
792: case XP_PRINTF_TYPE_INT:
793: l=i;
794: break;
795: case XP_PRINTF_TYPE_UINT:
796: l=ui;
797: break;
798: case XP_PRINTF_TYPE_LONG:
799: l=l;
800: break;
801: case XP_PRINTF_TYPE_ULONG:
802: l=ul;
803: break;
804: #if defined(XP_PRINTF_TYPE_LONGLONG)
805: case XP_PRINTF_TYPE_LONGLONG:
806: l=ll;
807: break;
808: case XP_PRINTF_TYPE_ULONGLONG:
809: l=ull;
810: break;
811: #endif
812: case XP_PRINTF_TYPE_CHARP:
813: l=strtol(cp, NULL, 0);
814: break;
815: case XP_PRINTF_TYPE_DOUBLE:
816: l=(long)d;
817: break;
818: case XP_PRINTF_TYPE_LONGDOUBLE:
819: l=(long)ld;
820: break;
821: case XP_PRINTF_TYPE_VOIDP:
822: l=(long)pntr;
823: break;
824: case XP_PRINTF_TYPE_SIZET:
825: l=s;
826: break;
827: }
828: break;
829: case XP_PRINTF_TYPE_ULONG:
830: switch(type) {
831: case XP_PRINTF_TYPE_CHAR:
832: case XP_PRINTF_TYPE_INT:
833: ul=i;
834: break;
835: case XP_PRINTF_TYPE_UINT:
836: ul=ui;
837: break;
838: case XP_PRINTF_TYPE_LONG:
839: ul=l;
840: break;
841: case XP_PRINTF_TYPE_ULONG:
842: ul=ul;
843: break;
844: #if defined(XP_PRINTF_TYPE_LONGLONG)
845: case XP_PRINTF_TYPE_LONGLONG:
846: ul=ll;
847: break;
848: case XP_PRINTF_TYPE_ULONGLONG:
849: ul=ull;
850: break;
851: #endif
852: case XP_PRINTF_TYPE_CHARP:
853: ul=strtoul(cp, NULL, 0);
854: break;
855: case XP_PRINTF_TYPE_DOUBLE:
856: ul=(unsigned long)d;
857: break;
858: case XP_PRINTF_TYPE_LONGDOUBLE:
859: ul=(unsigned long)ld;
860: break;
861: case XP_PRINTF_TYPE_VOIDP:
862: ul=(unsigned long)pntr;
863: break;
864: case XP_PRINTF_TYPE_SIZET:
865: ul=s;
866: break;
867: }
868: break;
869: #if defined(XP_PRINTF_TYPE_LONGLONG)
870: case XP_PRINTF_TYPE_LONGLONG:
871: switch(type) {
872: case XP_PRINTF_TYPE_CHAR:
873: case XP_PRINTF_TYPE_INT:
874: ll=i;
875: break;
876: case XP_PRINTF_TYPE_UINT:
877: ll=ui;
878: break;
879: case XP_PRINTF_TYPE_LONG:
880: ll=l;
881: break;
882: case XP_PRINTF_TYPE_ULONG:
883: ll=ul;
884: break;
885: case XP_PRINTF_TYPE_LONGLONG:
886: ll=ll;
887: break;
888: case XP_PRINTF_TYPE_ULONGLONG:
889: ll=ull;
890: break;
891: case XP_PRINTF_TYPE_CHARP:
892: ll=strtoll(cp, NULL, 0);
893: break;
894: case XP_PRINTF_TYPE_DOUBLE:
895: ll=d;
896: break;
897: case XP_PRINTF_TYPE_LONGDOUBLE:
898: ll=ld;
899: break;
900: case XP_PRINTF_TYPE_VOIDP:
901: ll=(long long)pntr;
902: break;
903: case XP_PRINTF_TYPE_SIZET:
904: ll=s;
905: break;
906: }
907: break;
908: case XP_PRINTF_TYPE_ULONGLONG:
909: switch(type) {
910: case XP_PRINTF_TYPE_CHAR:
911: case XP_PRINTF_TYPE_INT:
912: ull=i;
913: break;
914: case XP_PRINTF_TYPE_UINT:
915: ull=ui;
916: break;
917: case XP_PRINTF_TYPE_LONG:
918: ull=l;
919: break;
920: case XP_PRINTF_TYPE_ULONG:
921: ull=ul;
922: break;
923: case XP_PRINTF_TYPE_LONGLONG:
924: ull=ll;
925: break;
926: case XP_PRINTF_TYPE_ULONGLONG:
927: ull=ull;
928: break;
929: case XP_PRINTF_TYPE_CHARP:
930: ull=strtoull(cp, NULL, 0);
931: break;
932: case XP_PRINTF_TYPE_DOUBLE:
933: ull=d;
934: break;
935: case XP_PRINTF_TYPE_LONGDOUBLE:
936: ull=ld;
937: break;
938: case XP_PRINTF_TYPE_VOIDP:
939: ull=(unsigned long long int)pntr;
940: break;
941: case XP_PRINTF_TYPE_SIZET:
942: ull=s;
943: break;
944: }
945: break;
946: #endif
947: case XP_PRINTF_TYPE_CHARP:
948: num_str[0]=0;
949: switch(type) {
950: case XP_PRINTF_TYPE_CHAR:
951: case XP_PRINTF_TYPE_INT:
952: sprintf(num_str, "%d", i);
953: cp=num_str;
954: break;
955: case XP_PRINTF_TYPE_UINT:
956: sprintf(num_str, "%u", i);
957: cp=num_str;
958: break;
959: case XP_PRINTF_TYPE_LONG:
960: sprintf(num_str, "%ld", l);
961: cp=num_str;
962: break;
963: case XP_PRINTF_TYPE_ULONG:
964: sprintf(num_str, "%lu", ul);
965: cp=num_str;
966: break;
967: #if defined(XP_PRINTF_TYPE_LONGLONG)
968: case XP_PRINTF_TYPE_LONGLONG:
969: /* ToDo MSVC doesn't like this */
970: sprintf(num_str, "%lld", ll);
971: cp=num_str;
972: break;
973: case XP_PRINTF_TYPE_ULONGLONG:
974: /* ToDo MSVC doesn't like this */
975: sprintf(num_str, "%llu", ull);
976: cp=num_str;
977: break;
978: #endif
979: case XP_PRINTF_TYPE_CHARP:
980: cp=cp;
981: break;
982: case XP_PRINTF_TYPE_DOUBLE:
983: sprintf(num_str, "%f", d);
984: cp=num_str;
985: break;
986: case XP_PRINTF_TYPE_LONGDOUBLE:
987: sprintf(num_str, "%Lf", d);
988: cp=num_str;
989: break;
990: case XP_PRINTF_TYPE_VOIDP:
991: /* ToDo: Or should this pretend it's a char *? */
992: sprintf(num_str, "%p", pntr);
993: cp=num_str;
994: break;
995: case XP_PRINTF_TYPE_SIZET:
996: sprintf(num_str, "%zu", s);
997: cp=num_str;
998: break;
999: }
1000: break;
1001: case XP_PRINTF_TYPE_DOUBLE:
1002: switch(type) {
1003: case XP_PRINTF_TYPE_CHAR:
1004: case XP_PRINTF_TYPE_INT:
1005: d=i;
1006: break;
1007: case XP_PRINTF_TYPE_UINT:
1008: d=ui;
1009: break;
1010: case XP_PRINTF_TYPE_LONG:
1011: d=l;
1012: break;
1013: case XP_PRINTF_TYPE_ULONG:
1014: d=ul;
1015: break;
1016: #if defined(XP_PRINTF_TYPE_LONGLONG)
1017: case XP_PRINTF_TYPE_LONGLONG:
1018: d=ll;
1019: break;
1020: case XP_PRINTF_TYPE_ULONGLONG:
1021: d=ull;
1022: break;
1023: #endif
1024: case XP_PRINTF_TYPE_CHARP:
1025: d=strtod(cp, NULL);
1026: break;
1027: case XP_PRINTF_TYPE_DOUBLE:
1028: d=d;
1029: break;
1030: case XP_PRINTF_TYPE_LONGDOUBLE:
1031: d=ld;
1032: break;
1033: case XP_PRINTF_TYPE_VOIDP:
1034: d=(double)((long int)pntr);
1035: break;
1036: case XP_PRINTF_TYPE_SIZET:
1037: d=s;
1038: break;
1039: }
1040: break;
1041: case XP_PRINTF_TYPE_LONGDOUBLE:
1042: switch(type) {
1043: case XP_PRINTF_TYPE_CHAR:
1044: case XP_PRINTF_TYPE_INT:
1045: ld=i;
1046: break;
1047: case XP_PRINTF_TYPE_UINT:
1048: ld=ui;
1049: break;
1050: case XP_PRINTF_TYPE_LONG:
1051: ld=l;
1052: break;
1053: case XP_PRINTF_TYPE_ULONG:
1054: ld=ul;
1055: break;
1056: #if defined(XP_PRINTF_TYPE_LONGLONG)
1057: case XP_PRINTF_TYPE_LONGLONG:
1058: ld=ll;
1059: break;
1060: case XP_PRINTF_TYPE_ULONGLONG:
1061: ld=ull;
1062: break;
1063: #endif
1064: case XP_PRINTF_TYPE_CHARP:
1065: /* strtold() isn't ubiquitous yet */
1066: ld=strtod(cp, NULL);
1067: break;
1068: case XP_PRINTF_TYPE_DOUBLE:
1069: ld=d;
1070: break;
1071: case XP_PRINTF_TYPE_LONGDOUBLE:
1072: ld=ld;
1073: break;
1074: case XP_PRINTF_TYPE_VOIDP:
1075: ld=(long double)((long int)pntr);
1076: break;
1077: case XP_PRINTF_TYPE_SIZET:
1078: ld=s;
1079: break;
1080: }
1081: break;
1082: case XP_PRINTF_TYPE_VOIDP:
1083: /* ToDo: this is nasty... */
1084: switch(type) {
1085: case XP_PRINTF_TYPE_CHAR:
1086: case XP_PRINTF_TYPE_INT:
1087: pntr=(void *)i;
1088: break;
1089: case XP_PRINTF_TYPE_UINT:
1090: pntr=(void *)ui;
1091: break;
1092: case XP_PRINTF_TYPE_LONG:
1093: pntr=(void *)l;
1094: break;
1095: case XP_PRINTF_TYPE_ULONG:
1096: pntr=(void *)ul;
1097: break;
1098: #if defined(XP_PRINTF_TYPE_LONGLONG)
1099: case XP_PRINTF_TYPE_LONGLONG:
1100: pntr=(void *)ll;
1101: break;
1102: case XP_PRINTF_TYPE_ULONGLONG:
1103: pntr=(void *)ull;
1104: break;
1105: #endif
1106: case XP_PRINTF_TYPE_CHARP:
1107: pntr=(void *)cp;
1108: break;
1109: case XP_PRINTF_TYPE_DOUBLE:
1110: pntr=(void *)(long int)d;
1111: break;
1112: case XP_PRINTF_TYPE_LONGDOUBLE:
1113: pntr=(void *)(long int)ld;
1114: break;
1115: case XP_PRINTF_TYPE_VOIDP:
1116: pntr=pntr;
1117: break;
1118: case XP_PRINTF_TYPE_SIZET:
1119: pntr=(void *)s;
1120: break;
1121: }
1122: break;
1123: case XP_PRINTF_TYPE_SIZET:
1124: switch(type) {
1125: case XP_PRINTF_TYPE_CHAR:
1126: case XP_PRINTF_TYPE_INT:
1127: s=i;
1128: break;
1129: case XP_PRINTF_TYPE_UINT:
1130: s=ui;
1131: break;
1132: case XP_PRINTF_TYPE_LONG:
1133: s=l;
1134: break;
1135: case XP_PRINTF_TYPE_ULONG:
1136: s=ul;
1137: break;
1138: #if defined(XP_PRINTF_TYPE_LONGLONG)
1139: case XP_PRINTF_TYPE_LONGLONG:
1140: s=ll;
1141: break;
1142: case XP_PRINTF_TYPE_ULONGLONG:
1143: s=ull;
1144: break;
1145: #endif
1146: case XP_PRINTF_TYPE_CHARP:
1147: s=strtol(cp, NULL, 0); /* was strtoll */
1148: break;
1149: case XP_PRINTF_TYPE_DOUBLE:
1150: s=(size_t)d;
1151: break;
1152: case XP_PRINTF_TYPE_LONGDOUBLE:
1153: s=(size_t)ld;
1154: break;
1155: case XP_PRINTF_TYPE_VOIDP:
1156: s=(size_t)pntr;
1157: break;
1158: case XP_PRINTF_TYPE_SIZET:
1159: s=s;
1160: break;
1161: }
1162: break;
1163: }
1164: type=correct_type;
1165: }
1166: }
1167:
1168: /* The next char is now the type... perform native sprintf() using it */
1169: *(fmt++)=*p;
1170: *fmt=0;
1171: entry=entry_buf;
1172: switch(type) {
1173: case XP_PRINTF_TYPE_CHAR: /* Also includes char and short */
1174: case XP_PRINTF_TYPE_INT: /* Also includes char and short */
1175: j=sprintf(entry, this_format, i);
1176: break;
1177: case XP_PRINTF_TYPE_UINT: /* Also includes char and short */
1178: j=sprintf(entry, this_format, ui);
1179: break;
1180: case XP_PRINTF_TYPE_LONG:
1181: j=sprintf(entry, this_format, l);
1182: break;
1183: case XP_PRINTF_TYPE_ULONG:
1184: j=sprintf(entry, this_format, ul);
1185: break;
1186: #if defined(XP_PRINTF_TYPE_LONGLONG)
1187: case XP_PRINTF_TYPE_LONGLONG:
1188: j=sprintf(entry, this_format, ll);
1189: break;
1190: case XP_PRINTF_TYPE_ULONGLONG:
1191: j=sprintf(entry, this_format, ull);
1192: break;
1193: #endif
1194: case XP_PRINTF_TYPE_CHARP:
1195: if(cp==NULL)
1196: j=sprintf(entry, this_format, "<null>");
1197: else {
1198: s=strlen(cp);
1199: if(s<width)
1200: s=width;
1201: if(s<precision)
1202: s=precision;
1203: if(s>=MAX_ARG_LEN)
1204: entry=(char *)alloca(s+1);
1205: if(entry==NULL)
1206: return(NULL);
1207: j=sprintf(entry, this_format, cp);
1208: }
1209: break;
1210: case XP_PRINTF_TYPE_DOUBLE:
1211: j=sprintf(entry, this_format, d);
1212: break;
1213: case XP_PRINTF_TYPE_LONGDOUBLE:
1214: j=sprintf(entry, this_format, ld);
1215: break;
1216: case XP_PRINTF_TYPE_VOIDP:
1217: j=sprintf(entry, this_format, pntr);
1218: break;
1219: case XP_PRINTF_TYPE_SIZET:
1220: j=sprintf(entry, this_format, s);
1221: break;
1222: }
1223:
1224: this_format_len=strlen(this_format);
1225: if(j>=0) {
1226: /*
1227: * This isn't necessary if it's already the right size,
1228: * or it's too large... this realloc() should only need to grow
1229: * the string.
1230: */
1231: if(format_len < (format_len-this_format_len+j)) {
1232: newbuf=(char *)realloc(format, format_len-this_format_len+j);
1233: if(newbuf==NULL)
1234: return(NULL);
1235: format=newbuf;
1236: }
1237: /* Move trailing end to make space */
1238: memmove(format+offset+j, format+offset+this_format_len, format_len-offset-this_format_len);
1239: memcpy(format+offset, entry, j);
1240: p=format+offset+j;
1241: }
1242: else
1243: p=format+offset+this_format_len;
1244:
1245: *(size_t *)(format+sizeof(size_t))=format_len-this_format_len+j-sizeof(size_t)*2-1;
1246:
1247: /*
1248: * Search for next non-%% separateor and set offset
1249: * to zero if none found for wrappers to know when
1250: * they're done.
1251: */
1252: for(; *p; p++) {
1253: if(*p=='%') {
1254: if(*(p+1) == '%')
1255: p++;
1256: else
1257: break;
1258: }
1259: }
1260: if(!*p)
1261: *(size_t *)format=0;
1262: else
1263: *(size_t *)format=p-format;
1264: return(format);
1265: }
1266:
1267: char *xp_asprintf_start(const char *format)
1268: {
1269: char *ret;
1270: char *p;
1271:
1272: ret=(char *)malloc(strlen(format)+1+((sizeof(size_t)*2)));
1273: if(ret==NULL)
1274: return(NULL);
1275: /* Place current offset at the start of the buffer */
1276: strcpy(ret+sizeof(size_t)*2,format);
1277: /* Place the current length after the offset */
1278: *(size_t *)(ret+sizeof(size_t))=strlen(format);
1279:
1280: /*
1281: * Find the next non %% format, leaving %% as it is
1282: */
1283: for(p=ret+sizeof(size_t)*2; *p; p++) {
1284: if(*p=='%') {
1285: if(*(p+1) == '%')
1286: p++;
1287: else
1288: break;
1289: }
1290: }
1291: if(!*p)
1292: *(size_t *)ret=0;
1293: else
1294: *(size_t *)ret=p-ret;
1295: return(ret);
1296: }
1297:
1298: char *xp_asprintf_end(char *format, size_t *lenret)
1299: {
1300: char *p;
1301: size_t len;
1302: size_t end_len;
1303:
1304: len=*(size_t *)(format+sizeof(size_t));
1305: end_len=len;
1306: for(p=format+sizeof(size_t)*2; len; p++, len--) {
1307: if(*p=='%' && *(p+1)=='%') {
1308: memmove(p, p+1, len--);
1309: end_len--;
1310: }
1311: }
1312: memmove(format, format+sizeof(size_t)*2, end_len+1);
1313: if(lenret)
1314: *lenret=end_len;
1315: return(format);
1316: }
1317:
1318: char *xp_vasprintf(const char *format, va_list va)
1319: {
1320: char *working;
1321: char *next;
1322: int type;
1323:
1324: next=xp_asprintf_start(format);
1325: if(next==NULL)
1326: return(NULL);
1327: working=next;
1328: while(*(size_t *)working) {
1329: type=xp_printf_get_type(working);
1330: switch(type) {
1331: case 0:
1332: free(working);
1333: return(NULL);
1334: case XP_PRINTF_TYPE_CHAR:
1335: case XP_PRINTF_TYPE_INT: /* Also includes char and short */
1336: next=xp_asprintf_next(working, type, va_arg(va, int));
1337: break;
1338: case XP_PRINTF_TYPE_UINT: /* Also includes char and short */
1339: next=xp_asprintf_next(working, type, va_arg(va, unsigned int));
1340: break;
1341: case XP_PRINTF_TYPE_LONG:
1342: next=xp_asprintf_next(working, type, va_arg(va, long));
1343: break;
1344: case XP_PRINTF_TYPE_ULONG:
1345: next=xp_asprintf_next(working, type, va_arg(va, unsigned long));
1346: break;
1347: #if defined(XP_PRINTF_TYPE_LONGLONG)
1348: case XP_PRINTF_TYPE_LONGLONG:
1349: next=xp_asprintf_next(working, type, va_arg(va, long long));
1350: break;
1351: case XP_PRINTF_TYPE_ULONGLONG:
1352: next=xp_asprintf_next(working, type, va_arg(va, unsigned long long));
1353: break;
1354: #endif
1355: case XP_PRINTF_TYPE_CHARP:
1356: next=xp_asprintf_next(working, type, va_arg(va, char *));
1357: break;
1358: case XP_PRINTF_TYPE_DOUBLE:
1359: next=xp_asprintf_next(working, type, va_arg(va, double));
1360: break;
1361: case XP_PRINTF_TYPE_LONGDOUBLE:
1362: next=xp_asprintf_next(working, type, va_arg(va, long double));
1363: break;
1364: case XP_PRINTF_TYPE_VOIDP:
1365: next=xp_asprintf_next(working, type, va_arg(va, void *));
1366: break;
1367: case XP_PRINTF_TYPE_SIZET:
1368: next=xp_asprintf_next(working, type, va_arg(va, size_t));
1369: break;
1370: }
1371: if(next==NULL) {
1372: free(working);
1373: return(NULL);
1374: }
1375: working=next;
1376: }
1377: next=xp_asprintf_end(working, NULL);
1378: if(next==NULL) {
1379: free(working);
1380: return(NULL);
1381: }
1382: return(next);
1383: }
1384:
1385: char *xp_asprintf(const char *format, ...)
1386: {
1387: char *ret;
1388: va_list va;
1389:
1390: va_start(va, format);
1391: ret=xp_vasprintf(format, va);
1392: va_end(va);
1393: return(ret);
1394: }
1395:
1396: #if defined(XP_PRINTF_TEST)
1397:
1398: int main(int argc, char *argv[])
1399: {
1400: char *format;
1401: char *p;
1402: int i,j;
1403: #if defined(XP_PRINTF_TYPE_LONGLONG)
1404: long long L;
1405: #endif
1406: long l;
1407: char *cp;
1408: double d;
1409: float f;
1410: long double D;
1411:
1412: p=xp_asprintf("%%%%%*.*f %% %%%ss %cs %*.*lu",3,3,123.123456789,"%llutesting%",32,3,3,123);
1413: printf("%s\n",p);
1414: free(p);
1415: if(argc < 2)
1416: return(1);
1417:
1418: format=argv[1];
1419: format=xp_asprintf_start(format);
1420: for(j=2; j<argc; j++) {
1421: switch(argv[j][0]) {
1422: case 'f':
1423: f=(float)atof(argv[j]+1);
1424: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_FLOAT,f);
1425: break;
1426: case 'd':
1427: d=atof(argv[j]+1);
1428: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_DOUBLE,d);
1429: break;
1430: case 'D':
1431: /* Don't know of a thing that converts a string to a long double */
1432: D=atof(argv[j]+1);
1433: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_LONGDOUBLE,D);
1434: break;
1435: case 'i':
1436: i=atoi(argv[j]+1);
1437: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_INT,i);
1438: break;
1439: case 'l':
1440: l=atol(argv[j]+1);
1441: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_LONG,l);
1442: break;
1443: #if defined(XP_PRINTF_TYPE_LONGLONG)
1444: case 'L':
1445: L=strtoll(argv[j]+1, NULL, 10);
1446: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_LONGLONG,L);
1447: break;
1448: #endif
1449: case 's':
1450: cp=argv[j]+1;
1451: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_CHARP,cp);
1452: break;
1453: }
1454: if(p==NULL) {
1455: printf("Failed converting on item after %s\n",format);
1456: return(1);
1457: }
1458: format=p;
1459: }
1460: p=xp_asprintf_end(format, NULL);
1461: printf("At end, value is: '%s'\n",p);
1462: free(p);
1463: }
1464:
1465: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.