]>
Commit | Line | Data |
---|---|---|
212380e3 AC |
1 | /* |
2 | * libString, Copyright (C) 1999 Patrick Alken | |
3 | * This library comes with absolutely NO WARRANTY | |
4 | * | |
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 | * | |
9 | * $Id: snprintf.c 382 2005-12-07 15:15:59Z nenolod $ | |
10 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdarg.h> | |
14 | #include <stdlib.h> | |
15 | #include <sys/types.h> | |
16 | #include <ctype.h> | |
17 | #include "setup.h" | |
18 | #include "sprintf_irc.h" | |
19 | ||
20 | /* | |
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 :-). | |
39 | * | |
40 | * Patrick Alken <wnder@underworld.net> | |
41 | */ | |
42 | ||
43 | /* | |
44 | * Set this to the number of indices (numbers) in our table | |
45 | */ | |
46 | #define TABLE_MAX 1000 | |
47 | ||
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" | |
249 | }; | |
250 | ||
251 | /* | |
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 | |
255 | */ | |
256 | ||
257 | #define TEMPBUF_MAX 20 | |
258 | ||
259 | static char TempBuffer[TEMPBUF_MAX]; | |
260 | ||
261 | /* | |
262 | vSnprintf() | |
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' | |
266 | ||
267 | We always allow room for a terminating \0 character, so at most, | |
268 | bytes - 1 characters will be written to dest. | |
269 | ||
270 | Return: Number of characters written, NOT including the terminating | |
271 | \0 character which is *always* placed at the end of the string | |
272 | ||
273 | NOTE: This function handles the following flags only: | |
274 | %s %d %c %u %ld %lu | |
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 | |
278 | string. | |
279 | */ | |
280 | ||
281 | int | |
282 | ircvsnprintf(char *dest, const size_t bytes, const char *format, va_list args) | |
283 | { | |
284 | char ch; | |
285 | int written = 0; /* bytes written so far */ | |
286 | int maxbytes = bytes - 1; | |
287 | ||
288 | while ((ch = *format++) && (written < maxbytes)) | |
289 | { | |
290 | if(ch == '%') | |
291 | { | |
292 | /* | |
293 | * Advance past the % | |
294 | */ | |
295 | ch = *format++; | |
296 | ||
297 | /* | |
298 | * Put the most common cases first - %s %d etc | |
299 | */ | |
300 | ||
301 | if(ch == 's') | |
302 | { | |
303 | const char *str = va_arg(args, const char *); | |
304 | ||
305 | while ((*dest = *str)) | |
306 | { | |
307 | ++dest; | |
308 | ++str; | |
309 | ||
310 | if(++written >= maxbytes) | |
311 | break; | |
312 | } | |
313 | ||
314 | continue; | |
315 | } | |
316 | ||
317 | if(ch == 'd') | |
318 | { | |
319 | int num = va_arg(args, int); | |
320 | int quotient; | |
321 | const char *str; | |
322 | char *digitptr = TempBuffer; | |
323 | ||
324 | /* | |
325 | * We have to special-case "0" unfortunately | |
326 | */ | |
327 | if(num == 0) | |
328 | { | |
329 | *dest++ = '0'; | |
330 | ++written; | |
331 | continue; | |
332 | } | |
333 | ||
334 | if(num < 0) | |
335 | { | |
336 | *dest++ = '-'; | |
337 | if(++written >= maxbytes) | |
338 | continue; | |
339 | ||
340 | num = -num; | |
341 | } | |
342 | ||
343 | do | |
344 | { | |
345 | quotient = num / TABLE_MAX; | |
346 | ||
347 | /* | |
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: | |
351 | * | |
352 | * 10^X = TABLE_MAX | |
353 | * | |
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 | |
360 | * digits left. | |
361 | * | |
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 | |
374 | * to deal with. | |
375 | */ | |
376 | ||
377 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
378 | ||
379 | while ((*digitptr = *str)) | |
380 | { | |
381 | ++digitptr; | |
382 | ++str; | |
383 | } | |
384 | } | |
385 | while ((num = quotient) != 0); | |
386 | ||
387 | /* | |
388 | * If the last quotient was a 1 or 2 digit number, there | |
389 | * will be one or more leading zeroes in TempBuffer[] - | |
390 | * get rid of them. | |
391 | */ | |
392 | while (*(digitptr - 1) == '0') | |
393 | --digitptr; | |
394 | ||
395 | while (digitptr != TempBuffer) | |
396 | { | |
397 | *dest++ = *--digitptr; | |
398 | if(++written >= maxbytes) | |
399 | break; | |
400 | } | |
401 | ||
402 | continue; | |
403 | } /* if (ch == 'd') */ | |
404 | ||
405 | if(ch == 'c') | |
406 | { | |
407 | *dest++ = va_arg(args, int); | |
408 | ||
409 | ++written; | |
410 | ||
411 | continue; | |
412 | } /* if (ch == 'c') */ | |
413 | ||
414 | if(ch == 'u') | |
415 | { | |
416 | unsigned int num = va_arg(args, unsigned int); | |
417 | unsigned int quotient; | |
418 | const char *str; | |
419 | char *digitptr = TempBuffer; | |
420 | ||
421 | if(num == 0) | |
422 | { | |
423 | *dest++ = '0'; | |
424 | ++written; | |
425 | continue; | |
426 | } | |
427 | ||
428 | do | |
429 | { | |
430 | quotient = num / TABLE_MAX; | |
431 | ||
432 | /* | |
433 | * Very similar to case 'd' | |
434 | */ | |
435 | ||
436 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
437 | ||
438 | while ((*digitptr = *str)) | |
439 | { | |
440 | ++digitptr; | |
441 | ++str; | |
442 | } | |
443 | } | |
444 | while ((num = quotient) != 0); | |
445 | ||
446 | while (*(digitptr - 1) == '0') | |
447 | --digitptr; | |
448 | ||
449 | while (digitptr != TempBuffer) | |
450 | { | |
451 | *dest++ = *--digitptr; | |
452 | if(++written >= maxbytes) | |
453 | break; | |
454 | } | |
455 | ||
456 | continue; | |
457 | } /* if (ch == 'u') */ | |
458 | ||
459 | if(ch == 'l') | |
460 | { | |
461 | if(*format == 'u') | |
462 | { | |
463 | unsigned long num = va_arg(args, unsigned long); | |
464 | unsigned long quotient; | |
465 | const char *str; | |
466 | char *digitptr = TempBuffer; | |
467 | ||
468 | ++format; | |
469 | ||
470 | if(num == 0) | |
471 | { | |
472 | *dest++ = '0'; | |
473 | ++written; | |
474 | continue; | |
475 | } | |
476 | ||
477 | do | |
478 | { | |
479 | quotient = num / TABLE_MAX; | |
480 | ||
481 | /* | |
482 | * Very similar to case 'u' | |
483 | */ | |
484 | ||
485 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
486 | ||
487 | while ((*digitptr = *str)) | |
488 | { | |
489 | ++digitptr; | |
490 | ++str; | |
491 | } | |
492 | } | |
493 | while ((num = quotient) != 0); | |
494 | ||
495 | while (*(digitptr - 1) == '0') | |
496 | --digitptr; | |
497 | ||
498 | while (digitptr != TempBuffer) | |
499 | { | |
500 | *dest++ = *--digitptr; | |
501 | if(++written >= maxbytes) | |
502 | break; | |
503 | } | |
504 | ||
505 | continue; | |
506 | } else /* if (*format == 'u') */ | |
507 | ||
508 | if(*format == 'd') | |
509 | { | |
510 | long num = va_arg(args, long); | |
511 | long quotient; | |
512 | const char *str; | |
513 | char *digitptr = TempBuffer; | |
514 | ||
515 | ++format; | |
516 | ||
517 | if(num == 0) | |
518 | { | |
519 | *dest++ = '0'; | |
520 | ++written; | |
521 | continue; | |
522 | } | |
523 | ||
524 | if(num < 0) | |
525 | { | |
526 | *dest++ = '-'; | |
527 | if(++written >= maxbytes) | |
528 | continue; | |
529 | ||
530 | num = -num; | |
531 | } | |
532 | ||
533 | do | |
534 | { | |
535 | quotient = num / TABLE_MAX; | |
536 | ||
537 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
538 | ||
539 | while ((*digitptr = *str)) | |
540 | { | |
541 | ++digitptr; | |
542 | ++str; | |
543 | } | |
544 | } | |
545 | while ((num = quotient) != 0); | |
546 | ||
547 | while (*(digitptr - 1) == '0') | |
548 | --digitptr; | |
549 | ||
550 | while (digitptr != TempBuffer) | |
551 | { | |
552 | *dest++ = *--digitptr; | |
553 | if(++written >= maxbytes) | |
554 | break; | |
555 | } | |
556 | ||
557 | continue; | |
558 | } else /* if (*format == 'd') */ | |
559 | { | |
560 | int ret; | |
561 | format -= 2; | |
562 | #ifdef HAVE_VSNPRINTF | |
563 | ret = vsnprintf(dest, maxbytes - written, format, args); | |
564 | #else | |
565 | ret = vsprintf(dest, format, args); | |
566 | #endif | |
567 | dest += ret; | |
568 | written += ret; | |
569 | break; | |
570 | } | |
571 | ||
572 | ||
573 | } /* if (ch == 'l') */ | |
574 | ||
575 | if(ch != '%') | |
576 | { | |
577 | int ret; | |
578 | ||
579 | /* | |
580 | * The character might be invalid, or be a precision, | |
581 | * padding, or width specification - call vsprintf() | |
582 | * to finish off the string | |
583 | */ | |
584 | ||
585 | format -= 2; | |
586 | #ifdef HAVE_VSNPRINTF | |
587 | ret = vsnprintf(dest, maxbytes - written, format, args); | |
588 | #else | |
589 | ret = vsprintf(dest, format, args); | |
590 | #endif | |
591 | dest += ret; | |
592 | written += ret; | |
593 | ||
594 | break; | |
595 | } /* if (ch != '%') */ | |
596 | } /* if (ch == '%') */ | |
597 | ||
598 | *dest++ = ch; | |
599 | ++written; | |
600 | } /* while ((ch = *format++) && (written < maxbytes)) */ | |
601 | ||
602 | /* | |
603 | * Terminate the destination buffer with a \0 | |
604 | */ | |
605 | *dest = '\0'; | |
606 | ||
607 | return (written); | |
608 | } /* vSnprintf() */ | |
609 | ||
610 | /* | |
611 | ircvsprintf() | |
612 | Backend to Sprintf() - performs the construction of 'dest' | |
613 | using the string 'format' and the given arguments. | |
614 | ||
615 | We always place a \0 character onto the end of 'dest'. | |
616 | ||
617 | Return: Number of characters written, NOT including the terminating | |
618 | \0 character which is *always* placed at the end of the string | |
619 | ||
620 | NOTE: This function handles the following flags only: | |
621 | %s %d %c %u %ld %lu | |
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 | |
625 | string. | |
626 | */ | |
627 | ||
628 | int | |
629 | ircvsprintf(char *dest, const char *format, va_list args) | |
630 | { | |
631 | char ch; | |
632 | int written = 0; /* bytes written so far */ | |
633 | ||
634 | while ((ch = *format++)) | |
635 | { | |
636 | if(ch == '%') | |
637 | { | |
638 | /* | |
639 | * Advance past the % | |
640 | */ | |
641 | ch = *format++; | |
642 | ||
643 | /* | |
644 | * Put the most common cases first - %s %d etc | |
645 | */ | |
646 | ||
647 | if(ch == 's') | |
648 | { | |
649 | const char *str = va_arg(args, const char *); | |
650 | ||
651 | while ((*dest = *str)) | |
652 | { | |
653 | ++dest; | |
654 | ++str; | |
655 | ||
656 | ++written; | |
657 | } | |
658 | ||
659 | continue; | |
660 | } /* if (ch == 's') */ | |
661 | ||
662 | ||
663 | if(ch == 'd') | |
664 | { | |
665 | int num = va_arg(args, int); | |
666 | int quotient; | |
667 | const char *str; | |
668 | char *digitptr = TempBuffer; | |
669 | ||
670 | /* | |
671 | * We have to special-case "0" unfortunately | |
672 | */ | |
673 | if(num == 0) | |
674 | { | |
675 | *dest++ = '0'; | |
676 | ++written; | |
677 | continue; | |
678 | } | |
679 | ||
680 | if(num < 0) | |
681 | { | |
682 | *dest++ = '-'; | |
683 | ++written; | |
684 | ||
685 | num = -num; | |
686 | } | |
687 | ||
688 | do | |
689 | { | |
690 | quotient = num / TABLE_MAX; | |
691 | ||
692 | /* | |
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: | |
696 | * | |
697 | * 10^X = TABLE_MAX | |
698 | * | |
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 | |
705 | * digits left. | |
706 | * | |
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 | |
719 | * to deal with. | |
720 | */ | |
721 | ||
722 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
723 | ||
724 | while ((*digitptr = *str)) | |
725 | { | |
726 | ++digitptr; | |
727 | ++str; | |
728 | } | |
729 | } | |
730 | while ((num = quotient) != 0); | |
731 | ||
732 | /* | |
733 | * If the last quotient was a 1 or 2 digit number, there | |
734 | * will be one or more leading zeroes in TempBuffer[] - | |
735 | * get rid of them. | |
736 | */ | |
737 | while (*(digitptr - 1) == '0') | |
738 | --digitptr; | |
739 | ||
740 | while (digitptr != TempBuffer) | |
741 | { | |
742 | *dest++ = *--digitptr; | |
743 | ++written; | |
744 | } | |
745 | ||
746 | continue; | |
747 | } /* if (ch == 'd') */ | |
748 | ||
749 | if(ch == 'c') | |
750 | { | |
751 | *dest++ = va_arg(args, int); | |
752 | ||
753 | ++written; | |
754 | ||
755 | continue; | |
756 | } /* if (ch == 'c') */ | |
757 | ||
758 | if(ch == 'u') | |
759 | { | |
760 | unsigned int num = va_arg(args, unsigned int); | |
761 | unsigned int quotient; | |
762 | const char *str; | |
763 | char *digitptr = TempBuffer; | |
764 | ||
765 | if(num == 0) | |
766 | { | |
767 | *dest++ = '0'; | |
768 | ++written; | |
769 | continue; | |
770 | } | |
771 | ||
772 | do | |
773 | { | |
774 | quotient = num / TABLE_MAX; | |
775 | ||
776 | /* | |
777 | * Very similar to case 'd' | |
778 | */ | |
779 | ||
780 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
781 | ||
782 | while ((*digitptr = *str)) | |
783 | { | |
784 | ++digitptr; | |
785 | ++str; | |
786 | } | |
787 | } | |
788 | while ((num = quotient) != 0); | |
789 | ||
790 | while (*(digitptr - 1) == '0') | |
791 | --digitptr; | |
792 | ||
793 | while (digitptr != TempBuffer) | |
794 | { | |
795 | *dest++ = *--digitptr; | |
796 | ++written; | |
797 | } | |
798 | ||
799 | continue; | |
800 | } /* if (ch == 'u') */ | |
801 | ||
802 | if(ch == 'l') | |
803 | { | |
804 | if(*format == 'u') | |
805 | { | |
806 | unsigned long num = va_arg(args, unsigned long); | |
807 | unsigned long quotient; | |
808 | const char *str; | |
809 | char *digitptr = TempBuffer; | |
810 | ||
811 | ++format; | |
812 | ||
813 | if(num == 0) | |
814 | { | |
815 | *dest++ = '0'; | |
816 | ++written; | |
817 | continue; | |
818 | } | |
819 | ||
820 | do | |
821 | { | |
822 | quotient = num / TABLE_MAX; | |
823 | ||
824 | /* | |
825 | * Very similar to case 'u' | |
826 | */ | |
827 | ||
828 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
829 | ||
830 | while ((*digitptr = *str)) | |
831 | { | |
832 | ++digitptr; | |
833 | ++str; | |
834 | } | |
835 | } | |
836 | while ((num = quotient) != 0); | |
837 | ||
838 | while (*(digitptr - 1) == '0') | |
839 | --digitptr; | |
840 | ||
841 | while (digitptr != TempBuffer) | |
842 | { | |
843 | *dest++ = *--digitptr; | |
844 | ++written; | |
845 | } | |
846 | ||
847 | continue; | |
848 | } /* if (*format == 'u') */ | |
849 | ||
850 | if(*format == 'd') | |
851 | { | |
852 | long num = va_arg(args, long); | |
853 | long quotient; | |
854 | const char *str; | |
855 | char *digitptr = TempBuffer; | |
856 | ||
857 | ++format; | |
858 | ||
859 | if(num == 0) | |
860 | { | |
861 | *dest++ = '0'; | |
862 | ++written; | |
863 | continue; | |
864 | } | |
865 | ||
866 | if(num < 0) | |
867 | { | |
868 | *dest++ = '-'; | |
869 | ++written; | |
870 | ||
871 | num = -num; | |
872 | } | |
873 | ||
874 | do | |
875 | { | |
876 | quotient = num / TABLE_MAX; | |
877 | ||
878 | str = IntTable[num - (quotient * TABLE_MAX)]; | |
879 | ||
880 | while ((*digitptr = *str)) | |
881 | { | |
882 | ++digitptr; | |
883 | ++str; | |
884 | } | |
885 | } | |
886 | while ((num = quotient) != 0); | |
887 | ||
888 | while (*(digitptr - 1) == '0') | |
889 | --digitptr; | |
890 | ||
891 | while (digitptr != TempBuffer) | |
892 | { | |
893 | *dest++ = *--digitptr; | |
894 | ++written; | |
895 | } | |
896 | ||
897 | continue; | |
898 | } /* if (*format == 'd') */ | |
899 | ||
900 | continue; | |
901 | } /* if (ch == 'l') */ | |
902 | ||
903 | if(ch != '%') | |
904 | { | |
905 | int ret; | |
906 | ||
907 | format -= 2; | |
908 | ret = vsprintf(dest, format, args); | |
909 | dest += ret; | |
910 | written += ret; | |
911 | ||
912 | break; | |
913 | } /* if (ch != '%') */ | |
914 | } /* if (ch == '%') */ | |
915 | ||
916 | *dest++ = ch; | |
917 | ++written; | |
918 | } /* while ((ch = *format++)) */ | |
919 | ||
920 | /* | |
921 | * Terminate the destination buffer with a \0 | |
922 | */ | |
923 | *dest = '\0'; | |
924 | ||
925 | return (written); | |
926 | } /* vSprintf() */ | |
927 | ||
928 | /* | |
929 | ircsnprintf() | |
930 | Optimized version of snprintf(). | |
931 | ||
932 | Inputs: dest - destination string | |
933 | bytes - number of bytes to copy | |
934 | format - formatted string | |
935 | args - args to 'format' | |
936 | ||
937 | Return: number of characters copied, NOT including the terminating | |
938 | NULL which is always placed at the end of the string | |
939 | */ | |
940 | ||
941 | int | |
942 | ircsnprintf(char *dest, const size_t bytes, const char *format, ...) | |
943 | { | |
944 | va_list args; | |
945 | int count; | |
946 | ||
947 | va_start(args, format); | |
948 | ||
949 | count = ircvsnprintf(dest, bytes, format, args); | |
950 | ||
951 | va_end(args); | |
952 | ||
953 | return (count); | |
954 | } /* Snprintf() */ | |
955 | ||
956 | /* | |
957 | ircsprintf() | |
958 | Optimized version of sprintf() | |
959 | ||
960 | Inputs: dest - destination string | |
961 | format - formatted string | |
962 | args - arguments to 'format' | |
963 | ||
964 | Return: number of characters copied, NOT including the terminating | |
965 | NULL which is always placed at the end of the string | |
966 | */ | |
967 | ||
968 | int | |
969 | ircsprintf(char *dest, const char *format, ...) | |
970 | { | |
971 | va_list args; | |
972 | int count; | |
973 | ||
974 | va_start(args, format); | |
975 | ||
976 | count = ircvsprintf(dest, format, args); | |
977 | ||
978 | va_end(args); | |
979 | ||
980 | return (count); | |
981 | } /* Sprintf() */ |