| @@ -1,569 +1,582 @@ | | | @@ -1,569 +1,582 @@ |
1 | /* $NetBSD: tparm.c,v 1.11 2013/01/24 10:28:28 roy Exp $ */ | | 1 | /* $NetBSD: tparm.c,v 1.12 2013/01/24 10:41:28 roy Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2009, 2011 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2009, 2011, 2013 The NetBSD Foundation, Inc. |
5 | * | | 5 | * |
6 | * This code is derived from software contributed to The NetBSD Foundation | | 6 | * This code is derived from software contributed to The NetBSD Foundation |
7 | * by Roy Marples. | | 7 | * by Roy Marples. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * | | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ | | 28 | */ |
29 | | | 29 | |
30 | #include <sys/cdefs.h> | | 30 | #include <sys/cdefs.h> |
31 | __RCSID("$NetBSD: tparm.c,v 1.11 2013/01/24 10:28:28 roy Exp $"); | | 31 | __RCSID("$NetBSD: tparm.c,v 1.12 2013/01/24 10:41:28 roy Exp $"); |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | | | 33 | |
34 | #include <assert.h> | | 34 | #include <assert.h> |
35 | #include <ctype.h> | | 35 | #include <ctype.h> |
36 | #include <errno.h> | | 36 | #include <errno.h> |
37 | #include <stdarg.h> | | 37 | #include <stdarg.h> |
38 | #include <stdio.h> | | 38 | #include <stdio.h> |
39 | #include <stdlib.h> | | 39 | #include <stdlib.h> |
40 | #include <string.h> | | 40 | #include <string.h> |
41 | #include <term_private.h> | | 41 | #include <term_private.h> |
42 | #include <term.h> | | 42 | #include <term.h> |
43 | | | 43 | |
44 | #define LONG_STR_MAX ((CHAR_BIT * sizeof(long)) / 3) | | 44 | #define LONG_STR_MAX ((CHAR_BIT * sizeof(long)) / 3) |
45 | #define BUFINC 128 /* Size to increament the terminal buffer by */ | | 45 | #define BUFINC 128 /* Size to increament the terminal buffer by */ |
46 | | | 46 | |
47 | static TERMINAL *dumbterm; /* For non thread safe functions */ | | 47 | static TERMINAL *dumbterm; /* For non thread safe functions */ |
48 | | | 48 | |
49 | typedef struct { | | 49 | typedef struct { |
50 | long nums[20]; | | 50 | long nums[20]; |
51 | char *strings[20]; | | 51 | char *strings[20]; |
52 | size_t offset; | | 52 | size_t offset; |
53 | } TPSTACK; | | 53 | } TPSTACK; |
54 | | | 54 | |
55 | typedef struct { | | 55 | typedef struct { |
56 | long num; | | 56 | long num; |
57 | char *string; | | 57 | char *string; |
58 | } TPVAR; | | 58 | } TPVAR; |
59 | | | 59 | |
60 | static int | | 60 | static int |
61 | push(long num, char *string, TPSTACK *stack) | | 61 | push(long num, char *string, TPSTACK *stack) |
62 | { | | 62 | { |
63 | if (stack->offset >= sizeof(stack->nums)) { | | 63 | if (stack->offset >= sizeof(stack->nums)) { |
64 | errno = E2BIG; | | 64 | errno = E2BIG; |
65 | return -1; | | 65 | return -1; |
66 | } | | 66 | } |
67 | stack->nums[stack->offset] = num; | | 67 | stack->nums[stack->offset] = num; |
68 | stack->strings[stack->offset] = string; | | 68 | stack->strings[stack->offset] = string; |
69 | stack->offset++; | | 69 | stack->offset++; |
70 | return 0; | | 70 | return 0; |
71 | } | | 71 | } |
72 | | | 72 | |
73 | static int | | 73 | static int |
74 | pop(long *num, char **string, TPSTACK *stack) | | 74 | pop(long *num, char **string, TPSTACK *stack) |
75 | { | | 75 | { |
76 | if (stack->offset == 0) { | | 76 | if (stack->offset == 0) { |
77 | if (num) | | 77 | if (num) |
78 | *num = 0; | | 78 | *num = 0; |
79 | if (string) | | 79 | if (string) |
80 | *string = NULL; | | 80 | *string = NULL; |
81 | errno = E2BIG; | | 81 | errno = E2BIG; |
82 | return -1; | | 82 | return -1; |
83 | } | | 83 | } |
84 | stack->offset--; | | 84 | stack->offset--; |
85 | if (num) | | 85 | if (num) |
86 | *num = stack->nums[stack->offset]; | | 86 | *num = stack->nums[stack->offset]; |
87 | if (string) | | 87 | if (string) |
88 | *string = stack->strings[stack->offset]; | | 88 | *string = stack->strings[stack->offset]; |
89 | return 0; | | 89 | return 0; |
90 | } | | 90 | } |
91 | | | 91 | |
92 | static char * | | 92 | static char * |
93 | checkbuf(TERMINAL *term, size_t len) | | 93 | checkbuf(TERMINAL *term, size_t len) |
94 | { | | 94 | { |
95 | char *buf; | | 95 | char *buf; |
96 | | | 96 | |
97 | if (term->_bufpos + len >= term->_buflen) { | | 97 | if (term->_bufpos + len >= term->_buflen) { |
98 | len = term->_buflen + MAX(len, BUFINC); | | 98 | len = term->_buflen + MAX(len, BUFINC); |
99 | buf = realloc(term->_buf, len); | | 99 | buf = realloc(term->_buf, len); |
100 | if (buf == NULL) | | 100 | if (buf == NULL) |
101 | return NULL; | | 101 | return NULL; |
102 | term->_buf = buf; | | 102 | term->_buf = buf; |
103 | term->_buflen = len; | | 103 | term->_buflen = len; |
104 | } | | 104 | } |
105 | return term->_buf; | | 105 | return term->_buf; |
106 | } | | 106 | } |
107 | | | 107 | |
108 | static size_t | | 108 | static size_t |
109 | ochar(TERMINAL *term, int c) | | 109 | ochar(TERMINAL *term, int c) |
110 | { | | 110 | { |
111 | if (c == 0) | | 111 | if (c == 0) |
112 | c = 0200; | | 112 | c = 0200; |
113 | /* Check we have space and a terminator */ | | 113 | /* Check we have space and a terminator */ |
114 | if (checkbuf(term, 2) == NULL) | | 114 | if (checkbuf(term, 2) == NULL) |
115 | return 0; | | 115 | return 0; |
116 | term->_buf[term->_bufpos++] = (char)c; | | 116 | term->_buf[term->_bufpos++] = (char)c; |
117 | return 1; | | 117 | return 1; |
118 | } | | 118 | } |
119 | | | 119 | |
120 | static size_t | | 120 | static size_t |
121 | onum(TERMINAL *term, const char *fmt, int num, unsigned int len) | | 121 | onum(TERMINAL *term, const char *fmt, int num, unsigned int len) |
122 | { | | 122 | { |
123 | size_t l; | | 123 | size_t l; |
124 | | | 124 | |
125 | if (len < LONG_STR_MAX) | | 125 | if (len < LONG_STR_MAX) |
126 | len = LONG_STR_MAX; | | 126 | len = LONG_STR_MAX; |
127 | if (checkbuf(term, len + 2) == NULL) | | 127 | if (checkbuf(term, len + 2) == NULL) |
128 | return 0; | | 128 | return 0; |
129 | l = sprintf(term->_buf + term->_bufpos, fmt, num); | | 129 | l = sprintf(term->_buf + term->_bufpos, fmt, num); |
130 | term->_bufpos += l; | | 130 | term->_bufpos += l; |
131 | return l; | | 131 | return l; |
132 | } | | 132 | } |
133 | | | 133 | |
| | | 134 | /* |
| | | 135 | Make a pass through the string so we can work out |
| | | 136 | which parameters are ints and which are char *. |
| | | 137 | Basically we only use char * if %p[1-9] is followed by %l or %s. |
| | | 138 | */ |
| | | 139 | int |
| | | 140 | _ti_parm_analyse(const char *str, int *piss, int piss_len) |
| | | 141 | { |
| | | 142 | int nparm, lpop; |
| | | 143 | char c; |
| | | 144 | |
| | | 145 | nparm = 0; |
| | | 146 | lpop = -1; |
| | | 147 | while ((c = *str++) != '\0') { |
| | | 148 | if (c != '%') |
| | | 149 | continue; |
| | | 150 | c = *str++; |
| | | 151 | switch (c) { |
| | | 152 | case 'l': /* FALLTHROUGH */ |
| | | 153 | case 's': |
| | | 154 | if (lpop > 0) { |
| | | 155 | if (lpop <= piss_len) |
| | | 156 | piss[lpop - 1] = 1; |
| | | 157 | else if (piss) |
| | | 158 | errno = E2BIG; |
| | | 159 | } |
| | | 160 | break; |
| | | 161 | case 'p': |
| | | 162 | c = *str++; |
| | | 163 | if (c < '1' || c > '9') { |
| | | 164 | errno = EINVAL; |
| | | 165 | continue; |
| | | 166 | } else { |
| | | 167 | lpop = c - '0'; |
| | | 168 | if (lpop > nparm) |
| | | 169 | nparm = lpop; |
| | | 170 | } |
| | | 171 | break; |
| | | 172 | default: |
| | | 173 | lpop = -1; |
| | | 174 | } |
| | | 175 | } |
| | | 176 | |
| | | 177 | return nparm; |
| | | 178 | } |
| | | 179 | |
134 | static char * | | 180 | static char * |
135 | _ti_tiparm(TERMINAL *term, const char *str, int va_long, va_list parms) | | 181 | _ti_tiparm(TERMINAL *term, const char *str, int va_long, va_list parms) |
136 | { | | 182 | { |
137 | const char *sp; | | | |
138 | char c, fmt[64], *fp, *ostr; | | 183 | char c, fmt[64], *fp, *ostr; |
139 | long val, val2; | | 184 | long val, val2; |
140 | long dnums[26]; /* dynamic variables a-z, not preserved */ | | 185 | long dnums[26]; /* dynamic variables a-z, not preserved */ |
141 | size_t l, max; | | 186 | size_t l, max; |
142 | TPSTACK stack; | | 187 | TPSTACK stack; |
143 | TPVAR params[9]; | | 188 | TPVAR params[TPARM_MAX]; |
144 | unsigned int done, dot, minus, width, precision, olen; | | 189 | unsigned int done, dot, minus, width, precision, olen; |
145 | int piss[9]; /* Parameter IS String - piss ;) */ | | 190 | int piss[TPARM_MAX]; /* Parameter IS String - piss ;) */ |
146 | | | 191 | |
147 | if (str == NULL) | | 192 | if (str == NULL) |
148 | return NULL; | | 193 | return NULL; |
149 | | | 194 | |
150 | /* | | 195 | /* |
151 | If not passed a terminal, malloc a dummy one. | | 196 | If not passed a terminal, malloc a dummy one. |
152 | This means we can preserve buffers and variables per terminal and | | 197 | This means we can preserve buffers and variables per terminal and |
153 | still work with non thread safe functions (which sadly are still the | | 198 | still work with non thread safe functions (which sadly are still the |
154 | norm and standard). | | 199 | norm and standard). |
155 | */ | | 200 | */ |
156 | if (term == NULL) { | | 201 | if (term == NULL) { |
157 | if (dumbterm == NULL) { | | 202 | if (dumbterm == NULL) { |
158 | dumbterm = malloc(sizeof(*dumbterm)); | | 203 | dumbterm = malloc(sizeof(*dumbterm)); |
159 | if (dumbterm == NULL) | | 204 | if (dumbterm == NULL) |
160 | return NULL; | | 205 | return NULL; |
161 | dumbterm->_buflen = 0; | | 206 | dumbterm->_buflen = 0; |
162 | } | | 207 | } |
163 | term = dumbterm; | | 208 | term = dumbterm; |
164 | } | | 209 | } |
165 | | | 210 | |
166 | term->_bufpos = 0; | | 211 | term->_bufpos = 0; |
167 | /* Ensure we have an initial buffer */ | | 212 | /* Ensure we have an initial buffer */ |
168 | if (term->_buflen == 0) { | | 213 | if (term->_buflen == 0) { |
169 | term->_buf = malloc(BUFINC); | | 214 | term->_buf = malloc(BUFINC); |
170 | if (term->_buf == NULL) | | 215 | if (term->_buf == NULL) |
171 | return NULL; | | 216 | return NULL; |
172 | term->_buflen = BUFINC; | | 217 | term->_buflen = BUFINC; |
173 | } | | 218 | } |
174 | | | 219 | |
175 | /* | | | |
176 | Make a first pass through the string so we can work out | | | |
177 | which parameters are ints and which are char *. | | | |
178 | Basically we only use char * if %p[1-9] is followed by %l or %s. | | | |
179 | */ | | | |
180 | memset(&piss, 0, sizeof(piss)); | | 220 | memset(&piss, 0, sizeof(piss)); |
181 | max = 0; | | 221 | max = _ti_parm_analyse(str, piss, TPARM_MAX); |
182 | sp = str; | | | |
183 | while ((c = *sp++) != '\0') { | | | |
184 | if (c != '%') | | | |
185 | continue; | | | |
186 | c = *sp++; | | | |
187 | if (c == '\0') | | | |
188 | break; | | | |
189 | if (c != 'p') | | | |
190 | continue; | | | |
191 | c = *sp++; | | | |
192 | if (c < '1' || c > '9') { | | | |
193 | errno = EINVAL; | | | |
194 | continue; | | | |
195 | } | | | |
196 | l = c - '0'; | | | |
197 | if (l > max) | | | |
198 | max = l; | | | |
199 | if (*sp != '%') | | | |
200 | continue; | | | |
201 | /* Skip formatting */ | | | |
202 | sp++; | | | |
203 | while (*sp == '.' || *sp == '#' || *sp == ' ' || *sp == ':' || | | | |
204 | *sp == '-' || isdigit((unsigned char)*sp)) | | | |
205 | sp++; | | | |
206 | if (*sp == 'l' || *sp == 's') | | | |
207 | piss[l - 1] = 1; | | | |
208 | } | | | |
209 | | | 222 | |
210 | /* Put our parameters into variables */ | | 223 | /* Put our parameters into variables */ |
211 | memset(¶ms, 0, sizeof(params)); | | 224 | memset(¶ms, 0, sizeof(params)); |
212 | for (l = 0; l < max; l++) { | | 225 | for (l = 0; l < max; l++) { |
213 | if (piss[l]) | | 226 | if (piss[l]) |
214 | params[l].string = va_arg(parms, char *); | | 227 | params[l].string = va_arg(parms, char *); |
215 | else if (va_long) | | 228 | else if (va_long) |
216 | params[l].num = va_arg(parms, long); | | 229 | params[l].num = va_arg(parms, long); |
217 | else | | 230 | else |
218 | params[l].num = (long)va_arg(parms, int); | | 231 | params[l].num = (long)va_arg(parms, int); |
219 | } | | 232 | } |
220 | | | 233 | |
221 | memset(&stack, 0, sizeof(stack)); | | 234 | memset(&stack, 0, sizeof(stack)); |
222 | while ((c = *str++) != '\0') { | | 235 | while ((c = *str++) != '\0') { |
223 | if (c != '%' || (c = *str++) == '%') { | | 236 | if (c != '%' || (c = *str++) == '%') { |
224 | if (c == '\0') | | 237 | if (c == '\0') |
225 | break; | | 238 | break; |
226 | if (ochar(term, c) == 0) | | 239 | if (ochar(term, c) == 0) |
227 | return NULL; | | 240 | return NULL; |
228 | continue; | | 241 | continue; |
229 | } | | 242 | } |
230 | | | 243 | |
231 | /* Handle formatting. */ | | 244 | /* Handle formatting. */ |
232 | fp = fmt; | | 245 | fp = fmt; |
233 | *fp++ = '%'; | | 246 | *fp++ = '%'; |
234 | done = dot = minus = width = precision = 0; | | 247 | done = dot = minus = width = precision = 0; |
235 | val = 0; | | 248 | val = 0; |
236 | while (done == 0 && (size_t)(fp - fmt) < sizeof(fmt)) { | | 249 | while (done == 0 && (size_t)(fp - fmt) < sizeof(fmt)) { |
237 | switch (c) { | | 250 | switch (c) { |
238 | case 'c': /* FALLTHROUGH */ | | 251 | case 'c': /* FALLTHROUGH */ |
239 | case 's': | | 252 | case 's': |
240 | *fp++ = c; | | 253 | *fp++ = c; |
241 | done = 1; | | 254 | done = 1; |
242 | break; | | 255 | break; |
243 | case 'd': /* FALLTHROUGH */ | | 256 | case 'd': /* FALLTHROUGH */ |
244 | case 'o': /* FALLTHROUGH */ | | 257 | case 'o': /* FALLTHROUGH */ |
245 | case 'x': /* FALLTHROUGH */ | | 258 | case 'x': /* FALLTHROUGH */ |
246 | case 'X': /* FALLTHROUGH */ | | 259 | case 'X': /* FALLTHROUGH */ |
247 | *fp++ = 'l'; | | 260 | *fp++ = 'l'; |
248 | *fp++ = c; | | 261 | *fp++ = c; |
249 | done = 1; | | 262 | done = 1; |
250 | break; | | 263 | break; |
251 | case '#': /* FALLTHROUGH */ | | 264 | case '#': /* FALLTHROUGH */ |
252 | case ' ': | | 265 | case ' ': |
253 | *fp++ = c; | | 266 | *fp++ = c; |
254 | break; | | 267 | break; |
255 | case '.': | | 268 | case '.': |
256 | *fp++ = c; | | 269 | *fp++ = c; |
257 | if (dot == 0) { | | 270 | if (dot == 0) { |
258 | dot = 1; | | 271 | dot = 1; |
259 | width = val; | | 272 | width = val; |
260 | } else | | 273 | } else |
261 | done = 2; | | 274 | done = 2; |
262 | val = 0; | | 275 | val = 0; |
263 | break; | | 276 | break; |
264 | case ':': | | 277 | case ':': |
265 | minus = 1; | | 278 | minus = 1; |
266 | break; | | 279 | break; |
267 | case '-': | | 280 | case '-': |
268 | if (minus) | | 281 | if (minus) |
269 | *fp++ = c; | | 282 | *fp++ = c; |
270 | else | | 283 | else |
271 | done = 1; | | 284 | done = 1; |
272 | break; | | 285 | break; |
273 | default: | | 286 | default: |
274 | if (isdigit((unsigned char)c)) { | | 287 | if (isdigit((unsigned char)c)) { |
275 | val = (val * 10) + (c - '0'); | | 288 | val = (val * 10) + (c - '0'); |
276 | if (val > 10000) | | 289 | if (val > 10000) |
277 | done = 2; | | 290 | done = 2; |
278 | else | | 291 | else |
279 | *fp++ = c; | | 292 | *fp++ = c; |
280 | } else | | 293 | } else |
281 | done = 1; | | 294 | done = 1; |
282 | } | | 295 | } |
283 | if (done == 0) | | 296 | if (done == 0) |
284 | c = *str++; | | 297 | c = *str++; |
285 | } | | 298 | } |
286 | if (done == 2) { | | 299 | if (done == 2) { |
287 | /* Found an error in the format */ | | 300 | /* Found an error in the format */ |
288 | fp = fmt + 1; | | 301 | fp = fmt + 1; |
289 | *fp = *str; | | 302 | *fp = *str; |
290 | olen = 0; | | 303 | olen = 0; |
291 | } else { | | 304 | } else { |
292 | if (dot == 0) | | 305 | if (dot == 0) |
293 | width = val; | | 306 | width = val; |
294 | else | | 307 | else |
295 | precision = val; | | 308 | precision = val; |
296 | olen = MAX(width, precision); | | 309 | olen = MAX(width, precision); |
297 | } | | 310 | } |
298 | *fp++ = '\0'; | | 311 | *fp++ = '\0'; |
299 | | | 312 | |
300 | /* Handle commands */ | | 313 | /* Handle commands */ |
301 | switch (c) { | | 314 | switch (c) { |
302 | case 'c': | | 315 | case 'c': |
303 | pop(&val, NULL, &stack); | | 316 | pop(&val, NULL, &stack); |
304 | if (ochar(term, (unsigned char)val) == 0) | | 317 | if (ochar(term, (unsigned char)val) == 0) |
305 | return NULL; | | 318 | return NULL; |
306 | break; | | 319 | break; |
307 | case 's': | | 320 | case 's': |
308 | pop(NULL, &ostr, &stack); | | 321 | pop(NULL, &ostr, &stack); |
309 | if (ostr != NULL) { | | 322 | if (ostr != NULL) { |
310 | l = strlen(ostr); | | 323 | l = strlen(ostr); |
311 | if (l < (size_t)olen) | | 324 | if (l < (size_t)olen) |
312 | l = olen; | | 325 | l = olen; |
313 | if (checkbuf(term, (size_t)(l + 1)) == NULL) | | 326 | if (checkbuf(term, (size_t)(l + 1)) == NULL) |
314 | return NULL; | | 327 | return NULL; |
315 | l = sprintf(term->_buf + term->_bufpos, | | 328 | l = sprintf(term->_buf + term->_bufpos, |
316 | fmt, ostr); | | 329 | fmt, ostr); |
317 | term->_bufpos += l; | | 330 | term->_bufpos += l; |
318 | } | | 331 | } |
319 | break; | | 332 | break; |
320 | case 'l': | | 333 | case 'l': |
321 | pop(NULL, &ostr, &stack); | | 334 | pop(NULL, &ostr, &stack); |
322 | if (ostr == NULL) | | 335 | if (ostr == NULL) |
323 | l = 0; | | 336 | l = 0; |
324 | else | | 337 | else |
325 | l = strlen(ostr); | | 338 | l = strlen(ostr); |
326 | #ifdef NCURSES_COMPAT_57 | | 339 | #ifdef NCURSES_COMPAT_57 |
327 | if (onum(term, "%ld", (long)l, 0) == 0) | | 340 | if (onum(term, "%ld", (long)l, 0) == 0) |
328 | return NULL; | | 341 | return NULL; |
329 | #else | | 342 | #else |
330 | push((long)l, NULL, &stack); | | 343 | push((long)l, NULL, &stack); |
331 | #endif | | 344 | #endif |
332 | break; | | 345 | break; |
333 | case 'd': /* FALLTHROUGH */ | | 346 | case 'd': /* FALLTHROUGH */ |
334 | case 'o': /* FALLTHROUGH */ | | 347 | case 'o': /* FALLTHROUGH */ |
335 | case 'x': /* FALLTHROUGH */ | | 348 | case 'x': /* FALLTHROUGH */ |
336 | case 'X': | | 349 | case 'X': |
337 | pop(&val, NULL, &stack); | | 350 | pop(&val, NULL, &stack); |
338 | if (onum(term, fmt, (int)val, olen) == 0) | | 351 | if (onum(term, fmt, (int)val, olen) == 0) |
339 | return NULL; | | 352 | return NULL; |
340 | break; | | 353 | break; |
341 | case 'p': | | 354 | case 'p': |
342 | if (*str < '1' || *str > '9') | | 355 | if (*str < '1' || *str > '9') |
343 | break; | | 356 | break; |
344 | l = *str++ - '1'; | | 357 | l = *str++ - '1'; |
345 | if (push(params[l].num, params[l].string, &stack)) | | 358 | if (push(params[l].num, params[l].string, &stack)) |
346 | return NULL; | | 359 | return NULL; |
347 | break; | | 360 | break; |
348 | case 'P': | | 361 | case 'P': |
349 | pop(&val, NULL, &stack); | | 362 | pop(&val, NULL, &stack); |
350 | if (*str >= 'a' && *str <= 'z') | | 363 | if (*str >= 'a' && *str <= 'z') |
351 | dnums[*str - 'a'] = val; | | 364 | dnums[*str - 'a'] = val; |
352 | else if (*str >= 'A' && *str <= 'Z') | | 365 | else if (*str >= 'A' && *str <= 'Z') |
353 | term->_snums[*str - 'A'] = val; | | 366 | term->_snums[*str - 'A'] = val; |
354 | break; | | 367 | break; |
355 | case 'g': | | 368 | case 'g': |
356 | if (*str >= 'a' && *str <= 'z') { | | 369 | if (*str >= 'a' && *str <= 'z') { |
357 | if (push(dnums[*str - 'a'], NULL, &stack)) | | 370 | if (push(dnums[*str - 'a'], NULL, &stack)) |
358 | return NULL; | | 371 | return NULL; |
359 | } else if (*str >= 'A' && *str <= 'Z') { | | 372 | } else if (*str >= 'A' && *str <= 'Z') { |
360 | if (push(term->_snums[*str - 'A'], | | 373 | if (push(term->_snums[*str - 'A'], |
361 | NULL, &stack)) | | 374 | NULL, &stack)) |
362 | return NULL; | | 375 | return NULL; |
363 | } | | 376 | } |
364 | break; | | 377 | break; |
365 | case 'i': | | 378 | case 'i': |
366 | if (piss[0] == 0) | | 379 | if (piss[0] == 0) |
367 | params[0].num++; | | 380 | params[0].num++; |
368 | if (piss[1] == 0) | | 381 | if (piss[1] == 0) |
369 | params[1].num++; | | 382 | params[1].num++; |
370 | break; | | 383 | break; |
371 | case '\'': | | 384 | case '\'': |
372 | if (push((long)(unsigned char)*str++, NULL, &stack)) | | 385 | if (push((long)(unsigned char)*str++, NULL, &stack)) |
373 | return NULL; | | 386 | return NULL; |
374 | while (*str != '\0' && *str != '\'') | | 387 | while (*str != '\0' && *str != '\'') |
375 | str++; | | 388 | str++; |
376 | if (*str == '\'') | | 389 | if (*str == '\'') |
377 | str++; | | 390 | str++; |
378 | break; | | 391 | break; |
379 | case '{': | | 392 | case '{': |
380 | val = 0; | | 393 | val = 0; |
381 | for (; isdigit((unsigned char)*str); str++) | | 394 | for (; isdigit((unsigned char)*str); str++) |
382 | val = (val * 10) + (*str - '0'); | | 395 | val = (val * 10) + (*str - '0'); |
383 | if (push(val, NULL, &stack)) | | 396 | if (push(val, NULL, &stack)) |
384 | return NULL; | | 397 | return NULL; |
385 | while (*str != '\0' && *str != '}') | | 398 | while (*str != '\0' && *str != '}') |
386 | str++; | | 399 | str++; |
387 | if (*str == '}') | | 400 | if (*str == '}') |
388 | str++; | | 401 | str++; |
389 | break; | | 402 | break; |
390 | case '+': /* FALLTHROUGH */ | | 403 | case '+': /* FALLTHROUGH */ |
391 | case '-': /* FALLTHROUGH */ | | 404 | case '-': /* FALLTHROUGH */ |
392 | case '*': /* FALLTHROUGH */ | | 405 | case '*': /* FALLTHROUGH */ |
393 | case '/': /* FALLTHROUGH */ | | 406 | case '/': /* FALLTHROUGH */ |
394 | case 'm': /* FALLTHROUGH */ | | 407 | case 'm': /* FALLTHROUGH */ |
395 | case 'A': /* FALLTHROUGH */ | | 408 | case 'A': /* FALLTHROUGH */ |
396 | case 'O': /* FALLTHROUGH */ | | 409 | case 'O': /* FALLTHROUGH */ |
397 | case '&': /* FALLTHROUGH */ | | 410 | case '&': /* FALLTHROUGH */ |
398 | case '|': /* FALLTHROUGH */ | | 411 | case '|': /* FALLTHROUGH */ |
399 | case '^': /* FALLTHROUGH */ | | 412 | case '^': /* FALLTHROUGH */ |
400 | case '=': /* FALLTHROUGH */ | | 413 | case '=': /* FALLTHROUGH */ |
401 | case '<': /* FALLTHROUGH */ | | 414 | case '<': /* FALLTHROUGH */ |
402 | case '>': | | 415 | case '>': |
403 | pop(&val, NULL, &stack); | | 416 | pop(&val, NULL, &stack); |
404 | pop(&val2, NULL, &stack); | | 417 | pop(&val2, NULL, &stack); |
405 | switch (c) { | | 418 | switch (c) { |
406 | case '+': | | 419 | case '+': |
407 | val = val + val2; | | 420 | val = val + val2; |
408 | break; | | 421 | break; |
409 | case '-': | | 422 | case '-': |
410 | val = val2 - val; | | 423 | val = val2 - val; |
411 | break; | | 424 | break; |
412 | case '*': | | 425 | case '*': |
413 | val = val * val2; | | 426 | val = val * val2; |
414 | break; | | 427 | break; |
415 | case '/': | | 428 | case '/': |
416 | val = val ? val2 / val : 0; | | 429 | val = val ? val2 / val : 0; |
417 | break; | | 430 | break; |
418 | case 'm': | | 431 | case 'm': |
419 | val = val ? val2 % val : 0; | | 432 | val = val ? val2 % val : 0; |
420 | break; | | 433 | break; |
421 | case 'A': | | 434 | case 'A': |
422 | val = val && val2; | | 435 | val = val && val2; |
423 | break; | | 436 | break; |
424 | case 'O': | | 437 | case 'O': |
425 | val = val || val2; | | 438 | val = val || val2; |
426 | break; | | 439 | break; |
427 | case '&': | | 440 | case '&': |
428 | val = val & val2; | | 441 | val = val & val2; |
429 | break; | | 442 | break; |
430 | case '|': | | 443 | case '|': |
431 | val = val | val2; | | 444 | val = val | val2; |
432 | break; | | 445 | break; |
433 | case '^': | | 446 | case '^': |
434 | val = val ^ val2; | | 447 | val = val ^ val2; |
435 | break; | | 448 | break; |
436 | case '=': | | 449 | case '=': |
437 | val = val == val2; | | 450 | val = val == val2; |
438 | break; | | 451 | break; |
439 | case '<': | | 452 | case '<': |
440 | val = val2 < val; | | 453 | val = val2 < val; |
441 | break; | | 454 | break; |
442 | case '>': | | 455 | case '>': |
443 | val = val2 > val; | | 456 | val = val2 > val; |
444 | break; | | 457 | break; |
445 | } | | 458 | } |
446 | if (push(val, NULL, &stack)) | | 459 | if (push(val, NULL, &stack)) |
447 | return NULL; | | 460 | return NULL; |
448 | break; | | 461 | break; |
449 | case '!': | | 462 | case '!': |
450 | case '~': | | 463 | case '~': |
451 | pop(&val, NULL, &stack); | | 464 | pop(&val, NULL, &stack); |
452 | switch (c) { | | 465 | switch (c) { |
453 | case '!': | | 466 | case '!': |
454 | val = !val; | | 467 | val = !val; |
455 | break; | | 468 | break; |
456 | case '~': | | 469 | case '~': |
457 | val = ~val; | | 470 | val = ~val; |
458 | break; | | 471 | break; |
459 | } | | 472 | } |
460 | if (push(val, NULL, &stack)) | | 473 | if (push(val, NULL, &stack)) |
461 | return NULL; | | 474 | return NULL; |
462 | break; | | 475 | break; |
463 | case '?': /* if */ | | 476 | case '?': /* if */ |
464 | break; | | 477 | break; |
465 | case 't': /* then */ | | 478 | case 't': /* then */ |
466 | pop(&val, NULL, &stack); | | 479 | pop(&val, NULL, &stack); |
467 | if (val == 0) { | | 480 | if (val == 0) { |
468 | l = 0; | | 481 | l = 0; |
469 | for (; *str != '\0'; str++) { | | 482 | for (; *str != '\0'; str++) { |
470 | if (*str != '%') | | 483 | if (*str != '%') |
471 | continue; | | 484 | continue; |
472 | str++; | | 485 | str++; |
473 | if (*str == '?') | | 486 | if (*str == '?') |
474 | l++; | | 487 | l++; |
475 | else if (*str == ';') { | | 488 | else if (*str == ';') { |
476 | if (l > 0) | | 489 | if (l > 0) |
477 | l--; | | 490 | l--; |
478 | else { | | 491 | else { |
479 | str++; | | 492 | str++; |
480 | break; | | 493 | break; |
481 | } | | 494 | } |
482 | } else if (*str == 'e' && l == 0) { | | 495 | } else if (*str == 'e' && l == 0) { |
483 | str++; | | 496 | str++; |
484 | break; | | 497 | break; |
485 | } | | 498 | } |
486 | } | | 499 | } |
487 | } | | 500 | } |
488 | break; | | 501 | break; |
489 | case 'e': /* else */ | | 502 | case 'e': /* else */ |
490 | l = 0; | | 503 | l = 0; |
491 | for (; *str != '\0'; str++) { | | 504 | for (; *str != '\0'; str++) { |
492 | if (*str != '%') | | 505 | if (*str != '%') |
493 | continue; | | 506 | continue; |
494 | str++; | | 507 | str++; |
495 | if (*str == '?') | | 508 | if (*str == '?') |
496 | l++; | | 509 | l++; |
497 | else if (*str == ';') { | | 510 | else if (*str == ';') { |
498 | if (l > 0) | | 511 | if (l > 0) |
499 | l--; | | 512 | l--; |
500 | else { | | 513 | else { |
501 | str++; | | 514 | str++; |
502 | break; | | 515 | break; |
503 | } | | 516 | } |
504 | } | | 517 | } |
505 | } | | 518 | } |
506 | break; | | 519 | break; |
507 | case ';': /* fi */ | | 520 | case ';': /* fi */ |
508 | break; | | 521 | break; |
509 | } | | 522 | } |
510 | } | | 523 | } |
511 | term->_buf[term->_bufpos] = '\0'; | | 524 | term->_buf[term->_bufpos] = '\0'; |
512 | return term->_buf; | | 525 | return term->_buf; |
513 | } | | 526 | } |
514 | | | 527 | |
515 | char * | | 528 | char * |
516 | ti_tiparm(TERMINAL *term, const char *str, ...) | | 529 | ti_tiparm(TERMINAL *term, const char *str, ...) |
517 | { | | 530 | { |
518 | va_list va; | | 531 | va_list va; |
519 | char *ret; | | 532 | char *ret; |
520 | | | 533 | |
521 | _DIAGASSERT(term != NULL); | | 534 | _DIAGASSERT(term != NULL); |
522 | _DIAGASSERT(str != NULL); | | 535 | _DIAGASSERT(str != NULL); |
523 | | | 536 | |
524 | va_start(va, str); | | 537 | va_start(va, str); |
525 | ret = _ti_tiparm(term, str, 0, va); | | 538 | ret = _ti_tiparm(term, str, 0, va); |
526 | va_end(va); | | 539 | va_end(va); |
527 | return ret; | | 540 | return ret; |
528 | } | | 541 | } |
529 | | | 542 | |
530 | char * | | 543 | char * |
531 | tiparm(const char *str, ...) | | 544 | tiparm(const char *str, ...) |
532 | { | | 545 | { |
533 | va_list va; | | 546 | va_list va; |
534 | char *ret; | | 547 | char *ret; |
535 | | | 548 | |
536 | _DIAGASSERT(str != NULL); | | 549 | _DIAGASSERT(str != NULL); |
537 | | | 550 | |
538 | va_start(va, str); | | 551 | va_start(va, str); |
539 | ret = _ti_tiparm(NULL, str, 0, va); | | 552 | ret = _ti_tiparm(NULL, str, 0, va); |
540 | va_end(va); | | 553 | va_end(va); |
541 | return ret; | | 554 | return ret; |
542 | } | | 555 | } |
543 | | | 556 | |
544 | /* Same as tiparm, but accepts long instead of int for the numeric params. | | 557 | /* Same as tiparm, but accepts long instead of int for the numeric params. |
545 | * Currently there is no need for this to be a public interface and is only | | 558 | * Currently there is no need for this to be a public interface and is only |
546 | * consumed by tparm. If we need this to be public, and I really cannot | | 559 | * consumed by tparm. If we need this to be public, and I really cannot |
547 | * imagine why, then we would need ti_tlparm() as well. */ | | 560 | * imagine why, then we would need ti_tlparm() as well. */ |
548 | static char * | | 561 | static char * |
549 | tlparm(const char *str, ...) | | 562 | tlparm(const char *str, ...) |
550 | { | | 563 | { |
551 | va_list va; | | 564 | va_list va; |
552 | char *ret; | | 565 | char *ret; |
553 | | | 566 | |
554 | _DIAGASSERT(str != NULL); | | 567 | _DIAGASSERT(str != NULL); |
555 | | | 568 | |
556 | va_start(va, str); | | 569 | va_start(va, str); |
557 | ret = _ti_tiparm(NULL, str, 1, va); | | 570 | ret = _ti_tiparm(NULL, str, 1, va); |
558 | va_end(va); | | 571 | va_end(va); |
559 | return ret; | | 572 | return ret; |
560 | } | | 573 | } |
561 | | | 574 | |
562 | char * | | 575 | char * |
563 | tparm(const char *str, | | 576 | tparm(const char *str, |
564 | long p1, long p2, long p3, long p4, long p5, | | 577 | long p1, long p2, long p3, long p4, long p5, |
565 | long p6, long p7, long p8, long p9) | | 578 | long p6, long p7, long p8, long p9) |
566 | { | | 579 | { |
567 | | | 580 | |
568 | return tlparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); | | 581 | return tlparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9); |
569 | } | | 582 | } |