Clean a bit - to be continued...
[seven-1.x.git] / libseven / snprintf.c
blob03f4bdc91f0764c4d6f61b48c3ac4f5a4ed73c96
1 /*
2 * libString, Copyright (C) 1999 Patrick Alken
3 * This library comes with absolutely NO WARRANTY
5 * Should you choose to use and/or modify this source code, please
6 * do so under the terms of the GNU General Public License under which
7 * this library is distributed.
8 */
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <stdlib.h>
13 #include <sys/types.h>
14 #include <ctype.h>
15 #include "setup.h"
16 #include "sprintf_irc.h"
19 * This table is arranged in chronological order from 0-999,
20 * however the numbers are written backwards, so the number 100
21 * is expressed in this table as "001".
22 * It's purpose is to ensure fast conversions from integers to
23 * ASCII strings. When an integer variable is encountered, a
24 * simple hash algorithm is used to determine where to look
25 * in this array for the corresponding string.
26 * This outperforms continually dividing by 10 and using the
27 * digit obtained as a character, because we can now divide by
28 * 1000 and use the remainder directly, thus cutting down on
29 * the number of costly divisions needed. For an integer's worst
30 * case, 2 divisions are needed because it can only go up to
31 * 32767, so after 2 divisions by 1000, and some algebra, we will
32 * be left with 327 which we can get from this table. This is much
33 * better than the 5 divisions by 10 that we would need if we did
34 * it the conventional way. Of course, if we made this table go
35 * from 0-9999, only 1 division would be needed.
36 * Longs and unsigned ints of course, are another matter :-).
38 * Patrick Alken <wnder@underworld.net>
42 * Set this to the number of indices (numbers) in our table
44 #define TABLE_MAX 1000
46 static const char *IntTable[] = {
47 "000", "100", "200", "300", "400",
48 "500", "600", "700", "800", "900",
49 "010", "110", "210", "310", "410",
50 "510", "610", "710", "810", "910",
51 "020", "120", "220", "320", "420",
52 "520", "620", "720", "820", "920",
53 "030", "130", "230", "330", "430",
54 "530", "630", "730", "830", "930",
55 "040", "140", "240", "340", "440",
56 "540", "640", "740", "840", "940",
57 "050", "150", "250", "350", "450",
58 "550", "650", "750", "850", "950",
59 "060", "160", "260", "360", "460",
60 "560", "660", "760", "860", "960",
61 "070", "170", "270", "370", "470",
62 "570", "670", "770", "870", "970",
63 "080", "180", "280", "380", "480",
64 "580", "680", "780", "880", "980",
65 "090", "190", "290", "390", "490",
66 "590", "690", "790", "890", "990",
67 "001", "101", "201", "301", "401",
68 "501", "601", "701", "801", "901",
69 "011", "111", "211", "311", "411",
70 "511", "611", "711", "811", "911",
71 "021", "121", "221", "321", "421",
72 "521", "621", "721", "821", "921",
73 "031", "131", "231", "331", "431",
74 "531", "631", "731", "831", "931",
75 "041", "141", "241", "341", "441",
76 "541", "641", "741", "841", "941",
77 "051", "151", "251", "351", "451",
78 "551", "651", "751", "851", "951",
79 "061", "161", "261", "361", "461",
80 "561", "661", "761", "861", "961",
81 "071", "171", "271", "371", "471",
82 "571", "671", "771", "871", "971",
83 "081", "181", "281", "381", "481",
84 "581", "681", "781", "881", "981",
85 "091", "191", "291", "391", "491",
86 "591", "691", "791", "891", "991",
87 "002", "102", "202", "302", "402",
88 "502", "602", "702", "802", "902",
89 "012", "112", "212", "312", "412",
90 "512", "612", "712", "812", "912",
91 "022", "122", "222", "322", "422",
92 "522", "622", "722", "822", "922",
93 "032", "132", "232", "332", "432",
94 "532", "632", "732", "832", "932",
95 "042", "142", "242", "342", "442",
96 "542", "642", "742", "842", "942",
97 "052", "152", "252", "352", "452",
98 "552", "652", "752", "852", "952",
99 "062", "162", "262", "362", "462",
100 "562", "662", "762", "862", "962",
101 "072", "172", "272", "372", "472",
102 "572", "672", "772", "872", "972",
103 "082", "182", "282", "382", "482",
104 "582", "682", "782", "882", "982",
105 "092", "192", "292", "392", "492",
106 "592", "692", "792", "892", "992",
107 "003", "103", "203", "303", "403",
108 "503", "603", "703", "803", "903",
109 "013", "113", "213", "313", "413",
110 "513", "613", "713", "813", "913",
111 "023", "123", "223", "323", "423",
112 "523", "623", "723", "823", "923",
113 "033", "133", "233", "333", "433",
114 "533", "633", "733", "833", "933",
115 "043", "143", "243", "343", "443",
116 "543", "643", "743", "843", "943",
117 "053", "153", "253", "353", "453",
118 "553", "653", "753", "853", "953",
119 "063", "163", "263", "363", "463",
120 "563", "663", "763", "863", "963",
121 "073", "173", "273", "373", "473",
122 "573", "673", "773", "873", "973",
123 "083", "183", "283", "383", "483",
124 "583", "683", "783", "883", "983",
125 "093", "193", "293", "393", "493",
126 "593", "693", "793", "893", "993",
127 "004", "104", "204", "304", "404",
128 "504", "604", "704", "804", "904",
129 "014", "114", "214", "314", "414",
130 "514", "614", "714", "814", "914",
131 "024", "124", "224", "324", "424",
132 "524", "624", "724", "824", "924",
133 "034", "134", "234", "334", "434",
134 "534", "634", "734", "834", "934",
135 "044", "144", "244", "344", "444",
136 "544", "644", "744", "844", "944",
137 "054", "154", "254", "354", "454",
138 "554", "654", "754", "854", "954",
139 "064", "164", "264", "364", "464",
140 "564", "664", "764", "864", "964",
141 "074", "174", "274", "374", "474",
142 "574", "674", "774", "874", "974",
143 "084", "184", "284", "384", "484",
144 "584", "684", "784", "884", "984",
145 "094", "194", "294", "394", "494",
146 "594", "694", "794", "894", "994",
147 "005", "105", "205", "305", "405",
148 "505", "605", "705", "805", "905",
149 "015", "115", "215", "315", "415",
150 "515", "615", "715", "815", "915",
151 "025", "125", "225", "325", "425",
152 "525", "625", "725", "825", "925",
153 "035", "135", "235", "335", "435",
154 "535", "635", "735", "835", "935",
155 "045", "145", "245", "345", "445",
156 "545", "645", "745", "845", "945",
157 "055", "155", "255", "355", "455",
158 "555", "655", "755", "855", "955",
159 "065", "165", "265", "365", "465",
160 "565", "665", "765", "865", "965",
161 "075", "175", "275", "375", "475",
162 "575", "675", "775", "875", "975",
163 "085", "185", "285", "385", "485",
164 "585", "685", "785", "885", "985",
165 "095", "195", "295", "395", "495",
166 "595", "695", "795", "895", "995",
167 "006", "106", "206", "306", "406",
168 "506", "606", "706", "806", "906",
169 "016", "116", "216", "316", "416",
170 "516", "616", "716", "816", "916",
171 "026", "126", "226", "326", "426",
172 "526", "626", "726", "826", "926",
173 "036", "136", "236", "336", "436",
174 "536", "636", "736", "836", "936",
175 "046", "146", "246", "346", "446",
176 "546", "646", "746", "846", "946",
177 "056", "156", "256", "356", "456",
178 "556", "656", "756", "856", "956",
179 "066", "166", "266", "366", "466",
180 "566", "666", "766", "866", "966",
181 "076", "176", "276", "376", "476",
182 "576", "676", "776", "876", "976",
183 "086", "186", "286", "386", "486",
184 "586", "686", "786", "886", "986",
185 "096", "196", "296", "396", "496",
186 "596", "696", "796", "896", "996",
187 "007", "107", "207", "307", "407",
188 "507", "607", "707", "807", "907",
189 "017", "117", "217", "317", "417",
190 "517", "617", "717", "817", "917",
191 "027", "127", "227", "327", "427",
192 "527", "627", "727", "827", "927",
193 "037", "137", "237", "337", "437",
194 "537", "637", "737", "837", "937",
195 "047", "147", "247", "347", "447",
196 "547", "647", "747", "847", "947",
197 "057", "157", "257", "357", "457",
198 "557", "657", "757", "857", "957",
199 "067", "167", "267", "367", "467",
200 "567", "667", "767", "867", "967",
201 "077", "177", "277", "377", "477",
202 "577", "677", "777", "877", "977",
203 "087", "187", "287", "387", "487",
204 "587", "687", "787", "887", "987",
205 "097", "197", "297", "397", "497",
206 "597", "697", "797", "897", "997",
207 "008", "108", "208", "308", "408",
208 "508", "608", "708", "808", "908",
209 "018", "118", "218", "318", "418",
210 "518", "618", "718", "818", "918",
211 "028", "128", "228", "328", "428",
212 "528", "628", "728", "828", "928",
213 "038", "138", "238", "338", "438",
214 "538", "638", "738", "838", "938",
215 "048", "148", "248", "348", "448",
216 "548", "648", "748", "848", "948",
217 "058", "158", "258", "358", "458",
218 "558", "658", "758", "858", "958",
219 "068", "168", "268", "368", "468",
220 "568", "668", "768", "868", "968",
221 "078", "178", "278", "378", "478",
222 "578", "678", "778", "878", "978",
223 "088", "188", "288", "388", "488",
224 "588", "688", "788", "888", "988",
225 "098", "198", "298", "398", "498",
226 "598", "698", "798", "898", "998",
227 "009", "109", "209", "309", "409",
228 "509", "609", "709", "809", "909",
229 "019", "119", "219", "319", "419",
230 "519", "619", "719", "819", "919",
231 "029", "129", "229", "329", "429",
232 "529", "629", "729", "829", "929",
233 "039", "139", "239", "339", "439",
234 "539", "639", "739", "839", "939",
235 "049", "149", "249", "349", "449",
236 "549", "649", "749", "849", "949",
237 "059", "159", "259", "359", "459",
238 "559", "659", "759", "859", "959",
239 "069", "169", "269", "369", "469",
240 "569", "669", "769", "869", "969",
241 "079", "179", "279", "379", "479",
242 "579", "679", "779", "879", "979",
243 "089", "189", "289", "389", "489",
244 "589", "689", "789", "889", "989",
245 "099", "199", "299", "399", "499",
246 "599", "699", "799", "899", "999"
250 * Since we calculate the right-most digits for %d %u etc first,
251 * we need a temporary buffer to store them in until we get
252 * to the left-most digits
255 #define TEMPBUF_MAX 20
257 static char TempBuffer[TEMPBUF_MAX];
260 vSnprintf()
261 Backend to Snprintf() - performs the construction of 'dest'
262 using the string 'format' and the given arguments. Also makes sure
263 not more than 'bytes' characters are copied to 'dest'
265 We always allow room for a terminating \0 character, so at most,
266 bytes - 1 characters will be written to dest.
268 Return: Number of characters written, NOT including the terminating
269 \0 character which is *always* placed at the end of the string
271 NOTE: This function handles the following flags only:
272 %s %d %c %u %ld %lu
273 In addition, this function performs *NO* precision, padding,
274 or width formatting. If it receives an unknown % character,
275 it will call vsprintf() to complete the remainder of the
276 string.
280 ircvsnprintf(char *dest, const size_t bytes, const char *format, va_list args)
282 char ch;
283 int written = 0; /* bytes written so far */
284 int maxbytes = bytes - 1;
286 while ((ch = *format++) && (written < maxbytes))
288 if(ch == '%')
291 * Advance past the %
293 ch = *format++;
296 * Put the most common cases first - %s %d etc
299 if(ch == 's')
301 const char *str = va_arg(args, const char *);
303 while ((*dest = *str))
305 ++dest;
306 ++str;
308 if(++written >= maxbytes)
309 break;
312 continue;
315 if(ch == 'd')
317 int num = va_arg(args, int);
318 int quotient;
319 const char *str;
320 char *digitptr = TempBuffer;
323 * We have to special-case "0" unfortunately
325 if(num == 0)
327 *dest++ = '0';
328 ++written;
329 continue;
332 if(num < 0)
334 *dest++ = '-';
335 if(++written >= maxbytes)
336 continue;
338 num = -num;
343 quotient = num / TABLE_MAX;
346 * We'll start with the right-most digits of 'num'.
347 * Dividing by TABLE_MAX cuts off all but the X
348 * right-most digits, where X is such that:
350 * 10^X = TABLE_MAX
352 * For example, if num = 1200, and TABLE_MAX = 1000,
353 * quotient will be 1. Multiplying this by 1000 and
354 * subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
355 * We then go right to slot 200 in our array and behold!
356 * The string "002" (200 backwards) is conveniently
357 * waiting for us. Then repeat the process with the
358 * digits left.
360 * The reason we need to have the integers written
361 * backwards, is because we don't know how many digits
362 * there are. If we want to express the number 12130
363 * for example, our first pass would leave us with 130,
364 * whose slot in the array yields "031", which we
365 * plug into our TempBuffer[]. The next pass gives us
366 * 12, whose slot yields "21" which we append to
367 * TempBuffer[], leaving us with "03121". This is the
368 * exact number we want, only backwards, so it is
369 * a simple matter to reverse the string. If we used
370 * straightfoward numbers, we would have a TempBuffer
371 * looking like this: "13012" which would be a nightmare
372 * to deal with.
375 str = IntTable[num - (quotient * TABLE_MAX)];
377 while ((*digitptr = *str))
379 ++digitptr;
380 ++str;
383 while ((num = quotient) != 0);
386 * If the last quotient was a 1 or 2 digit number, there
387 * will be one or more leading zeroes in TempBuffer[] -
388 * get rid of them.
390 while (*(digitptr - 1) == '0')
391 --digitptr;
393 while (digitptr != TempBuffer)
395 *dest++ = *--digitptr;
396 if(++written >= maxbytes)
397 break;
400 continue;
401 } /* if (ch == 'd') */
403 if(ch == 'c')
405 *dest++ = va_arg(args, int);
407 ++written;
409 continue;
410 } /* if (ch == 'c') */
412 if(ch == 'u')
414 unsigned int num = va_arg(args, unsigned int);
415 unsigned int quotient;
416 const char *str;
417 char *digitptr = TempBuffer;
419 if(num == 0)
421 *dest++ = '0';
422 ++written;
423 continue;
428 quotient = num / TABLE_MAX;
431 * Very similar to case 'd'
434 str = IntTable[num - (quotient * TABLE_MAX)];
436 while ((*digitptr = *str))
438 ++digitptr;
439 ++str;
442 while ((num = quotient) != 0);
444 while (*(digitptr - 1) == '0')
445 --digitptr;
447 while (digitptr != TempBuffer)
449 *dest++ = *--digitptr;
450 if(++written >= maxbytes)
451 break;
454 continue;
455 } /* if (ch == 'u') */
457 if(ch == 'l')
459 if(*format == 'u')
461 unsigned long num = va_arg(args, unsigned long);
462 unsigned long quotient;
463 const char *str;
464 char *digitptr = TempBuffer;
466 ++format;
468 if(num == 0)
470 *dest++ = '0';
471 ++written;
472 continue;
477 quotient = num / TABLE_MAX;
480 * Very similar to case 'u'
483 str = IntTable[num - (quotient * TABLE_MAX)];
485 while ((*digitptr = *str))
487 ++digitptr;
488 ++str;
491 while ((num = quotient) != 0);
493 while (*(digitptr - 1) == '0')
494 --digitptr;
496 while (digitptr != TempBuffer)
498 *dest++ = *--digitptr;
499 if(++written >= maxbytes)
500 break;
503 continue;
504 } else /* if (*format == 'u') */
506 if(*format == 'd')
508 long num = va_arg(args, long);
509 long quotient;
510 const char *str;
511 char *digitptr = TempBuffer;
513 ++format;
515 if(num == 0)
517 *dest++ = '0';
518 ++written;
519 continue;
522 if(num < 0)
524 *dest++ = '-';
525 if(++written >= maxbytes)
526 continue;
528 num = -num;
533 quotient = num / TABLE_MAX;
535 str = IntTable[num - (quotient * TABLE_MAX)];
537 while ((*digitptr = *str))
539 ++digitptr;
540 ++str;
543 while ((num = quotient) != 0);
545 while (*(digitptr - 1) == '0')
546 --digitptr;
548 while (digitptr != TempBuffer)
550 *dest++ = *--digitptr;
551 if(++written >= maxbytes)
552 break;
555 continue;
556 } else /* if (*format == 'd') */
558 int ret;
559 format -= 2;
560 #ifdef HAVE_VSNPRINTF
561 ret = vsnprintf(dest, maxbytes - written, format, args);
562 #else
563 ret = vsprintf(dest, format, args);
564 #endif
565 dest += ret;
566 written += ret;
567 break;
571 } /* if (ch == 'l') */
573 if(ch != '%')
575 int ret;
578 * The character might be invalid, or be a precision,
579 * padding, or width specification - call vsprintf()
580 * to finish off the string
583 format -= 2;
584 #ifdef HAVE_VSNPRINTF
585 ret = vsnprintf(dest, maxbytes - written, format, args);
586 #else
587 ret = vsprintf(dest, format, args);
588 #endif
589 dest += ret;
590 written += ret;
592 break;
593 } /* if (ch != '%') */
594 } /* if (ch == '%') */
596 *dest++ = ch;
597 ++written;
598 } /* while ((ch = *format++) && (written < maxbytes)) */
601 * Terminate the destination buffer with a \0
603 *dest = '\0';
605 return (written);
606 } /* vSnprintf() */
609 ircvsprintf()
610 Backend to Sprintf() - performs the construction of 'dest'
611 using the string 'format' and the given arguments.
613 We always place a \0 character onto the end of 'dest'.
615 Return: Number of characters written, NOT including the terminating
616 \0 character which is *always* placed at the end of the string
618 NOTE: This function handles the following flags only:
619 %s %d %c %u %ld %lu
620 In addition, this function performs *NO* precision, padding,
621 or width formatting. If it receives an unknown % character,
622 it will call vsprintf() to complete the remainder of the
623 string.
627 ircvsprintf(char *dest, const char *format, va_list args)
629 char ch;
630 int written = 0; /* bytes written so far */
632 while ((ch = *format++))
634 if(ch == '%')
637 * Advance past the %
639 ch = *format++;
642 * Put the most common cases first - %s %d etc
645 if(ch == 's')
647 const char *str = va_arg(args, const char *);
649 while ((*dest = *str))
651 ++dest;
652 ++str;
654 ++written;
657 continue;
658 } /* if (ch == 's') */
661 if(ch == 'd')
663 int num = va_arg(args, int);
664 int quotient;
665 const char *str;
666 char *digitptr = TempBuffer;
669 * We have to special-case "0" unfortunately
671 if(num == 0)
673 *dest++ = '0';
674 ++written;
675 continue;
678 if(num < 0)
680 *dest++ = '-';
681 ++written;
683 num = -num;
688 quotient = num / TABLE_MAX;
691 * We'll start with the right-most digits of 'num'.
692 * Dividing by TABLE_MAX cuts off all but the X
693 * right-most digits, where X is such that:
695 * 10^X = TABLE_MAX
697 * For example, if num = 1200, and TABLE_MAX = 1000,
698 * quotient will be 1. Multiplying this by 1000 and
699 * subtracting from 1200 gives: 1200 - (1 * 1000) = 200.
700 * We then go right to slot 200 in our array and behold!
701 * The string "002" (200 backwards) is conveniently
702 * waiting for us. Then repeat the process with the
703 * digits left.
705 * The reason we need to have the integers written
706 * backwards, is because we don't know how many digits
707 * there are. If we want to express the number 12130
708 * for example, our first pass would leave us with 130,
709 * whose slot in the array yields "031", which we
710 * plug into our TempBuffer[]. The next pass gives us
711 * 12, whose slot yields "21" which we append to
712 * TempBuffer[], leaving us with "03121". This is the
713 * exact number we want, only backwards, so it is
714 * a simple matter to reverse the string. If we used
715 * straightfoward numbers, we would have a TempBuffer
716 * looking like this: "13012" which would be a nightmare
717 * to deal with.
720 str = IntTable[num - (quotient * TABLE_MAX)];
722 while ((*digitptr = *str))
724 ++digitptr;
725 ++str;
728 while ((num = quotient) != 0);
731 * If the last quotient was a 1 or 2 digit number, there
732 * will be one or more leading zeroes in TempBuffer[] -
733 * get rid of them.
735 while (*(digitptr - 1) == '0')
736 --digitptr;
738 while (digitptr != TempBuffer)
740 *dest++ = *--digitptr;
741 ++written;
744 continue;
745 } /* if (ch == 'd') */
747 if(ch == 'c')
749 *dest++ = va_arg(args, int);
751 ++written;
753 continue;
754 } /* if (ch == 'c') */
756 if(ch == 'u')
758 unsigned int num = va_arg(args, unsigned int);
759 unsigned int quotient;
760 const char *str;
761 char *digitptr = TempBuffer;
763 if(num == 0)
765 *dest++ = '0';
766 ++written;
767 continue;
772 quotient = num / TABLE_MAX;
775 * Very similar to case 'd'
778 str = IntTable[num - (quotient * TABLE_MAX)];
780 while ((*digitptr = *str))
782 ++digitptr;
783 ++str;
786 while ((num = quotient) != 0);
788 while (*(digitptr - 1) == '0')
789 --digitptr;
791 while (digitptr != TempBuffer)
793 *dest++ = *--digitptr;
794 ++written;
797 continue;
798 } /* if (ch == 'u') */
800 if(ch == 'l')
802 if(*format == 'u')
804 unsigned long num = va_arg(args, unsigned long);
805 unsigned long quotient;
806 const char *str;
807 char *digitptr = TempBuffer;
809 ++format;
811 if(num == 0)
813 *dest++ = '0';
814 ++written;
815 continue;
820 quotient = num / TABLE_MAX;
823 * Very similar to case 'u'
826 str = IntTable[num - (quotient * TABLE_MAX)];
828 while ((*digitptr = *str))
830 ++digitptr;
831 ++str;
834 while ((num = quotient) != 0);
836 while (*(digitptr - 1) == '0')
837 --digitptr;
839 while (digitptr != TempBuffer)
841 *dest++ = *--digitptr;
842 ++written;
845 continue;
846 } /* if (*format == 'u') */
848 if(*format == 'd')
850 long num = va_arg(args, long);
851 long quotient;
852 const char *str;
853 char *digitptr = TempBuffer;
855 ++format;
857 if(num == 0)
859 *dest++ = '0';
860 ++written;
861 continue;
864 if(num < 0)
866 *dest++ = '-';
867 ++written;
869 num = -num;
874 quotient = num / TABLE_MAX;
876 str = IntTable[num - (quotient * TABLE_MAX)];
878 while ((*digitptr = *str))
880 ++digitptr;
881 ++str;
884 while ((num = quotient) != 0);
886 while (*(digitptr - 1) == '0')
887 --digitptr;
889 while (digitptr != TempBuffer)
891 *dest++ = *--digitptr;
892 ++written;
895 continue;
896 } /* if (*format == 'd') */
898 continue;
899 } /* if (ch == 'l') */
901 if(ch != '%')
903 int ret;
905 format -= 2;
906 ret = vsprintf(dest, format, args);
907 dest += ret;
908 written += ret;
910 break;
911 } /* if (ch != '%') */
912 } /* if (ch == '%') */
914 *dest++ = ch;
915 ++written;
916 } /* while ((ch = *format++)) */
919 * Terminate the destination buffer with a \0
921 *dest = '\0';
923 return (written);
924 } /* vSprintf() */
927 ircsnprintf()
928 Optimized version of snprintf().
930 Inputs: dest - destination string
931 bytes - number of bytes to copy
932 format - formatted string
933 args - args to 'format'
935 Return: number of characters copied, NOT including the terminating
936 NULL which is always placed at the end of the string
940 ircsnprintf(char *dest, const size_t bytes, const char *format, ...)
942 va_list args;
943 int count;
945 va_start(args, format);
947 count = ircvsnprintf(dest, bytes, format, args);
949 va_end(args);
951 return (count);
952 } /* Snprintf() */
955 ircsprintf()
956 Optimized version of sprintf()
958 Inputs: dest - destination string
959 format - formatted string
960 args - arguments to 'format'
962 Return: number of characters copied, NOT including the terminating
963 NULL which is always placed at the end of the string
967 ircsprintf(char *dest, const char *format, ...)
969 va_list args;
970 int count;
972 va_start(args, format);
974 count = ircvsprintf(dest, format, args);
976 va_end(args);
978 return (count);
979 } /* Sprintf() */