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