]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
c59f5181 | 3 | ** Copyright (C) 1994-2003 University of Virginia, |
616915dd | 4 | ** Massachusetts Institute of Technology |
5 | ** | |
6 | ** This program is free software; you can redistribute it and/or modify it | |
7 | ** under the terms of the GNU General Public License as published by the | |
8 | ** Free Software Foundation; either version 2 of the License, or (at your | |
9 | ** option) any later version. | |
10 | ** | |
11 | ** This program is distributed in the hope that it will be useful, but | |
12 | ** WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | ** General Public License for more details. | |
15 | ** | |
16 | ** The GNU General Public License is available from http://www.gnu.org/ or | |
17 | ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
18 | ** MA 02111-1307, USA. | |
19 | ** | |
155af98d | 20 | ** For information on splint: info@splint.org |
21 | ** To report a bug: splint-bug@splint.org | |
11db3170 | 22 | ** For more information: http://www.splint.org |
616915dd | 23 | */ |
24 | /* | |
25 | ** message.c | |
26 | */ | |
27 | ||
1b8ae690 | 28 | # include "splintMacros.nf" |
616915dd | 29 | # include "basic.h" |
30 | ||
31 | /* patch for linux? solaris? */ | |
32 | ||
33 | static char strbuf[64]; | |
34 | static int modcode; | |
35 | ||
36 | typedef enum | |
37 | { | |
38 | XINVALID, | |
39 | XCHAR, XSTRING, XSTRINGFREE, XTSTRINGFREE, XINT, XFLOAT, XBOOL, XUENTRY, | |
2c88d156 | 40 | XPERCENT, XCTYPE, XPLURAL, XREPREFIX, XFILELOC, XPOINTER |
616915dd | 41 | } ccode; |
42 | ||
53306cab | 43 | /*@function void GETPRINTF (char *p_s, anytype p_v) modifies strbuf@*/ |
44 | ||
616915dd | 45 | /*@notfunction@*/ |
53306cab | 46 | # ifndef WIN32 |
47 | /* ISO requires this, but not all implementations (e.g., Microsoft's) provide it */ | |
f9264521 | 48 | # define GETPRINTF(s,v) (snprintf (strbuf, 64, s, v), mstring_copy (strbuf)) |
53306cab | 49 | # else |
50 | /* MS provides _snprintf instead */ | |
51 | # define GETPRINTF(s,v) (_snprintf (strbuf, 64, s, v), mstring_copy (strbuf)) | |
52 | # endif | |
616915dd | 53 | |
54 | /* | |
55 | ** returns control code indicated by *c, and | |
56 | ** advances *c to next character. | |
57 | */ | |
58 | ||
28bf4b0b | 59 | static ccode identify_control (char **s) |
616915dd | 60 | { |
61 | char c; | |
62 | ||
63 | modcode = 0; | |
64 | ||
65 | c = **s; | |
66 | if (c == '\0') | |
67 | { | |
68 | return (XINVALID); | |
69 | } | |
70 | ||
71 | if (c >= '0' && c <= '9') | |
72 | { | |
28bf4b0b | 73 | modcode = reader_getInt (s); |
616915dd | 74 | } |
75 | ||
76 | c = **s; | |
77 | ||
78 | (*s)++; | |
79 | ||
80 | /* | |
81 | ** handle single-char codes | |
82 | */ | |
83 | ||
84 | switch (c) | |
85 | { | |
86 | case '%': | |
87 | return (XPERCENT); | |
88 | case 'h': | |
89 | case 'c': | |
90 | return (XCHAR); | |
91 | case 's': | |
92 | return (XSTRING); | |
93 | case 'q': | |
94 | return (XSTRINGFREE); | |
95 | case 'x': | |
96 | return (XSTRINGFREE); | |
97 | case 'd': | |
98 | return (XINT); | |
99 | case 'u': | |
100 | return (XINT); /* unsigned */ | |
101 | case 'w': | |
102 | return (XINT); /* unsigned long */ | |
103 | case 'f': | |
104 | return (XFLOAT); | |
105 | case 'b': | |
106 | return (XBOOL); | |
107 | case 't': | |
108 | return (XCTYPE); | |
2c88d156 | 109 | case 'p': |
110 | return (XPOINTER); | |
616915dd | 111 | case 'l': |
112 | return (XFILELOC); | |
28bf4b0b | 113 | case '&': |
616915dd | 114 | return (XPLURAL); |
115 | case 'r': | |
116 | return (XREPREFIX); | |
117 | default: | |
118 | llcontbug (message ("Message: invalid code: %h (%s)", c, | |
119 | cstring_fromChars (*s))); | |
120 | return (XINVALID); | |
121 | } | |
122 | } | |
123 | ||
124 | /* | |
125 | ** message | |
126 | ** | |
127 | ** returns a cstring containing the message, as formated by s. | |
128 | ** | |
129 | ** the format codes are similar to printf: | |
130 | ** | |
131 | ** %s cstring (don't free after print) | |
132 | ** %q cstring (free after print) | |
133 | ** %d int | |
134 | ** %f float | |
135 | ** %b bool (uses bool_unparse) | |
136 | ** %u uentry | |
137 | ** %l fileloc | |
138 | ** %t ctype | |
139 | */ | |
140 | ||
141 | ||
142 | # if USEVARARGS | |
143 | cstring | |
144 | message (fmt, va_alist) | |
145 | char *fmt; | |
146 | va_dcl | |
147 | # else | |
148 | /*@messagelike@*/ /*@only@*/ cstring | |
149 | message (/*@temp@*/ char *fmt, ...) | |
150 | # endif | |
151 | { | |
152 | char c; | |
153 | int lastint = 0; | |
154 | char *ret = mstring_createEmpty (); | |
155 | char *ofmt = fmt; | |
156 | va_list pvar; | |
157 | ||
158 | # if USEVARARGS | |
159 | va_start (pvar); | |
160 | # else | |
161 | va_start (pvar, fmt); | |
162 | # endif | |
163 | ||
164 | while ((c = *fmt++) != '\0') | |
165 | { | |
166 | if (c == '%') | |
167 | { | |
168 | /*@-loopswitchbreak@*/ | |
169 | ||
170 | switch (identify_control (&fmt)) | |
171 | { | |
172 | case XPERCENT: | |
173 | { | |
174 | ret = mstring_concatFree1 (ret, "%"); | |
175 | break; | |
176 | } | |
177 | case XCHAR: | |
178 | { | |
179 | /* | |
180 | ** some systems don't handle char va_arg correctly, so it must be | |
181 | ** passed as an int here | |
182 | */ | |
183 | ||
184 | char lc = (char) va_arg (pvar, int); | |
185 | ||
186 | ret = mstring_append (ret, lc); | |
187 | break; | |
188 | } | |
189 | case XSTRING: | |
190 | { | |
191 | cstring s = va_arg (pvar, cstring); | |
192 | ||
193 | if (modcode != 0) | |
194 | { | |
195 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
abd7f895 | 196 | (cstring_fill (s, size_fromInt (modcode)))); |
616915dd | 197 | } |
198 | else | |
199 | { | |
200 | if (cstring_isDefined (s)) | |
201 | { | |
202 | ret = mstring_concatFree1 (ret, cstring_toCharsSafe (s)); | |
203 | } | |
204 | } | |
205 | } | |
206 | break; | |
207 | case XSTRINGFREE: | |
208 | case XTSTRINGFREE: | |
209 | { | |
210 | cstring s = va_arg (pvar, cstring); | |
211 | ||
212 | if (modcode != 0) | |
213 | { | |
214 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
abd7f895 | 215 | (cstring_fill (s, size_fromInt (modcode)))); |
616915dd | 216 | } |
217 | else | |
218 | { | |
219 | if (cstring_isDefined (s)) | |
220 | { | |
221 | ret = mstring_concatFree | |
222 | (ret, cstring_toCharsSafe (s)); | |
223 | } | |
224 | } | |
225 | } | |
226 | break; | |
227 | case XREPREFIX: | |
228 | lastint = va_arg (pvar, int); | |
229 | ||
230 | if (lastint != 0) | |
231 | { | |
232 | ret = mstring_concatFree1 (ret, "re"); | |
233 | } | |
234 | break; | |
235 | case XPLURAL: | |
236 | if (lastint != 1) | |
237 | { | |
238 | ret = mstring_concatFree1 (ret, "s"); | |
239 | } | |
240 | break; | |
241 | case XINT: | |
242 | lastint = va_arg (pvar, int); | |
243 | ret = mstring_concatFree (ret, GETPRINTF ("%d", lastint)); | |
244 | break; | |
245 | case XFLOAT: | |
ce7034f0 | 246 | ret = mstring_concatFree (ret, GETPRINTF ("%.2lf", va_arg (pvar, double))); |
616915dd | 247 | break; |
248 | case XBOOL: | |
4caf866b | 249 | ret = mstring_concatFree1 |
250 | (ret, cstring_toCharsSafe | |
251 | (bool_unparse (bool_fromInt ((va_arg (pvar, int)))))); | |
252 | /* va_arg should not use bool type */ | |
616915dd | 253 | break; |
254 | case XUENTRY: | |
255 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
256 | (uentry_unparse (va_arg (pvar, uentry)))); | |
257 | break; | |
258 | case XCTYPE: | |
259 | /* cannot free ctype_unparse */ | |
260 | ret = mstring_concatFree1 (ret, cstring_toCharsSafe | |
261 | (ctype_unparse (va_arg (pvar, ctype)))); | |
262 | break; | |
2c88d156 | 263 | case XPOINTER: |
264 | ret = mstring_concatFree (ret, GETPRINTF ("%p", va_arg (pvar, void *))); | |
265 | break; | |
266 | ||
616915dd | 267 | case XFILELOC: |
268 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
269 | (fileloc_unparse (va_arg (pvar, fileloc)))); | |
270 | break; | |
271 | case XINVALID: | |
272 | default: | |
273 | llcontbug (cstring_makeLiteral ("message: bad control flag")); | |
274 | fprintf (stdout, "\tFormat string: %s", ofmt); | |
275 | } | |
276 | /*@=loopswitchbreak@*/ | |
277 | } | |
278 | else | |
279 | { | |
280 | ret = mstring_append (ret, c); | |
281 | } | |
282 | } | |
283 | ||
284 | va_end (pvar); | |
285 | ||
286 | /* | |
287 | ** cstring_fromChars returns the same storage (exposed) | |
288 | */ | |
289 | ||
290 | /*@-mustfree@*/ return (cstring_fromChars (ret)); /*@=mustfree@*/ | |
291 | } |