]>
Commit | Line | Data |
---|---|---|
616915dd | 1 | /* |
11db3170 | 2 | ** Splint - annotation-assisted static program checker |
77d37419 | 3 | ** Copyright (C) 1994-2002 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 | ||
43 | /* char *s, anytype v */ | |
44 | /*@notfunction@*/ | |
45 | # define GETPRINTF(s,v) (sprintf (strbuf, s, v), mstring_copy (strbuf)) | |
46 | ||
47 | /* | |
48 | ** returns control code indicated by *c, and | |
49 | ** advances *c to next character. | |
50 | */ | |
51 | ||
28bf4b0b | 52 | static ccode identify_control (char **s) |
616915dd | 53 | { |
54 | char c; | |
55 | ||
56 | modcode = 0; | |
57 | ||
58 | c = **s; | |
59 | if (c == '\0') | |
60 | { | |
61 | return (XINVALID); | |
62 | } | |
63 | ||
64 | if (c >= '0' && c <= '9') | |
65 | { | |
28bf4b0b | 66 | modcode = reader_getInt (s); |
616915dd | 67 | } |
68 | ||
69 | c = **s; | |
70 | ||
71 | (*s)++; | |
72 | ||
73 | /* | |
74 | ** handle single-char codes | |
75 | */ | |
76 | ||
77 | switch (c) | |
78 | { | |
79 | case '%': | |
80 | return (XPERCENT); | |
81 | case 'h': | |
82 | case 'c': | |
83 | return (XCHAR); | |
84 | case 's': | |
85 | return (XSTRING); | |
86 | case 'q': | |
87 | return (XSTRINGFREE); | |
88 | case 'x': | |
89 | return (XSTRINGFREE); | |
90 | case 'd': | |
91 | return (XINT); | |
92 | case 'u': | |
93 | return (XINT); /* unsigned */ | |
94 | case 'w': | |
95 | return (XINT); /* unsigned long */ | |
96 | case 'f': | |
97 | return (XFLOAT); | |
98 | case 'b': | |
99 | return (XBOOL); | |
100 | case 't': | |
101 | return (XCTYPE); | |
2c88d156 | 102 | case 'p': |
103 | return (XPOINTER); | |
616915dd | 104 | case 'l': |
105 | return (XFILELOC); | |
28bf4b0b | 106 | case '&': |
616915dd | 107 | return (XPLURAL); |
108 | case 'r': | |
109 | return (XREPREFIX); | |
110 | default: | |
111 | llcontbug (message ("Message: invalid code: %h (%s)", c, | |
112 | cstring_fromChars (*s))); | |
113 | return (XINVALID); | |
114 | } | |
115 | } | |
116 | ||
117 | /* | |
118 | ** message | |
119 | ** | |
120 | ** returns a cstring containing the message, as formated by s. | |
121 | ** | |
122 | ** the format codes are similar to printf: | |
123 | ** | |
124 | ** %s cstring (don't free after print) | |
125 | ** %q cstring (free after print) | |
126 | ** %d int | |
127 | ** %f float | |
128 | ** %b bool (uses bool_unparse) | |
129 | ** %u uentry | |
130 | ** %l fileloc | |
131 | ** %t ctype | |
132 | */ | |
133 | ||
134 | ||
135 | # if USEVARARGS | |
136 | cstring | |
137 | message (fmt, va_alist) | |
138 | char *fmt; | |
139 | va_dcl | |
140 | # else | |
141 | /*@messagelike@*/ /*@only@*/ cstring | |
142 | message (/*@temp@*/ char *fmt, ...) | |
143 | # endif | |
144 | { | |
145 | char c; | |
146 | int lastint = 0; | |
147 | char *ret = mstring_createEmpty (); | |
148 | char *ofmt = fmt; | |
149 | va_list pvar; | |
150 | ||
151 | # if USEVARARGS | |
152 | va_start (pvar); | |
153 | # else | |
154 | va_start (pvar, fmt); | |
155 | # endif | |
156 | ||
157 | while ((c = *fmt++) != '\0') | |
158 | { | |
159 | if (c == '%') | |
160 | { | |
161 | /*@-loopswitchbreak@*/ | |
162 | ||
163 | switch (identify_control (&fmt)) | |
164 | { | |
165 | case XPERCENT: | |
166 | { | |
167 | ret = mstring_concatFree1 (ret, "%"); | |
168 | break; | |
169 | } | |
170 | case XCHAR: | |
171 | { | |
172 | /* | |
173 | ** some systems don't handle char va_arg correctly, so it must be | |
174 | ** passed as an int here | |
175 | */ | |
176 | ||
177 | char lc = (char) va_arg (pvar, int); | |
178 | ||
179 | ret = mstring_append (ret, lc); | |
180 | break; | |
181 | } | |
182 | case XSTRING: | |
183 | { | |
184 | cstring s = va_arg (pvar, cstring); | |
185 | ||
186 | if (modcode != 0) | |
187 | { | |
188 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
abd7f895 | 189 | (cstring_fill (s, size_fromInt (modcode)))); |
616915dd | 190 | } |
191 | else | |
192 | { | |
193 | if (cstring_isDefined (s)) | |
194 | { | |
195 | ret = mstring_concatFree1 (ret, cstring_toCharsSafe (s)); | |
196 | } | |
197 | } | |
198 | } | |
199 | break; | |
200 | case XSTRINGFREE: | |
201 | case XTSTRINGFREE: | |
202 | { | |
203 | cstring s = va_arg (pvar, cstring); | |
204 | ||
205 | if (modcode != 0) | |
206 | { | |
207 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
abd7f895 | 208 | (cstring_fill (s, size_fromInt (modcode)))); |
616915dd | 209 | } |
210 | else | |
211 | { | |
212 | if (cstring_isDefined (s)) | |
213 | { | |
214 | ret = mstring_concatFree | |
215 | (ret, cstring_toCharsSafe (s)); | |
216 | } | |
217 | } | |
218 | } | |
219 | break; | |
220 | case XREPREFIX: | |
221 | lastint = va_arg (pvar, int); | |
222 | ||
223 | if (lastint != 0) | |
224 | { | |
225 | ret = mstring_concatFree1 (ret, "re"); | |
226 | } | |
227 | break; | |
228 | case XPLURAL: | |
229 | if (lastint != 1) | |
230 | { | |
231 | ret = mstring_concatFree1 (ret, "s"); | |
232 | } | |
233 | break; | |
234 | case XINT: | |
235 | lastint = va_arg (pvar, int); | |
236 | ret = mstring_concatFree (ret, GETPRINTF ("%d", lastint)); | |
237 | break; | |
238 | case XFLOAT: | |
ce7034f0 | 239 | ret = mstring_concatFree (ret, GETPRINTF ("%.2lf", va_arg (pvar, double))); |
616915dd | 240 | break; |
241 | case XBOOL: | |
242 | ret = mstring_concatFree1 (ret, cstring_toCharsSafe | |
243 | (bool_unparse (va_arg (pvar, bool)))); | |
244 | break; | |
245 | case XUENTRY: | |
246 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
247 | (uentry_unparse (va_arg (pvar, uentry)))); | |
248 | break; | |
249 | case XCTYPE: | |
250 | /* cannot free ctype_unparse */ | |
251 | ret = mstring_concatFree1 (ret, cstring_toCharsSafe | |
252 | (ctype_unparse (va_arg (pvar, ctype)))); | |
253 | break; | |
2c88d156 | 254 | case XPOINTER: |
255 | ret = mstring_concatFree (ret, GETPRINTF ("%p", va_arg (pvar, void *))); | |
256 | break; | |
257 | ||
616915dd | 258 | case XFILELOC: |
259 | ret = mstring_concatFree (ret, cstring_toCharsSafe | |
260 | (fileloc_unparse (va_arg (pvar, fileloc)))); | |
261 | break; | |
262 | case XINVALID: | |
263 | default: | |
264 | llcontbug (cstring_makeLiteral ("message: bad control flag")); | |
265 | fprintf (stdout, "\tFormat string: %s", ofmt); | |
266 | } | |
267 | /*@=loopswitchbreak@*/ | |
268 | } | |
269 | else | |
270 | { | |
271 | ret = mstring_append (ret, c); | |
272 | } | |
273 | } | |
274 | ||
275 | va_end (pvar); | |
276 | ||
277 | /* | |
278 | ** cstring_fromChars returns the same storage (exposed) | |
279 | */ | |
280 | ||
281 | /*@-mustfree@*/ return (cstring_fromChars (ret)); /*@=mustfree@*/ | |
282 | } |