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