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