|
|
1.1 root 1: /* xpprintf.c */
2:
3: /* Deuce's vs[n]printf() replacement */
4:
1.1.1.2 ! root 5: /* $Id: xpprintf.c,v 1.36 2008/01/21 07:33:12 deuce Exp $ */
1.1 root 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);
1.1.1.2 ! root 389: *(size_t *)(format+sizeof(size_t))+=i-1;
1.1 root 390: }
391: else
392: *p=entry_buf[0];
393: p=format+offset;
394: *(size_t *)format=p-format;
395: return(format);
396: }
397: /* Skip width */
398: if(*p >= '0' && *p <= '9')
399: width=strtoul(p, NULL, 10);
400: while(*p >= '0' && *p <= '9')
401: *(fmt++)=*(p++);
402: /* Check for precision */
403: if(*p=='.') {
404: *(fmt++)=*(p++);
405: /*
406: * If the precision is '*' then the argument is an int which
407: * specifies the precision.
408: */
409: if(*p=='*') {
410: va_start(vars, type);
411: i=sprintf(entry_buf,"%d", va_arg(vars, int));
412: va_end(vars);
413: if(i > 1) {
414: /*
415: * We must calculate this before we go mucking about
416: * with format and p
417: */
418: offset2=p-format;
419: newbuf=(char *)realloc(format, format_len+i-1 /* -1 for the '*' that's already there */);
420: if(newbuf==NULL)
421: return(NULL);
422: format=newbuf;
423: p=format+offset2;
424: /*
425: * Move trailing end to make space... leaving the * where it
426: * is so it can be overwritten
427: */
428: memmove(p+i, p+1, format-p+format_len);
429: memcpy(p, entry_buf, i);
1.1.1.2 ! root 430: *(size_t *)(format+sizeof(size_t))+=i-1;
1.1 root 431: }
432: else
433: *p=entry_buf[0];
434: p=format+offset;
435: *(size_t *)format=p-format;
436: return(format);
437: }
438: /* Skip precision */
439: if(*p >= '0' && *p <= '9')
440: precision=strtoul(p, NULL, 10);
441: while(*p >= '0' && *p <= '9')
442: *(fmt++)=*(p++);
443: }
444:
445: /* Skip/Translate length modifiers */
446: /*
447: * ToDo: This could (should?) convert the standard ll modifier
448: * to the MSVC equivilant (I64 or something?)
449: * if you do this, the calculations using this_format_len will need
450: * rewriting.
451: */
452: switch(*p) {
453: case 'h':
454: modifier='h';
455: *(fmt++)=*(p++);
456: if(*p=='h') {
457: *(fmt++)=*(p++);
458: modifier+='h'<<8;
459: }
460: break;
461: case 'l':
462: modifier='h';
463: *(fmt++)=*(p++);
464: if(*p=='l') {
465: *(fmt++)=*(p++);
466: modifier+='l'<<8;
467: }
468: break;
469: case 'j':
470: modifier='j';
471: *(fmt++)=*(p++);
472: break;
473: case 't':
474: modifier='t';
475: *(fmt++)=*(p++);
476: break;
477: case 'z':
478: modifier='z';
479: *(fmt++)=*(p++);
480: break;
481: case 'L':
482: modifier='L';
483: *(fmt++)=*(p++);
484: break;
485: }
486:
487: /*
488: * The next char is now the type... if type is auto,
489: * set type to what it SHOULD be
490: */
491: if(type==XP_PRINTF_TYPE_AUTO || type & XP_PRINTF_CONVERT) {
492: switch(*p) {
493: /* INT types */
494: case 'd':
495: case 'i':
496: switch(modifier) {
497: case 'h'|'h'<<8:
498: correct_type=XP_PRINTF_TYPE_SCHAR;
499: break;
500: case 'h':
501: correct_type=XP_PRINTF_TYPE_SHORT;
502: break;
503: case 'l':
504: correct_type=XP_PRINTF_TYPE_LONG;
505: break;
506: #if defined(XP_PRINTF_TYPE_LONGLONG)
507: case 'l'|'l'<<8:
508: correct_type=XP_PRINTF_TYPE_LONGLONG;
509: break;
510: #endif
511: case 'j':
512: correct_type=XP_PRINTF_TYPE_INTMAX;
513: break;
514: case 't':
515: correct_type=XP_PRINTF_TYPE_PTRDIFF;
516: break;
517: case 'z':
518: /*
519: * ToDo this is a signed type of same size
520: * as size_t
521: */
522: correct_type=XP_PRINTF_TYPE_LONG;
523: break;
524: default:
525: correct_type=XP_PRINTF_TYPE_INT;
526: break;
527: }
528: break;
529: case 'o':
530: case 'u':
531: case 'x':
532: case 'X':
533: switch(modifier) {
534: case 'h'|'h'<<8:
535: correct_type=XP_PRINTF_TYPE_UCHAR;
536: break;
537: case 'h':
538: correct_type=XP_PRINTF_TYPE_USHORT;
539: break;
540: case 'l':
541: correct_type=XP_PRINTF_TYPE_ULONG;
542: break;
543: #if defined(XP_PRINTF_TYPE_LONGLONG)
544: case 'l'|'l'<<8:
545: correct_type=XP_PRINTF_TYPE_ULONGLONG;
546: break;
547: #endif
548: case 'j':
549: correct_type=XP_PRINTF_TYPE_UINTMAX;
550: break;
551: case 't':
552: /*
553: * ToDo this is an unsigned type of same size
554: * as ptrdiff_t
555: */
556: correct_type=XP_PRINTF_TYPE_ULONG;
557: break;
558: case 'z':
559: correct_type=XP_PRINTF_TYPE_SIZET;
560: break;
561: default:
562: correct_type=XP_PRINTF_TYPE_UINT;
563: break;
564: }
565: break;
566: case 'a':
567: case 'A':
568: case 'e':
569: case 'E':
570: case 'f':
571: case 'F':
572: case 'g':
573: case 'G':
574: switch(modifier) {
575: case 'L':
576: correct_type=XP_PRINTF_TYPE_LONGDOUBLE;
577: break;
578: case 'l':
579: default:
580: correct_type=XP_PRINTF_TYPE_DOUBLE;
581: break;
582: }
583: break;
584: case 'C':
585: /* ToDo wide chars... not yet supported */
586: correct_type=XP_PRINTF_TYPE_CHAR;
587: break;
588: case 'c':
589: switch(modifier) {
590: case 'l':
591: /* ToDo wide chars... not yet supported */
592: default:
593: correct_type=XP_PRINTF_TYPE_CHAR;
594: }
595: break;
596: case 'S':
597: /* ToDo wide chars... not yet supported */
598: correct_type=XP_PRINTF_TYPE_CHARP;
599: break;
600: case 's':
601: switch(modifier) {
602: case 'l':
603: /* ToDo wide chars... not yet supported */
604: default:
605: correct_type=XP_PRINTF_TYPE_CHARP;
606: }
607: break;
608: case 'p':
609: correct_type=XP_PRINTF_TYPE_VOIDP;
610: break;
611: }
612: }
613: if(type==XP_PRINTF_TYPE_AUTO)
614: type=correct_type;
615:
616: /*
617: * Copy the arg to the passed type.
618: */
619: va_start(vars, type);
620: switch(type & ~XP_PRINTF_CONVERT) {
621: case XP_PRINTF_TYPE_CHAR:
622: case XP_PRINTF_TYPE_INT: /* Also includes char and short */
623: i=va_arg(vars, int);
624: break;
625: case XP_PRINTF_TYPE_UINT: /* Also includes char and short */
626: /*
627: * ToDo: If it's a %c, and the value is 0, should it output [null]
628: * or should it terminate the string?
629: */
630: ui=va_arg(vars, unsigned int);
631: break;
632: case XP_PRINTF_TYPE_LONG:
633: l=va_arg(vars, long);
634: break;
635: case XP_PRINTF_TYPE_ULONG:
636: ul=va_arg(vars, unsigned long int);
637: break;
638: #if defined(XP_PRINTF_TYPE_LONGLONG)
639: case XP_PRINTF_TYPE_LONGLONG:
640: ll=va_arg(vars, long long int);
641: break;
642: case XP_PRINTF_TYPE_ULONGLONG:
643: ull=va_arg(vars, unsigned long long int);
644: break;
645: #endif
646: case XP_PRINTF_TYPE_CHARP:
647: cp=va_arg(vars, char*);
648: break;
649: case XP_PRINTF_TYPE_DOUBLE:
650: d=va_arg(vars, double);
651: break;
652: case XP_PRINTF_TYPE_LONGDOUBLE:
653: ld=va_arg(vars, long double);
654: break;
655: case XP_PRINTF_TYPE_VOIDP:
656: pntr=va_arg(vars, void*);
657: break;
658: case XP_PRINTF_TYPE_SIZET:
659: s=va_arg(vars, size_t);
660: break;
661: }
662: va_end(vars);
663:
664: if(type & XP_PRINTF_CONVERT) {
665: type=type & ~XP_PRINTF_CONVERT;
666: if(type != correct_type) {
667: switch(correct_type) {
668: case XP_PRINTF_TYPE_CHAR:
669: switch(type) {
670: case XP_PRINTF_TYPE_CHAR:
671: case XP_PRINTF_TYPE_INT:
672: i=i;
673: break;
674: case XP_PRINTF_TYPE_UINT:
675: i=ui;
676: break;
677: case XP_PRINTF_TYPE_LONG:
678: i=l;
679: break;
680: case XP_PRINTF_TYPE_ULONG:
681: i=ul;
682: break;
683: #if defined(XP_PRINTF_TYPE_LONGLONG)
684: case XP_PRINTF_TYPE_LONGLONG:
685: i=ll;
686: break;
687: case XP_PRINTF_TYPE_ULONGLONG:
688: i=ull;
689: break;
690: #endif
691: case XP_PRINTF_TYPE_CHARP:
692: if(cp)
693: i=*cp;
694: else
695: i=0;
696: break;
697: case XP_PRINTF_TYPE_DOUBLE:
698: i=(int)d;
699: break;
700: case XP_PRINTF_TYPE_LONGDOUBLE:
701: i=(int)ld;
702: break;
703: case XP_PRINTF_TYPE_VOIDP:
704: i=(int)pntr;
705: break;
706: case XP_PRINTF_TYPE_SIZET:
707: i=s;
708: break;
709: }
710: break;
711: case XP_PRINTF_TYPE_INT:
712: switch(type) {
713: case XP_PRINTF_TYPE_CHAR:
714: case XP_PRINTF_TYPE_INT:
715: i=i;
716: break;
717: case XP_PRINTF_TYPE_UINT:
718: i=ui;
719: break;
720: case XP_PRINTF_TYPE_LONG:
721: i=l;
722: break;
723: case XP_PRINTF_TYPE_ULONG:
724: i=ul;
725: break;
726: #if defined(XP_PRINTF_TYPE_LONGLONG)
727: case XP_PRINTF_TYPE_LONGLONG:
728: i=ll;
729: break;
730: case XP_PRINTF_TYPE_ULONGLONG:
731: i=ull;
732: break;
733: #endif
734: case XP_PRINTF_TYPE_CHARP:
735: i=strtol(cp, NULL, 0);
736: break;
737: case XP_PRINTF_TYPE_DOUBLE:
738: i=(int)d;
739: break;
740: case XP_PRINTF_TYPE_LONGDOUBLE:
741: i=(int)ld;
742: break;
743: case XP_PRINTF_TYPE_VOIDP:
744: i=(int)pntr;
745: break;
746: case XP_PRINTF_TYPE_SIZET:
747: i=s;
748: break;
749: }
750: break;
751: case XP_PRINTF_TYPE_UINT:
752: switch(type) {
753: case XP_PRINTF_TYPE_CHAR:
754: case XP_PRINTF_TYPE_INT:
755: ui=i;
756: break;
757: case XP_PRINTF_TYPE_UINT:
758: ui=ui;
759: break;
760: case XP_PRINTF_TYPE_LONG:
761: ui=l;
762: break;
763: case XP_PRINTF_TYPE_ULONG:
764: ui=ul;
765: break;
766: #if defined(XP_PRINTF_TYPE_LONGLONG)
767: case XP_PRINTF_TYPE_LONGLONG:
768: ui=ll;
769: break;
770: case XP_PRINTF_TYPE_ULONGLONG:
771: ui=ull;
772: break;
773: #endif
774: case XP_PRINTF_TYPE_CHARP:
775: ui=strtoul(cp, NULL, 0);
776: break;
777: case XP_PRINTF_TYPE_DOUBLE:
778: ui=(unsigned)d;
779: break;
780: case XP_PRINTF_TYPE_LONGDOUBLE:
781: ui=(unsigned)ld;
782: break;
783: case XP_PRINTF_TYPE_VOIDP:
784: ui=(unsigned int)pntr;
785: break;
786: case XP_PRINTF_TYPE_SIZET:
787: ui=s;
788: break;
789: }
790: break;
791: case XP_PRINTF_TYPE_LONG:
792: switch(type) {
793: case XP_PRINTF_TYPE_CHAR:
794: case XP_PRINTF_TYPE_INT:
795: l=i;
796: break;
797: case XP_PRINTF_TYPE_UINT:
798: l=ui;
799: break;
800: case XP_PRINTF_TYPE_LONG:
801: l=l;
802: break;
803: case XP_PRINTF_TYPE_ULONG:
804: l=ul;
805: break;
806: #if defined(XP_PRINTF_TYPE_LONGLONG)
807: case XP_PRINTF_TYPE_LONGLONG:
808: l=ll;
809: break;
810: case XP_PRINTF_TYPE_ULONGLONG:
811: l=ull;
812: break;
813: #endif
814: case XP_PRINTF_TYPE_CHARP:
815: l=strtol(cp, NULL, 0);
816: break;
817: case XP_PRINTF_TYPE_DOUBLE:
818: l=(long)d;
819: break;
820: case XP_PRINTF_TYPE_LONGDOUBLE:
821: l=(long)ld;
822: break;
823: case XP_PRINTF_TYPE_VOIDP:
824: l=(long)pntr;
825: break;
826: case XP_PRINTF_TYPE_SIZET:
827: l=s;
828: break;
829: }
830: break;
831: case XP_PRINTF_TYPE_ULONG:
832: switch(type) {
833: case XP_PRINTF_TYPE_CHAR:
834: case XP_PRINTF_TYPE_INT:
835: ul=i;
836: break;
837: case XP_PRINTF_TYPE_UINT:
838: ul=ui;
839: break;
840: case XP_PRINTF_TYPE_LONG:
841: ul=l;
842: break;
843: case XP_PRINTF_TYPE_ULONG:
844: ul=ul;
845: break;
846: #if defined(XP_PRINTF_TYPE_LONGLONG)
847: case XP_PRINTF_TYPE_LONGLONG:
848: ul=ll;
849: break;
850: case XP_PRINTF_TYPE_ULONGLONG:
851: ul=ull;
852: break;
853: #endif
854: case XP_PRINTF_TYPE_CHARP:
855: ul=strtoul(cp, NULL, 0);
856: break;
857: case XP_PRINTF_TYPE_DOUBLE:
858: ul=(unsigned long)d;
859: break;
860: case XP_PRINTF_TYPE_LONGDOUBLE:
861: ul=(unsigned long)ld;
862: break;
863: case XP_PRINTF_TYPE_VOIDP:
864: ul=(unsigned long)pntr;
865: break;
866: case XP_PRINTF_TYPE_SIZET:
867: ul=s;
868: break;
869: }
870: break;
871: #if defined(XP_PRINTF_TYPE_LONGLONG)
872: case XP_PRINTF_TYPE_LONGLONG:
873: switch(type) {
874: case XP_PRINTF_TYPE_CHAR:
875: case XP_PRINTF_TYPE_INT:
876: ll=i;
877: break;
878: case XP_PRINTF_TYPE_UINT:
879: ll=ui;
880: break;
881: case XP_PRINTF_TYPE_LONG:
882: ll=l;
883: break;
884: case XP_PRINTF_TYPE_ULONG:
885: ll=ul;
886: break;
887: case XP_PRINTF_TYPE_LONGLONG:
888: ll=ll;
889: break;
890: case XP_PRINTF_TYPE_ULONGLONG:
891: ll=ull;
892: break;
893: case XP_PRINTF_TYPE_CHARP:
894: ll=strtoll(cp, NULL, 0);
895: break;
896: case XP_PRINTF_TYPE_DOUBLE:
897: ll=d;
898: break;
899: case XP_PRINTF_TYPE_LONGDOUBLE:
900: ll=ld;
901: break;
902: case XP_PRINTF_TYPE_VOIDP:
903: ll=(long long)pntr;
904: break;
905: case XP_PRINTF_TYPE_SIZET:
906: ll=s;
907: break;
908: }
909: break;
910: case XP_PRINTF_TYPE_ULONGLONG:
911: switch(type) {
912: case XP_PRINTF_TYPE_CHAR:
913: case XP_PRINTF_TYPE_INT:
914: ull=i;
915: break;
916: case XP_PRINTF_TYPE_UINT:
917: ull=ui;
918: break;
919: case XP_PRINTF_TYPE_LONG:
920: ull=l;
921: break;
922: case XP_PRINTF_TYPE_ULONG:
923: ull=ul;
924: break;
925: case XP_PRINTF_TYPE_LONGLONG:
926: ull=ll;
927: break;
928: case XP_PRINTF_TYPE_ULONGLONG:
929: ull=ull;
930: break;
931: case XP_PRINTF_TYPE_CHARP:
932: ull=strtoull(cp, NULL, 0);
933: break;
934: case XP_PRINTF_TYPE_DOUBLE:
935: ull=d;
936: break;
937: case XP_PRINTF_TYPE_LONGDOUBLE:
938: ull=ld;
939: break;
940: case XP_PRINTF_TYPE_VOIDP:
941: ull=(unsigned long long int)pntr;
942: break;
943: case XP_PRINTF_TYPE_SIZET:
944: ull=s;
945: break;
946: }
947: break;
948: #endif
949: case XP_PRINTF_TYPE_CHARP:
950: num_str[0]=0;
951: switch(type) {
952: case XP_PRINTF_TYPE_CHAR:
953: case XP_PRINTF_TYPE_INT:
954: sprintf(num_str, "%d", i);
955: cp=num_str;
956: break;
957: case XP_PRINTF_TYPE_UINT:
958: sprintf(num_str, "%u", i);
959: cp=num_str;
960: break;
961: case XP_PRINTF_TYPE_LONG:
962: sprintf(num_str, "%ld", l);
963: cp=num_str;
964: break;
965: case XP_PRINTF_TYPE_ULONG:
966: sprintf(num_str, "%lu", ul);
967: cp=num_str;
968: break;
969: #if defined(XP_PRINTF_TYPE_LONGLONG)
970: case XP_PRINTF_TYPE_LONGLONG:
971: /* ToDo MSVC doesn't like this */
972: sprintf(num_str, "%lld", ll);
973: cp=num_str;
974: break;
975: case XP_PRINTF_TYPE_ULONGLONG:
976: /* ToDo MSVC doesn't like this */
977: sprintf(num_str, "%llu", ull);
978: cp=num_str;
979: break;
980: #endif
981: case XP_PRINTF_TYPE_CHARP:
982: cp=cp;
983: break;
984: case XP_PRINTF_TYPE_DOUBLE:
985: sprintf(num_str, "%f", d);
986: cp=num_str;
987: break;
988: case XP_PRINTF_TYPE_LONGDOUBLE:
1.1.1.2 ! root 989: sprintf(num_str, "%Lf", ld);
1.1 root 990: cp=num_str;
991: break;
992: case XP_PRINTF_TYPE_VOIDP:
993: /* ToDo: Or should this pretend it's a char *? */
994: sprintf(num_str, "%p", pntr);
995: cp=num_str;
996: break;
997: case XP_PRINTF_TYPE_SIZET:
998: sprintf(num_str, "%zu", s);
999: cp=num_str;
1000: break;
1001: }
1002: break;
1003: case XP_PRINTF_TYPE_DOUBLE:
1004: switch(type) {
1005: case XP_PRINTF_TYPE_CHAR:
1006: case XP_PRINTF_TYPE_INT:
1007: d=i;
1008: break;
1009: case XP_PRINTF_TYPE_UINT:
1010: d=ui;
1011: break;
1012: case XP_PRINTF_TYPE_LONG:
1013: d=l;
1014: break;
1015: case XP_PRINTF_TYPE_ULONG:
1016: d=ul;
1017: break;
1018: #if defined(XP_PRINTF_TYPE_LONGLONG)
1019: case XP_PRINTF_TYPE_LONGLONG:
1020: d=ll;
1021: break;
1022: case XP_PRINTF_TYPE_ULONGLONG:
1023: d=ull;
1024: break;
1025: #endif
1026: case XP_PRINTF_TYPE_CHARP:
1027: d=strtod(cp, NULL);
1028: break;
1029: case XP_PRINTF_TYPE_DOUBLE:
1030: d=d;
1031: break;
1032: case XP_PRINTF_TYPE_LONGDOUBLE:
1033: d=ld;
1034: break;
1035: case XP_PRINTF_TYPE_VOIDP:
1036: d=(double)((long int)pntr);
1037: break;
1038: case XP_PRINTF_TYPE_SIZET:
1039: d=s;
1040: break;
1041: }
1042: break;
1043: case XP_PRINTF_TYPE_LONGDOUBLE:
1044: switch(type) {
1045: case XP_PRINTF_TYPE_CHAR:
1046: case XP_PRINTF_TYPE_INT:
1047: ld=i;
1048: break;
1049: case XP_PRINTF_TYPE_UINT:
1050: ld=ui;
1051: break;
1052: case XP_PRINTF_TYPE_LONG:
1053: ld=l;
1054: break;
1055: case XP_PRINTF_TYPE_ULONG:
1056: ld=ul;
1057: break;
1058: #if defined(XP_PRINTF_TYPE_LONGLONG)
1059: case XP_PRINTF_TYPE_LONGLONG:
1060: ld=ll;
1061: break;
1062: case XP_PRINTF_TYPE_ULONGLONG:
1063: ld=ull;
1064: break;
1065: #endif
1066: case XP_PRINTF_TYPE_CHARP:
1067: /* strtold() isn't ubiquitous yet */
1068: ld=strtod(cp, NULL);
1069: break;
1070: case XP_PRINTF_TYPE_DOUBLE:
1071: ld=d;
1072: break;
1073: case XP_PRINTF_TYPE_LONGDOUBLE:
1074: ld=ld;
1075: break;
1076: case XP_PRINTF_TYPE_VOIDP:
1077: ld=(long double)((long int)pntr);
1078: break;
1079: case XP_PRINTF_TYPE_SIZET:
1080: ld=s;
1081: break;
1082: }
1083: break;
1084: case XP_PRINTF_TYPE_VOIDP:
1085: /* ToDo: this is nasty... */
1086: switch(type) {
1087: case XP_PRINTF_TYPE_CHAR:
1088: case XP_PRINTF_TYPE_INT:
1089: pntr=(void *)i;
1090: break;
1091: case XP_PRINTF_TYPE_UINT:
1092: pntr=(void *)ui;
1093: break;
1094: case XP_PRINTF_TYPE_LONG:
1095: pntr=(void *)l;
1096: break;
1097: case XP_PRINTF_TYPE_ULONG:
1098: pntr=(void *)ul;
1099: break;
1100: #if defined(XP_PRINTF_TYPE_LONGLONG)
1101: case XP_PRINTF_TYPE_LONGLONG:
1102: pntr=(void *)ll;
1103: break;
1104: case XP_PRINTF_TYPE_ULONGLONG:
1105: pntr=(void *)ull;
1106: break;
1107: #endif
1108: case XP_PRINTF_TYPE_CHARP:
1109: pntr=(void *)cp;
1110: break;
1111: case XP_PRINTF_TYPE_DOUBLE:
1112: pntr=(void *)(long int)d;
1113: break;
1114: case XP_PRINTF_TYPE_LONGDOUBLE:
1115: pntr=(void *)(long int)ld;
1116: break;
1117: case XP_PRINTF_TYPE_VOIDP:
1118: pntr=pntr;
1119: break;
1120: case XP_PRINTF_TYPE_SIZET:
1121: pntr=(void *)s;
1122: break;
1123: }
1124: break;
1125: case XP_PRINTF_TYPE_SIZET:
1126: switch(type) {
1127: case XP_PRINTF_TYPE_CHAR:
1128: case XP_PRINTF_TYPE_INT:
1129: s=i;
1130: break;
1131: case XP_PRINTF_TYPE_UINT:
1132: s=ui;
1133: break;
1134: case XP_PRINTF_TYPE_LONG:
1135: s=l;
1136: break;
1137: case XP_PRINTF_TYPE_ULONG:
1138: s=ul;
1139: break;
1140: #if defined(XP_PRINTF_TYPE_LONGLONG)
1141: case XP_PRINTF_TYPE_LONGLONG:
1142: s=ll;
1143: break;
1144: case XP_PRINTF_TYPE_ULONGLONG:
1145: s=ull;
1146: break;
1147: #endif
1148: case XP_PRINTF_TYPE_CHARP:
1149: s=strtol(cp, NULL, 0); /* was strtoll */
1150: break;
1151: case XP_PRINTF_TYPE_DOUBLE:
1152: s=(size_t)d;
1153: break;
1154: case XP_PRINTF_TYPE_LONGDOUBLE:
1155: s=(size_t)ld;
1156: break;
1157: case XP_PRINTF_TYPE_VOIDP:
1158: s=(size_t)pntr;
1159: break;
1160: case XP_PRINTF_TYPE_SIZET:
1161: s=s;
1162: break;
1163: }
1164: break;
1165: }
1166: type=correct_type;
1167: }
1168: }
1169:
1170: /* The next char is now the type... perform native sprintf() using it */
1171: *(fmt++)=*p;
1172: *fmt=0;
1173: entry=entry_buf;
1174: switch(type) {
1175: case XP_PRINTF_TYPE_CHAR: /* Also includes char and short */
1176: case XP_PRINTF_TYPE_INT: /* Also includes char and short */
1177: j=sprintf(entry, this_format, i);
1178: break;
1179: case XP_PRINTF_TYPE_UINT: /* Also includes char and short */
1180: j=sprintf(entry, this_format, ui);
1181: break;
1182: case XP_PRINTF_TYPE_LONG:
1183: j=sprintf(entry, this_format, l);
1184: break;
1185: case XP_PRINTF_TYPE_ULONG:
1186: j=sprintf(entry, this_format, ul);
1187: break;
1188: #if defined(XP_PRINTF_TYPE_LONGLONG)
1189: case XP_PRINTF_TYPE_LONGLONG:
1190: j=sprintf(entry, this_format, ll);
1191: break;
1192: case XP_PRINTF_TYPE_ULONGLONG:
1193: j=sprintf(entry, this_format, ull);
1194: break;
1195: #endif
1196: case XP_PRINTF_TYPE_CHARP:
1197: if(cp==NULL)
1198: j=sprintf(entry, this_format, "<null>");
1199: else {
1200: s=strlen(cp);
1201: if(s<width)
1202: s=width;
1203: if(s<precision)
1204: s=precision;
1205: if(s>=MAX_ARG_LEN)
1206: entry=(char *)alloca(s+1);
1207: if(entry==NULL)
1208: return(NULL);
1209: j=sprintf(entry, this_format, cp);
1210: }
1211: break;
1212: case XP_PRINTF_TYPE_DOUBLE:
1213: j=sprintf(entry, this_format, d);
1214: break;
1215: case XP_PRINTF_TYPE_LONGDOUBLE:
1216: j=sprintf(entry, this_format, ld);
1217: break;
1218: case XP_PRINTF_TYPE_VOIDP:
1219: j=sprintf(entry, this_format, pntr);
1220: break;
1221: case XP_PRINTF_TYPE_SIZET:
1222: j=sprintf(entry, this_format, s);
1223: break;
1224: }
1225:
1226: this_format_len=strlen(this_format);
1227: if(j>=0) {
1228: /*
1229: * This isn't necessary if it's already the right size,
1230: * or it's too large... this realloc() should only need to grow
1231: * the string.
1232: */
1233: if(format_len < (format_len-this_format_len+j)) {
1234: newbuf=(char *)realloc(format, format_len-this_format_len+j);
1235: if(newbuf==NULL)
1236: return(NULL);
1237: format=newbuf;
1238: }
1239: /* Move trailing end to make space */
1240: memmove(format+offset+j, format+offset+this_format_len, format_len-offset-this_format_len);
1241: memcpy(format+offset, entry, j);
1242: p=format+offset+j;
1243: }
1244: else
1245: p=format+offset+this_format_len;
1246:
1247: *(size_t *)(format+sizeof(size_t))=format_len-this_format_len+j-sizeof(size_t)*2-1;
1248:
1249: /*
1250: * Search for next non-%% separateor and set offset
1251: * to zero if none found for wrappers to know when
1252: * they're done.
1253: */
1254: for(; *p; p++) {
1255: if(*p=='%') {
1256: if(*(p+1) == '%')
1257: p++;
1258: else
1259: break;
1260: }
1261: }
1262: if(!*p)
1263: *(size_t *)format=0;
1264: else
1265: *(size_t *)format=p-format;
1266: return(format);
1267: }
1268:
1269: char *xp_asprintf_start(const char *format)
1270: {
1271: char *ret;
1272: char *p;
1273:
1274: ret=(char *)malloc(strlen(format)+1+((sizeof(size_t)*2)));
1275: if(ret==NULL)
1276: return(NULL);
1277: /* Place current offset at the start of the buffer */
1278: strcpy(ret+sizeof(size_t)*2,format);
1279: /* Place the current length after the offset */
1280: *(size_t *)(ret+sizeof(size_t))=strlen(format);
1281:
1282: /*
1283: * Find the next non %% format, leaving %% as it is
1284: */
1285: for(p=ret+sizeof(size_t)*2; *p; p++) {
1286: if(*p=='%') {
1287: if(*(p+1) == '%')
1288: p++;
1289: else
1290: break;
1291: }
1292: }
1293: if(!*p)
1294: *(size_t *)ret=0;
1295: else
1296: *(size_t *)ret=p-ret;
1297: return(ret);
1298: }
1299:
1300: char *xp_asprintf_end(char *format, size_t *lenret)
1301: {
1302: char *p;
1303: size_t len;
1304: size_t end_len;
1305:
1306: len=*(size_t *)(format+sizeof(size_t));
1307: end_len=len;
1308: for(p=format+sizeof(size_t)*2; len; p++, len--) {
1309: if(*p=='%' && *(p+1)=='%') {
1310: memmove(p, p+1, len--);
1311: end_len--;
1312: }
1313: }
1314: memmove(format, format+sizeof(size_t)*2, end_len+1);
1315: if(lenret)
1316: *lenret=end_len;
1317: return(format);
1318: }
1319:
1320: char *xp_vasprintf(const char *format, va_list va)
1321: {
1322: char *working;
1323: char *next;
1324: int type;
1325:
1326: next=xp_asprintf_start(format);
1327: if(next==NULL)
1328: return(NULL);
1329: working=next;
1330: while(*(size_t *)working) {
1331: type=xp_printf_get_type(working);
1332: switch(type) {
1333: case 0:
1334: free(working);
1335: return(NULL);
1336: case XP_PRINTF_TYPE_CHAR:
1337: case XP_PRINTF_TYPE_INT: /* Also includes char and short */
1338: next=xp_asprintf_next(working, type, va_arg(va, int));
1339: break;
1340: case XP_PRINTF_TYPE_UINT: /* Also includes char and short */
1341: next=xp_asprintf_next(working, type, va_arg(va, unsigned int));
1342: break;
1343: case XP_PRINTF_TYPE_LONG:
1344: next=xp_asprintf_next(working, type, va_arg(va, long));
1345: break;
1346: case XP_PRINTF_TYPE_ULONG:
1347: next=xp_asprintf_next(working, type, va_arg(va, unsigned long));
1348: break;
1349: #if defined(XP_PRINTF_TYPE_LONGLONG)
1350: case XP_PRINTF_TYPE_LONGLONG:
1351: next=xp_asprintf_next(working, type, va_arg(va, long long));
1352: break;
1353: case XP_PRINTF_TYPE_ULONGLONG:
1354: next=xp_asprintf_next(working, type, va_arg(va, unsigned long long));
1355: break;
1356: #endif
1357: case XP_PRINTF_TYPE_CHARP:
1358: next=xp_asprintf_next(working, type, va_arg(va, char *));
1359: break;
1360: case XP_PRINTF_TYPE_DOUBLE:
1361: next=xp_asprintf_next(working, type, va_arg(va, double));
1362: break;
1363: case XP_PRINTF_TYPE_LONGDOUBLE:
1364: next=xp_asprintf_next(working, type, va_arg(va, long double));
1365: break;
1366: case XP_PRINTF_TYPE_VOIDP:
1367: next=xp_asprintf_next(working, type, va_arg(va, void *));
1368: break;
1369: case XP_PRINTF_TYPE_SIZET:
1370: next=xp_asprintf_next(working, type, va_arg(va, size_t));
1371: break;
1372: }
1373: if(next==NULL) {
1374: free(working);
1375: return(NULL);
1376: }
1377: working=next;
1378: }
1379: next=xp_asprintf_end(working, NULL);
1380: if(next==NULL) {
1381: free(working);
1382: return(NULL);
1383: }
1384: return(next);
1385: }
1386:
1387: char *xp_asprintf(const char *format, ...)
1388: {
1389: char *ret;
1390: va_list va;
1391:
1392: va_start(va, format);
1393: ret=xp_vasprintf(format, va);
1394: va_end(va);
1395: return(ret);
1396: }
1397:
1398: #if defined(XP_PRINTF_TEST)
1399:
1400: int main(int argc, char *argv[])
1401: {
1402: char *format;
1403: char *p;
1404: int i,j;
1405: #if defined(XP_PRINTF_TYPE_LONGLONG)
1406: long long L;
1407: #endif
1408: long l;
1409: char *cp;
1410: double d;
1411: float f;
1412: long double D;
1413:
1414: p=xp_asprintf("%%%%%*.*f %% %%%ss %cs %*.*lu",3,3,123.123456789,"%llutesting%",32,3,3,123);
1415: printf("%s\n",p);
1416: free(p);
1417: if(argc < 2)
1418: return(1);
1419:
1420: format=argv[1];
1421: format=xp_asprintf_start(format);
1422: for(j=2; j<argc; j++) {
1423: switch(argv[j][0]) {
1424: case 'f':
1425: f=(float)atof(argv[j]+1);
1426: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_FLOAT,f);
1427: break;
1428: case 'd':
1429: d=atof(argv[j]+1);
1430: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_DOUBLE,d);
1431: break;
1432: case 'D':
1433: /* Don't know of a thing that converts a string to a long double */
1434: D=atof(argv[j]+1);
1435: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_LONGDOUBLE,D);
1436: break;
1437: case 'i':
1438: i=atoi(argv[j]+1);
1439: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_INT,i);
1440: break;
1441: case 'l':
1442: l=atol(argv[j]+1);
1443: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_LONG,l);
1444: break;
1445: #if defined(XP_PRINTF_TYPE_LONGLONG)
1446: case 'L':
1447: L=strtoll(argv[j]+1, NULL, 10);
1448: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_LONGLONG,L);
1449: break;
1450: #endif
1451: case 's':
1452: cp=argv[j]+1;
1453: p=xp_asprintf_next(format,XP_PRINTF_CONVERT|XP_PRINTF_TYPE_CHARP,cp);
1454: break;
1455: }
1456: if(p==NULL) {
1457: printf("Failed converting on item after %s\n",format);
1458: return(1);
1459: }
1460: format=p;
1461: }
1462: p=xp_asprintf_end(format, NULL);
1463: printf("At end, value is: '%s'\n",p);
1464: free(p);
1465: }
1466:
1467: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.