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