Tue, 25 Feb 2003 20:02:42 +0100
trunk: changeset 47
Added system-inc.mk and modified Makefile to use it
35 | 1 | |
2 | snprintf.c | |
3 | - a portable implementation of snprintf, | |
4 | including vsnprintf.c, asnprintf, vasnprintf, asprintf, vasprintf | |
5 | ||
6 | snprintf is a routine to convert numeric and string arguments to | |
7 | formatted strings. It is similar to sprintf(3) provided in a system's | |
8 | C library, yet it requires an additional argument - the buffer size - | |
9 | and it guarantees never to store anything beyond the given buffer, | |
10 | regardless of the format or arguments to be formatted. Some newer | |
11 | operating systems do provide snprintf in their C library, but many do | |
12 | not or do provide an inadequate (slow or idiosyncratic) version, which | |
13 | calls for a portable implementation of this routine. | |
14 | ||
15 | Author | |
16 | ||
17 | Mark Martinec <mark.martinec@ijs.si>, April 1999, June 2000 | |
18 | Copyright © 1999, Mark Martinec | |
19 | ||
20 | Terms and conditions ... | |
21 | ||
22 | This program is free software; you can redistribute it and/or modify | |
23 | it under the terms of the Frontier Artistic License which comes with | |
24 | this Kit. | |
25 | ||
26 | Features | |
27 | ||
28 | * careful adherence to specs regarding flags, field width and | |
29 | precision; | |
30 | * good performance for large string handling (large format, large | |
31 | argument or large paddings). Performance is similar to system's | |
32 | sprintf and in several cases significantly better (make sure you | |
33 | compile with optimizations turned on, tell the compiler the code | |
34 | is strict ANSI if necessary to give it more freedom for | |
35 | optimizations); | |
36 | * return value semantics per ISO/IEC 9899:1999 ("ISO C99"); | |
37 | * written in standard ISO/ANSI C - requires an ANSI C compiler. | |
38 | ||
39 | Supported conversion specifiers and data types | |
40 | ||
41 | This snprintf only supports the following conversion specifiers: s, c, | |
42 | d, o, u, x, X, p (and synonyms: i, D, U, O - see below) with flags: | |
43 | '-', '+', ' ', '0' and '#'. An asterisk is supported for field width | |
44 | as well as precision. | |
45 | ||
46 | Length modifiers 'h' (short int), 'l' (long int), and 'll' (long long | |
47 | int) are supported. | |
48 | ||
49 | NOTE: | |
50 | ||
51 | If macro SNPRINTF_LONGLONG_SUPPORT is not defined (default) the | |
52 | length modifier 'll' is recognized but treated the same as 'l', | |
53 | which may cause argument value truncation! Defining | |
54 | SNPRINTF_LONGLONG_SUPPORT requires that your system's sprintf also | |
55 | handles length modifier 'll'. long long int is a language extension | |
56 | which may not be portable. | |
57 | ||
58 | Conversion of numeric data (conversion specifiers d, o, u, x, X, p) | |
59 | with length modifiers (none or h, l, ll) is left to the system routine | |
60 | sprintf, but all handling of flags, field width and precision as well | |
61 | as c and s conversions is done very carefully by this portable | |
62 | routine. If a string precision (truncation) is specified (e.g. %.8s) | |
63 | it is guaranteed the string beyond the specified precision will not be | |
64 | referenced. | |
65 | ||
66 | Length modifiers h, l and ll are ignored for c and s conversions (data | |
67 | types wint_t and wchar_t are not supported). | |
68 | ||
69 | The following common synonyms for conversion characters are supported: | |
70 | * i is a synonym for d | |
71 | * D is a synonym for ld, explicit length modifiers are ignored | |
72 | * U is a synonym for lu, explicit length modifiers are ignored | |
73 | * O is a synonym for lo, explicit length modifiers are ignored | |
74 | ||
75 | The D, O and U conversion characters are nonstandard, they are | |
76 | supported for backward compatibility only, and should not be used for | |
77 | new code. | |
78 | ||
79 | The following is specifically not supported: | |
80 | * flag ' (thousands' grouping character) is recognized but ignored | |
81 | * numeric conversion specifiers: f, e, E, g, G and synonym F, as | |
82 | well as the new a and A conversion specifiers | |
83 | * length modifier 'L' (long double) and 'q' (quad - use 'll' | |
84 | instead) | |
85 | * wide character/string conversions: lc, ls, and nonstandard | |
86 | synonyms C and S | |
87 | * writeback of converted string length: conversion character n | |
88 | * the n$ specification for direct reference to n-th argument | |
89 | * locales | |
90 | ||
91 | It is permitted for str_m to be zero, and it is permitted to specify | |
92 | NULL pointer for resulting string argument if str_m is zero (as per | |
93 | ISO C99). | |
94 | ||
95 | The return value is the number of characters which would be generated | |
96 | for the given input, excluding the trailing null. If this value is | |
97 | greater or equal to str_m, not all characters from the result have | |
98 | been stored in str, output bytes beyond the (str_m-1) -th character | |
99 | are discarded. If str_m is greater than zero it is guaranteed the | |
100 | resulting string will be null-terminated. | |
101 | ||
102 | NOTE that this matches the ISO C99, OpenBSD, and GNU C library 2.1, | |
103 | but is different from some older and vendor implementations, and is | |
104 | also different from XPG, XSH5, SUSv2 specifications. For historical | |
105 | discussion on changes in the semantics and standards of snprintf see | |
106 | printf(3) man page in the Linux programmers manual. | |
107 | ||
108 | Routines asprintf and vasprintf return a pointer (in the ptr argument) | |
109 | to a buffer sufficiently large to hold the resulting string. This | |
110 | pointer should be passed to free(3) to release the allocated storage | |
111 | when it is no longer needed. If sufficient space cannot be allocated, | |
112 | these functions will return -1 and set ptr to be a NULL pointer. These | |
113 | two routines are a GNU C library extensions (glibc). | |
114 | ||
115 | Routines asnprintf and vasnprintf are similar to asprintf and | |
116 | vasprintf, yet, like snprintf and vsnprintf counterparts, will write | |
117 | at most str_m-1 characters into the allocated output string, the last | |
118 | character in the allocated buffer then gets the terminating null. If | |
119 | the formatted string length (the return value) is greater than or | |
120 | equal to the str_m argument, the resulting string was truncated and | |
121 | some of the formatted characters were discarded. These routines | |
122 | present a handy way to limit the amount of allocated memory to some | |
123 | sane value. | |
124 | ||
125 | Availability | |
126 | ||
127 | http://www.ijs.si/software/snprintf/ | |
128 | * snprintf_1.3.tar.gz (1999-06-30), md5 sum: snprintf_1.3.tar.gz.md5 | |
129 | * snprintf_2.1.tar.gz (2000-07-14), md5 sum: snprintf_2.1.tar.gz.md5 | |
130 | * snprintf_2.2.tar.gz (2000-10-18), md5 sum: snprintf_2.2.tar.gz.md5 | |
131 | ||
132 | Mailing list | |
133 | ||
134 | There is a very low-traffic mailing list snprintf-announce@ijs.si | |
135 | where announcements about new versions will be posted as well as | |
136 | warnings about threatening bugs if discovered. The posting is | |
137 | restricted to snprintf developer(s). | |
138 | ||
139 | To subscribe to (or unsubscribe from) the mailing list please visit | |
140 | the list server's web page | |
141 | http://mailman.ijs.si/listinfo/snprintf-announce | |
142 | ||
143 | You can also subscribe to the list by mailing the command SUBSCRIBE | |
144 | either in the subject or in the message body to the address | |
145 | snprintf-announce-request@ijs.si . You will be asked for confirmation | |
146 | before subscription will be effective. | |
147 | ||
148 | The list of members is only accessible to the list administrator, so | |
149 | there is no need for concern about automatic e-mail address gatherers. | |
150 | ||
151 | Questions about the mailing list and concerns for the attention of a | |
152 | person should be sent to snprintf-announce-admin@ijs.si | |
153 | ||
154 | There is no general discussion list about portable snprintf at the | |
155 | moment. Please send comments and suggestion to the author. | |
156 | ||
157 | Revision history | |
158 | ||
159 | Version 1.3 fixes a runaway loop problem from 1.2. Please upgrade. | |
160 | ||
161 | 1999-06-30 V1.3 Mark Martinec <mark.martinec@ijs.si> | |
162 | ||
163 | + fixed runaway loop (eventually crashing when str_l wraps | |
164 | beyond 2^31) while copying format string without conversion | |
165 | specifiers to a buffer that is too short (thanks to Edwin | |
166 | Young <edwiny@autonomy.com> for spotting the problem); | |
167 | + added macros PORTABLE_SNPRINTF_VERSION_(MAJOR|MINOR) to | |
168 | snprintf.h | |
169 | ||
170 | 2000-02-14 V2.0 (never released) Mark Martinec <mark.martinec@ijs.si> | |
171 | ||
172 | + relaxed license terms: The Artistic License now applies. You | |
173 | may still apply the GNU GENERAL PUBLIC LICENSE as was | |
174 | distributed with previous versions, if you prefer; | |
175 | + changed REVISION HISTORY dates to use ISO 8601 date format; | |
176 | + added vsnprintf (patch also independently proposed by Caolán | |
177 | McNamara 2000-05-04, and Keith M Willenson 2000-06-01) | |
178 | ||
179 | 2000-06-27 V2.1 Mark Martinec <mark.martinec@ijs.si> | |
180 | ||
181 | + removed POSIX check for str_m < 1; value 0 for str_m is | |
182 | allowed by ISO C99 (and GNU C library 2.1) (pointed out on | |
183 | 2000-05-04 by Caolán McNamara, caolan@ csn dot ul dot ie). | |
184 | Besides relaxed license this change in standards adherence is | |
185 | the main reason to bump up the major version number; | |
186 | + added nonstandard routines asnprintf, vasnprintf, asprintf, | |
187 | vasprintf that dynamically allocate storage for the resulting | |
188 | string; these routines are not compiled by default, see | |
189 | comments where NEED_V?ASN?PRINTF macros are defined; | |
190 | + autoconf contributed by Caolán McNamara | |
191 | ||
192 | 2000-10-06 V2.2 Mark Martinec <mark.martinec@ijs.si> | |
193 | ||
194 | + BUG FIX: the %c conversion used a temporary variable that was | |
195 | no longer in scope when referenced, possibly causing | |
196 | incorrect resulting character; | |
197 | + BUG FIX: make precision and minimal field width unsigned to | |
198 | handle huge values (2^31 <= n < 2^32) correctly; also be more | |
199 | careful in the use of signed/unsigned/size_t internal | |
200 | variables -- probably more careful than many vendor | |
201 | implementations, but there may still be a case where huge | |
202 | values of str_m, precision or minimal field could cause | |
203 | incorrect behaviour; | |
204 | + use separate variables for signed/unsigned arguments, and for | |
205 | short/int, long, and long long argument lengths to avoid | |
206 | possible incompatibilities on certain computer architectures. | |
207 | Also use separate variable arg_sign to hold sign of a numeric | |
208 | argument, to make code more transparent; | |
209 | + some fiddling with zero padding and "0x" to make it Linux | |
210 | compatible; | |
211 | + systematically use macros fast_memcpy and fast_memset instead | |
212 | of case-by-case hand optimization; determine some breakeven | |
213 | string lengths for different architectures; | |
214 | + terminology change: format -> conversion specifier, C9x -> | |
215 | ISO/IEC 9899:1999 ("ISO C99"), alternative form -> alternate | |
216 | form, data type modifier -> length modifier; | |
217 | + several comments rephrased and new ones added; | |
218 | + make compiler not complain about 'credits' defined but not | |
219 | used; | |
220 | ||
221 | Other implementations of snprintf | |
222 | ||
223 | I am aware of some other (more or less) portable implementations of | |
224 | snprintf. I do not claim they are free software - please refer to | |
225 | their respective copyright and licensing terms. If you know of other | |
226 | versions please let me know. | |
227 | * a very thorough implementation (src/util_snprintf.c) by the Apache | |
228 | Group distributed with the Apache web server - | |
229 | http://www.apache.org/ . Does its own floating point conversions | |
230 | using routines ecvt(3), fcvt(3) and gcvt(3) from the standard C | |
231 | library or from the GNU libc. | |
232 | This is from the code: | |
233 | ||
234 | This software [...] was originally based on public domain software | |
235 | written at the National Center for Supercomputing Applications, | |
236 | University of Illinois, Urbana-Champaign. | |
237 | [...] This code is based on, and used with the permission of, the | |
238 | SIO stdio-replacement strx_* functions by Panos Tsirigotis | |
239 | <panos@alumni.cs.colorado.edu> for xinetd. | |
240 | * QCI Utilities use a modified version of snprintf from the Apache | |
241 | group. | |
242 | * implementations as distributed with OpenBSD, FreeBSD, and NetBSD | |
243 | are all wrappers to vfprintf.c, which is derived from software | |
244 | contributed to Berkeley by Chris Torek. | |
245 | * implementation from Prof. Patrick Powell <papowell@sdsu.edu>, | |
246 | Dept. Electrical and Computer Engineering, San Diego State | |
247 | University, San Diego, CA 92182-1309, published in Bugtraq | |
248 | archives for 3rd quarter (Jul-Aug) 1995. No floating point | |
249 | conversions. | |
250 | * Brandon Long's <blong@fiction.net> modified version of Prof. | |
251 | Patrick Powell's snprintf with contributions from others. With | |
252 | minimal floating point support. | |
253 | * implementation (src/snprintf.c) as distributed with sendmail - | |
254 | http://www.sendmail.org/ is a cleaned up Prof. Patrick Powell's | |
255 | version to compile properly and to support .precision and %lx. | |
256 | * implementation from Caolán McNamara available at | |
257 | http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz, handles | |
258 | floating point. | |
259 | * implementation used by newlog (a replacement for syslog(3)) made | |
260 | available by the SOS Corporation. Enabling floating point support | |
261 | is a compile-time option. | |
262 | * implementation by Michael Richardson <mcr@metis.milkyway.com> is | |
263 | available at http://sandelman.ottawa.on.ca/SSW/snp/snp.html. It is | |
264 | based on BSD44-lite's vfprintf() call, modified to function on | |
265 | SunOS. Needs internal routines from the 4.4 strtod (included), | |
266 | requires GCC to compile the long long (aka quad_t) portions. | |
267 | * implementation from Tomi Salo <ttsalo@ssh.fi> distributed with SSH | |
268 | 2.0 Unix Server. Not in public domain. Floating point conversions | |
269 | done by system's sprintf. | |
270 | * and for completeness: my portable version described in this very | |
271 | document available at http://www.ijs.si/software/snprintf/ . | |
272 | ||
273 | In retrospect, it appears that a lot of effort was wasted by many | |
274 | people for not being aware of what others are doing. Sigh. | |
275 | ||
276 | Also of interest: The Approved Base Working Group Resolution for XSH5, | |
277 | Ref: bwg98-006, Topic: snprintf. | |
278 | _________________________________________________________________ | |
279 | ||
280 | mm | |
281 | Last updated: 2000-10-18 | |
282 | ||
283 | Valid HTML 4.0! |