]>
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.
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 :-).
32 * Patrick Alken <wnder@underworld.net>
36 * Set this to the number of indices (numbers) in our table
38 #define TABLE_MAX 1000
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"
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
249 #define TEMPBUF_MAX 20
251 static char TempBuffer
[TEMPBUF_MAX
];
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'
259 We always allow room for a terminating \0 character, so at most,
260 bytes - 1 characters will be written to dest.
262 Return: Number of characters written, NOT including the terminating
263 \0 character which is *always* placed at the end of the string
265 NOTE: This function handles the following flags only:
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
274 rs_vsnprintf(char *dest
, const size_t bytes
, const char *format
, va_list args
)
277 int written
= 0; /* bytes written so far */
278 int maxbytes
= bytes
- 1;
280 while((ch
= *format
++) && (written
< maxbytes
))
290 * Put the most common cases first - %s %d etc
295 const char *str
= va_arg(args
, const char *);
297 while((*dest
= *str
))
302 if(++written
>= maxbytes
)
311 int num
= va_arg(args
, int);
314 char *digitptr
= TempBuffer
;
317 * We have to special-case "0" unfortunately
329 if(++written
>= maxbytes
)
337 quotient
= num
/ TABLE_MAX
;
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:
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
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
369 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
371 while((*digitptr
= *str
))
377 while((num
= quotient
) != 0);
380 * If the last quotient was a 1 or 2 digit number, there
381 * will be one or more leading zeroes in TempBuffer[] -
384 while(*(digitptr
- 1) == '0')
387 while(digitptr
!= TempBuffer
)
389 *dest
++ = *--digitptr
;
390 if(++written
>= maxbytes
)
395 } /* if (ch == 'd') */
399 *dest
++ = va_arg(args
, int);
404 } /* if (ch == 'c') */
408 unsigned int num
= va_arg(args
, unsigned int);
409 unsigned int quotient
;
411 char *digitptr
= TempBuffer
;
422 quotient
= num
/ TABLE_MAX
;
425 * Very similar to case 'd'
428 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
430 while((*digitptr
= *str
))
436 while((num
= quotient
) != 0);
438 while(*(digitptr
- 1) == '0')
441 while(digitptr
!= TempBuffer
)
443 *dest
++ = *--digitptr
;
444 if(++written
>= maxbytes
)
449 } /* if (ch == 'u') */
453 const char *arg
= va_arg(args
, const char *);
458 const char *str
= rsdb_quote(arg
);
460 while((*dest
= *str
))
465 if(++written
>= maxbytes
)
476 unsigned long num
= va_arg(args
, unsigned long);
477 unsigned long quotient
;
479 char *digitptr
= TempBuffer
;
492 quotient
= num
/ TABLE_MAX
;
495 * Very similar to case 'u'
498 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
500 while((*digitptr
= *str
))
506 while((num
= quotient
) != 0);
508 while(*(digitptr
- 1) == '0')
511 while(digitptr
!= TempBuffer
)
513 *dest
++ = *--digitptr
;
514 if(++written
>= maxbytes
)
521 /* if (*format == 'u') */ if(*format
== 'd')
523 long num
= va_arg(args
, long);
526 char *digitptr
= TempBuffer
;
540 if(++written
>= maxbytes
)
548 quotient
= num
/ TABLE_MAX
;
550 str
= IntTable
[num
- (quotient
* TABLE_MAX
)];
552 while((*digitptr
= *str
))
558 while((num
= quotient
) != 0);
560 while(*(digitptr
- 1) == '0')
563 while(digitptr
!= TempBuffer
)
565 *dest
++ = *--digitptr
;
566 if(++written
>= maxbytes
)
572 else /* if (*format == 'd') */
579 } /* if (ch == 'l') */
585 } /* if (ch != '%') */
586 } /* if (ch == '%') */
590 } /* while ((ch = *format++) && (written < maxbytes)) */
593 * Terminate the destination buffer with a \0
602 Optimized version of snprintf().
604 Inputs: dest - destination string
605 bytes - number of bytes to copy
606 format - formatted string
607 args - args to 'format'
609 Return: number of characters copied, NOT including the terminating
610 NULL which is always placed at the end of the string
614 rs_snprintf(char *dest
, const size_t bytes
, const char *format
, ...)
619 va_start(args
, format
);
621 count
= rs_vsnprintf(dest
, bytes
, format
, args
);