]>
jfr.im git - solanum.git/blob - bandb/rsdb_snprintf.c
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.
9 * $Id: rsdb_snprintf.c 26094 2008-09-19 15:33:46Z androsyn $
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 :-).
34 * Patrick Alken <wnder@underworld.net>
38 * Set this to the number of indices (numbers) in our table
40 #define TABLE_MAX 1000
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"
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
251 #define TEMPBUF_MAX 20
253 static char TempBuffer
[TEMPBUF_MAX
];
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'
261 We always allow room for a terminating \0 character, so at most,
262 bytes - 1 characters will be written to dest.
264 Return: Number of characters written, NOT including the terminating
265 \0 character which is *always* placed at the end of the string
267 NOTE: This function handles the following flags only:
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
276 rs_vsnprintf(char *dest
, const size_t bytes
, const char *format
, va_list args
)
279 int written
= 0; /* bytes written so far */
280 int maxbytes
= bytes
- 1;
282 while((ch
= *format
++) && (written
< maxbytes
))
292 * Put the most common cases first - %s %d etc
297 const char *str
= va_arg(args
, const char *);
299 while((*dest
= *str
))
304 if(++written
>= maxbytes
)
313 int num
= va_arg(args
, int);
316 char *digitptr
= TempBuffer
;
319 * We have to special-case "0" unfortunately
331 if(++written
>= maxbytes
)
339 quotient
= num
/ TABLE_MAX
;
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:
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
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
371 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
373 while((*digitptr
= *str
))
379 while((num
= quotient
) != 0);
382 * If the last quotient was a 1 or 2 digit number, there
383 * will be one or more leading zeroes in TempBuffer[] -
386 while(*(digitptr
- 1) == '0')
389 while(digitptr
!= TempBuffer
)
391 *dest
++ = *--digitptr
;
392 if(++written
>= maxbytes
)
397 } /* if (ch == 'd') */
401 *dest
++ = va_arg(args
, int);
406 } /* if (ch == 'c') */
410 unsigned int num
= va_arg(args
, unsigned int);
411 unsigned int quotient
;
413 char *digitptr
= TempBuffer
;
424 quotient
= num
/ TABLE_MAX
;
427 * Very similar to case 'd'
430 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
432 while((*digitptr
= *str
))
438 while((num
= quotient
) != 0);
440 while(*(digitptr
- 1) == '0')
443 while(digitptr
!= TempBuffer
)
445 *dest
++ = *--digitptr
;
446 if(++written
>= maxbytes
)
451 } /* if (ch == 'u') */
455 const char *arg
= va_arg(args
, const char *);
460 const char *str
= rsdb_quote(arg
);
462 while((*dest
= *str
))
467 if(++written
>= maxbytes
)
478 unsigned long num
= va_arg(args
, unsigned long);
479 unsigned long quotient
;
481 char *digitptr
= TempBuffer
;
494 quotient
= num
/ TABLE_MAX
;
497 * Very similar to case 'u'
500 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
502 while((*digitptr
= *str
))
508 while((num
= quotient
) != 0);
510 while(*(digitptr
- 1) == '0')
513 while(digitptr
!= TempBuffer
)
515 *dest
++ = *--digitptr
;
516 if(++written
>= maxbytes
)
523 /* if (*format == 'u') */ if(*format
== 'd')
525 long num
= va_arg(args
, long);
528 char *digitptr
= TempBuffer
;
542 if(++written
>= maxbytes
)
550 quotient
= num
/ TABLE_MAX
;
552 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
554 while((*digitptr
= *str
))
560 while((num
= quotient
) != 0);
562 while(*(digitptr
- 1) == '0')
565 while(digitptr
!= TempBuffer
)
567 *dest
++ = *--digitptr
;
568 if(++written
>= maxbytes
)
574 else /* if (*format == 'd') */
581 } /* if (ch == 'l') */
587 } /* if (ch != '%') */
588 } /* if (ch == '%') */
592 } /* while ((ch = *format++) && (written < maxbytes)) */
595 * Terminate the destination buffer with a \0
604 Optimized version of snprintf().
606 Inputs: dest - destination string
607 bytes - number of bytes to copy
608 format - formatted string
609 args - args to 'format'
611 Return: number of characters copied, NOT including the terminating
612 NULL which is always placed at the end of the string
616 rs_snprintf(char *dest
, const size_t bytes
, const char *format
, ...)
621 va_start(args
, format
);
623 count
= rs_vsnprintf(dest
, bytes
, format
, args
);