retire BIOS_SEG and umap_bios
[minix3.git] / lib / libterminfo / tparm.c
blob92a2d698dd982d534aca05716585537bdc24054f
1 /* $NetBSD: tparm.c,v 1.2 2010/09/22 06:10:51 roy Exp $ */
3 /*
4 * Copyright (c) 2009 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Roy Marples.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
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
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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
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
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __RCSID("$NetBSD: tparm.c,v 1.2 2010/09/22 06:10:51 roy Exp $");
33 #include <assert.h>
34 #include <ctype.h>
35 #include <errno.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <term_private.h>
41 #include <term.h>
43 static TERMINAL *dumbterm; /* For non thread safe functions */
45 typedef struct {
46 long nums[20];
47 char *strings[20];
48 size_t offset;
49 } TPSTACK;
51 typedef struct {
52 long num;
53 char *string;
54 } TPVAR;
56 static int
57 push(long num, char *string, TPSTACK *stack)
59 if (stack->offset > sizeof(stack->nums)) {
60 errno = E2BIG;
61 return -1;
63 stack->nums[stack->offset] = num;
64 stack->strings[stack->offset] = string;
65 stack->offset++;
66 return 0;
69 static int
70 pop(long *num, char **string, TPSTACK *stack)
72 if (stack->offset == 0) {
73 errno = E2BIG;
74 return -1;
76 stack->offset--;
77 if (num)
78 *num = stack->nums[stack->offset];
79 if (string)
80 *string = stack->strings[stack->offset];
81 return 0;
84 static char *
85 checkbuf(TERMINAL *term, size_t len)
87 char *buf;
89 if (term->_bufpos + len >= term->_buflen) {
90 len = term->_buflen + BUFSIZ;
91 buf = realloc(term->_buf, len);
92 if (buf == NULL)
93 return 0;
94 term->_buf = buf;
95 term->_buflen = len;
97 return term->_buf;
100 static size_t
101 ochar(TERMINAL *term, int c)
103 if (c == 0)
104 c = 0200;
105 /* Check we have space and a terminator */
106 if (checkbuf(term, 2) == NULL)
107 return 0;
108 term->_buf[term->_bufpos++] = (char)c;
109 return 1;
112 static size_t
113 onum(TERMINAL *term, const char *fmt, long num, int len)
115 size_t l;
117 /* Assume we never have natural number longer than 64 chars */
118 if (len < 64)
119 len = 64;
120 if (checkbuf(term, (size_t)len + 1) == NULL)
121 return 0;
122 l = sprintf(term->_buf + term->_bufpos, fmt, num);
123 term->_bufpos += l;
124 return l;
127 static char *
128 _ti_vtparm(TERMINAL *term, const char *str, va_list parms)
130 const char *sp;
131 char c, fmt[64], *fp, *ostr;
132 long val, val2;
133 long dnums[26]; /* dynamic variables a-z, not preserved */
134 size_t l, max;
135 TPSTACK stack;
136 TPVAR params[9];
137 int done, dot, minus, width, precision, olen;
138 int piss[9]; /* Parameter IS String - piss ;) */
140 if (str == NULL)
141 return NULL;
144 If not passed a terminal, malloc a dummy one.
145 This means we can preserve buffers and variables per terminal and
146 still work with non thread safe functions (which sadly are still the
147 norm and standard).
149 if (term == NULL) {
150 if (dumbterm == NULL) {
151 dumbterm = malloc(sizeof(*dumbterm));
152 if (dumbterm == NULL)
153 return NULL;
154 dumbterm->_buflen = 0;
156 term = dumbterm;
159 term->_bufpos = 0;
160 /* Ensure we have an initial buffer */
161 if (term->_buflen == 0) {
162 term->_buf = malloc(BUFSIZ);
163 if (term->_buf == NULL)
164 return NULL;
165 term->_buflen = BUFSIZ;
169 Make a first pass through the string so we can work out
170 which parameters are longs and which are char *.
171 Basically we only use char * if %p[1-9] is followed by %l or %s.
173 memset(&piss, 0, sizeof(piss));
174 max = 0;
175 sp = str;
176 while ((c = *sp++) != '\0') {
177 if (c != '%')
178 continue;
179 c = *sp++;
180 if (c == '\0')
181 break;
182 if (c != 'p')
183 continue;
184 c = *sp++;
185 if (c < '1' || c > '9') {
186 errno = EINVAL;
187 return NULL;
189 l = c - '0';
190 if (l > max)
191 max = l;
192 if (*sp != '%')
193 continue;
194 /* Skip formatting */
195 sp++;
196 while (*sp == '.' || *sp == '#' || *sp == ' ' || *sp == ':' ||
197 *sp == '-' || isdigit((unsigned char)*sp))
198 sp++;
199 if (*sp == 'l' || *sp == 's')
200 piss[l - 1] = 1;
203 /* Put our parameters into variables */
204 memset(&params, 0, sizeof(params));
205 for (l = 0; l < max; l++) {
206 if (piss[l] == 0)
207 params[l].num = va_arg(parms, long);
208 else
209 params[l].string = va_arg(parms, char *);
212 term->_bufpos = 0;
213 memset(&stack, 0, sizeof(stack));
214 while ((c = *str++) != '\0') {
215 if (c != '%' || (c = *str++) == '%') {
216 if (c == '\0')
217 break;
218 if (ochar(term, c) == 0)
219 return NULL;
220 continue;
223 /* Handle formatting. */
224 fp = fmt;
225 *fp++ = '%';
226 done = dot = minus = width = precision = 0;
227 val = 0;
228 while (done == 0 && (size_t)(fp - fmt) < sizeof(fmt)) {
229 switch (c) {
230 case 'c': /* FALLTHROUGH */
231 case 'd': /* FALLTHROUGH */
232 case 'o': /* FALLTHROUGH */
233 case 'x': /* FALLTHROUGH */
234 case 'X': /* FALLTHROUGH */
235 case 's':
236 *fp++ = c;
237 done = 1;
238 break;
239 case '#': /* FALLTHROUGH */
240 case ' ':
241 *fp++ = c;
242 break;
243 case '.':
244 *fp++ = c;
245 if (dot == 0) {
246 dot = 1;
247 width = val;
248 } else
249 done = 2;
250 val = 0;
251 break;
252 case ':':
253 minus = 1;
254 break;
255 case '-':
256 if (minus)
257 *fp++ = c;
258 else
259 done = 1;
260 break;
261 default:
262 if (isdigit((unsigned char)c)) {
263 val = (val * 10) + (c - '0');
264 if (val > 10000)
265 done = 2;
266 else
267 *fp++ = c;
268 } else
269 done = 1;
271 if (done == 0)
272 c = *str++;
274 if (done == 2) {
275 /* Found an error in the format */
276 fp = fmt + 1;
277 *fp = *str;
278 olen = 0;
279 } else {
280 if (dot == 0)
281 width = val;
282 else
283 precision = val;
284 olen = (width > precision) ? width : precision;
286 *fp++ = '\0';
288 /* Handle commands */
289 switch (c) {
290 case 'c':
291 if (pop(&val, NULL, &stack))
292 return NULL;
293 if (ochar(term, (unsigned char)val) == 0)
294 return NULL;
295 break;
296 case 's':
297 if (pop(NULL, &ostr, &stack))
298 return NULL;
299 if (ostr != NULL) {
300 l = strlen(ostr);
301 if (l < (size_t)olen)
302 l = olen;
303 if (checkbuf(term, (size_t)(l + 1)) == NULL)
304 return NULL;
305 l = sprintf(term->_buf + term->_bufpos,
306 fmt, ostr);
307 term->_bufpos += l;
309 break;
310 case 'l':
311 if (pop(NULL, &ostr, &stack))
312 return NULL;
313 if (ostr == NULL)
314 l = 0;
315 else
316 l = strlen(ostr);
317 if (onum(term, "%d", (long)l, 0) == 0)
318 return NULL;
319 break;
320 case 'd': /* FALLTHROUGH */
321 case 'o': /* FALLTHROUGH */
322 case 'x': /* FALLTHROUGH */
323 case 'X':
324 if (pop(&val, NULL, &stack))
325 return NULL;
326 if (onum(term, fmt, val, olen) == 0)
327 return NULL;
328 break;
329 case 'p':
330 if (*str < '1' || *str > '9') {
331 errno = EINVAL;
332 return NULL;
334 l = *str++ - '1';
335 if (push(params[l].num, params[l].string, &stack))
336 return NULL;
337 break;
338 case 'P':
339 if (pop(&val, NULL, &stack))
340 return NULL;
341 str++;
342 if (*str >= 'a' && *str <= 'z')
343 dnums[*str - 'a'] = val;
344 else if (*str >= 'A' && *str <= 'Z')
345 term->_snums[*str - 'A'] = val;
346 break;
347 case 'g':
348 str++;
349 if (*str >= 'a' && *str <= 'z') {
350 if (push(dnums[*str - 'a'], NULL, &stack))
351 return NULL;
352 } else if (*str >= 'A' && *str <= 'Z') {
353 if (push(term->_snums[*str - 'A'],
354 NULL, &stack))
355 return NULL;
357 break;
358 case 'i':
359 if (piss[0] == 0)
360 params[0].num++;
361 if (piss[1] == 0)
362 params[1].num++;
363 break;
364 case '\'':
365 if (push((long)(unsigned char)*str++, NULL, &stack))
366 return NULL;
367 while (*str != '\0' && *str != '\'')
368 str++;
369 if (*str == '\'')
370 str++;
371 break;
372 case '{':
373 val = 0;
374 for (str++; isdigit((unsigned char)*str); str++)
375 val = (val * 10) + (*str - '0');
376 if (push(val, NULL, &stack))
377 return NULL;
378 while (*str != '\0' && *str != '}')
379 str++;
380 if (*str == '}')
381 str++;
382 break;
383 case '+': /* FALLTHROUGH */
384 case '-': /* FALLTHROUGH */
385 case '*': /* FALLTHROUGH */
386 case '/': /* FALLTHROUGH */
387 case 'm': /* FALLTHROUGH */
388 case 'A': /* FALLTHROUGH */
389 case 'O': /* FALLTHROUGH */
390 case '&': /* FALLTHROUGH */
391 case '|': /* FALLTHROUGH */
392 case '^': /* FALLTHROUGH */
393 case '=': /* FALLTHROUGH */
394 case '<': /* FALLTHROUGH */
395 case '>':
396 if (pop(&val, NULL, &stack) ||
397 pop(&val2, NULL, &stack))
398 return NULL;
399 switch (c) {
400 case '+':
401 val = val + val2;
402 break;
403 case '-':
404 val = val2 - val;
405 break;
406 case '*':
407 val = val * val2;
408 break;
409 case '/':
410 val = val ? val2 / val : 0;
411 break;
412 case 'm':
413 val = val ? val2 % val : 0;
414 break;
415 case 'A':
416 val = val && val2;
417 break;
418 case 'O':
419 val = val || val2;
420 break;
421 case '&':
422 val = val & val2;
423 break;
424 case '|':
425 val = val | val2;
426 break;
427 case '^':
428 val = val ^ val2;
429 break;
430 case '=':
431 val = val == val2;
432 break;
433 case '<':
434 val = val2 < val;
435 break;
436 case '>':
437 val = val2 > val;
438 break;
440 if (push(val, NULL, &stack))
441 return NULL;
442 break;
443 case '!':
444 case '~':
445 if (pop(&val, NULL, &stack))
446 return NULL;
447 switch (*str) {
448 case '!':
449 val = !val;
450 break;
451 case '~':
452 val = ~val;
453 break;
455 if (push(val, NULL, &stack))
456 return NULL;
457 break;
458 case '?': /* if */
459 break;
460 case 't': /* then */
461 if (pop(&val, NULL, &stack))
462 return NULL;
463 if (val != 0) {
464 l = 0;
465 for (; *str != '\0'; str++) {
466 if (*str != '%')
467 continue;
468 str++;
469 if (*str == '?')
470 l++;
471 else if (*str == ';') {
472 if (l > 0)
473 l--;
474 else
475 break;
476 } else if (*str == 'e' && l == 0)
477 break;
480 break;
481 case 'e': /* else */
482 l = 0;
483 for (; *str != '\0'; str++) {
484 if (*str != '%')
485 continue;
486 str++;
487 if (*str == '?')
488 l++;
489 else if (*str == ';') {
490 if (l > 0)
491 l--;
492 else
493 break;
496 break;
497 case ';': /* fi */
498 break;
501 term->_buf[term->_bufpos] = '\0';
502 return term->_buf;
505 char *
506 t_vparm(TERMINAL *term, const char *str, ...)
508 va_list va;
509 char *ret;
511 _DIAGASSERT(term != NULL);
512 _DIAGASSERT(str != NULL);
514 va_start(va, str);
515 ret = _ti_vtparm(term, str, va);
516 va_end(va);
517 return ret;
520 char *
521 vtparm(const char *str, ...)
523 va_list va;
524 char *ret;
526 _DIAGASSERT(str != NULL);
528 va_start(va, str);
529 ret = _ti_vtparm(NULL, str, va);
530 va_end(va);
531 return ret;
534 char *
535 t_parm(TERMINAL *term, const char *str,
536 long p1, long p2, long p3, long p4, long p5,
537 long p6, long p7, long p8, long p9)
540 _DIAGASSERT(term != NULL);
541 _DIAGASSERT(str != NULL);
542 return t_vparm(term, str, p1, p2, p3, p4, p5, p6, p7, p8, p9);
545 char *
546 tparm(const char *str,
547 long p1, long p2, long p3, long p4, long p5,
548 long p6, long p7, long p8, long p9)
551 _DIAGASSERT(str != NULL);
552 return t_vparm(NULL, str, p1, p2, p3, p4, p5, p6, p7, p8, p9);