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.
13 #include <sys/types.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
];
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:
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
280 ircvsnprintf(char *dest
, const size_t bytes
, const char *format
, va_list args
)
283 int written
= 0; /* bytes written so far */
284 int maxbytes
= bytes
- 1;
286 while ((ch
= *format
++) && (written
< maxbytes
))
296 * Put the most common cases first - %s %d etc
301 const char *str
= va_arg(args
, const char *);
303 while ((*dest
= *str
))
308 if(++written
>= maxbytes
)
317 int num
= va_arg(args
, int);
320 char *digitptr
= TempBuffer
;
323 * We have to special-case "0" unfortunately
335 if(++written
>= maxbytes
)
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:
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
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
375 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
377 while ((*digitptr
= *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[] -
390 while (*(digitptr
- 1) == '0')
393 while (digitptr
!= TempBuffer
)
395 *dest
++ = *--digitptr
;
396 if(++written
>= maxbytes
)
401 } /* if (ch == 'd') */
405 *dest
++ = va_arg(args
, int);
410 } /* if (ch == 'c') */
414 unsigned int num
= va_arg(args
, unsigned int);
415 unsigned int quotient
;
417 char *digitptr
= TempBuffer
;
428 quotient
= num
/ TABLE_MAX
;
431 * Very similar to case 'd'
434 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
436 while ((*digitptr
= *str
))
442 while ((num
= quotient
) != 0);
444 while (*(digitptr
- 1) == '0')
447 while (digitptr
!= TempBuffer
)
449 *dest
++ = *--digitptr
;
450 if(++written
>= maxbytes
)
455 } /* if (ch == 'u') */
461 unsigned long num
= va_arg(args
, unsigned long);
462 unsigned long quotient
;
464 char *digitptr
= TempBuffer
;
477 quotient
= num
/ TABLE_MAX
;
480 * Very similar to case 'u'
483 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
485 while ((*digitptr
= *str
))
491 while ((num
= quotient
) != 0);
493 while (*(digitptr
- 1) == '0')
496 while (digitptr
!= TempBuffer
)
498 *dest
++ = *--digitptr
;
499 if(++written
>= maxbytes
)
504 } else /* if (*format == 'u') */
508 long num
= va_arg(args
, long);
511 char *digitptr
= TempBuffer
;
525 if(++written
>= maxbytes
)
533 quotient
= num
/ TABLE_MAX
;
535 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
537 while ((*digitptr
= *str
))
543 while ((num
= quotient
) != 0);
545 while (*(digitptr
- 1) == '0')
548 while (digitptr
!= TempBuffer
)
550 *dest
++ = *--digitptr
;
551 if(++written
>= maxbytes
)
556 } else /* if (*format == 'd') */
560 #ifdef HAVE_VSNPRINTF
561 ret
= vsnprintf(dest
, maxbytes
- written
, format
, args
);
563 ret
= vsprintf(dest
, format
, args
);
571 } /* if (ch == 'l') */
578 * The character might be invalid, or be a precision,
579 * padding, or width specification - call vsprintf()
580 * to finish off the string
584 #ifdef HAVE_VSNPRINTF
585 ret
= vsnprintf(dest
, maxbytes
- written
, format
, args
);
587 ret
= vsprintf(dest
, format
, args
);
593 } /* if (ch != '%') */
594 } /* if (ch == '%') */
598 } /* while ((ch = *format++) && (written < maxbytes)) */
601 * Terminate the destination buffer with a \0
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:
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
627 ircvsprintf(char *dest
, const char *format
, va_list args
)
630 int written
= 0; /* bytes written so far */
632 while ((ch
= *format
++))
642 * Put the most common cases first - %s %d etc
647 const char *str
= va_arg(args
, const char *);
649 while ((*dest
= *str
))
658 } /* if (ch == 's') */
663 int num
= va_arg(args
, int);
666 char *digitptr
= TempBuffer
;
669 * We have to special-case "0" unfortunately
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:
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
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
720 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
722 while ((*digitptr
= *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[] -
735 while (*(digitptr
- 1) == '0')
738 while (digitptr
!= TempBuffer
)
740 *dest
++ = *--digitptr
;
745 } /* if (ch == 'd') */
749 *dest
++ = va_arg(args
, int);
754 } /* if (ch == 'c') */
758 unsigned int num
= va_arg(args
, unsigned int);
759 unsigned int quotient
;
761 char *digitptr
= TempBuffer
;
772 quotient
= num
/ TABLE_MAX
;
775 * Very similar to case 'd'
778 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
780 while ((*digitptr
= *str
))
786 while ((num
= quotient
) != 0);
788 while (*(digitptr
- 1) == '0')
791 while (digitptr
!= TempBuffer
)
793 *dest
++ = *--digitptr
;
798 } /* if (ch == 'u') */
804 unsigned long num
= va_arg(args
, unsigned long);
805 unsigned long quotient
;
807 char *digitptr
= TempBuffer
;
820 quotient
= num
/ TABLE_MAX
;
823 * Very similar to case 'u'
826 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
828 while ((*digitptr
= *str
))
834 while ((num
= quotient
) != 0);
836 while (*(digitptr
- 1) == '0')
839 while (digitptr
!= TempBuffer
)
841 *dest
++ = *--digitptr
;
846 } /* if (*format == 'u') */
850 long num
= va_arg(args
, long);
853 char *digitptr
= TempBuffer
;
874 quotient
= num
/ TABLE_MAX
;
876 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
878 while ((*digitptr
= *str
))
884 while ((num
= quotient
) != 0);
886 while (*(digitptr
- 1) == '0')
889 while (digitptr
!= TempBuffer
)
891 *dest
++ = *--digitptr
;
896 } /* if (*format == 'd') */
899 } /* if (ch == 'l') */
906 ret
= vsprintf(dest
, format
, args
);
911 } /* if (ch != '%') */
912 } /* if (ch == '%') */
916 } /* while ((ch = *format++)) */
919 * Terminate the destination buffer with a \0
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
, ...)
945 va_start(args
, format
);
947 count
= ircvsnprintf(dest
, bytes
, format
, args
);
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
, ...)
972 va_start(args
, format
);
974 count
= ircvsprintf(dest
, format
, args
);