pkgin_all: script to auto-install all packages
[minix.git] / lib / libterminfo / tparm.c
blob8e48cafc9972500211d773542752a5415f3aa562
1 /* $NetBSD: tparm.c,v 1.8 2012/06/02 19:10:33 roy Exp $ */
3 /*
4 * Copyright (c) 2009, 2011 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.8 2012/06/02 19:10:33 roy Exp $");
32 #include <sys/param.h>
34 #include <assert.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <term_private.h>
42 #include <term.h>
44 static TERMINAL *dumbterm; /* For non thread safe functions */
46 typedef struct {
47 int nums[20];
48 char *strings[20];
49 size_t offset;
50 } TPSTACK;
52 typedef struct {
53 int num;
54 char *string;
55 } TPVAR;
57 static int
58 push(int num, char *string, TPSTACK *stack)
60 if (stack->offset > sizeof(stack->nums)) {
61 errno = E2BIG;
62 return -1;
64 stack->nums[stack->offset] = num;
65 stack->strings[stack->offset] = string;
66 stack->offset++;
67 return 0;
70 static int
71 pop(int *num, char **string, TPSTACK *stack)
73 if (stack->offset == 0) {
74 if (num)
75 *num = 0;
76 if (string)
77 *string = NULL;
78 errno = E2BIG;
79 return -1;
81 stack->offset--;
82 if (num)
83 *num = stack->nums[stack->offset];
84 if (string)
85 *string = stack->strings[stack->offset];
86 return 0;
89 static char *
90 checkbuf(TERMINAL *term, size_t len)
92 char *buf;
94 if (term->_bufpos + len >= term->_buflen) {
95 len = term->_buflen + MAX(len, BUFSIZ);
96 buf = realloc(term->_buf, len);
97 if (buf == NULL)
98 return NULL;
99 term->_buf = buf;
100 term->_buflen = len;
102 return term->_buf;
105 static size_t
106 ochar(TERMINAL *term, int c)
108 if (c == 0)
109 c = 0200;
110 /* Check we have space and a terminator */
111 if (checkbuf(term, 2) == NULL)
112 return 0;
113 term->_buf[term->_bufpos++] = (char)c;
114 return 1;
117 static size_t
118 onum(TERMINAL *term, const char *fmt, int num, int len)
120 size_t l;
122 /* Assume we never have natural number longer than 64 chars */
123 if (len < 64)
124 len = 64;
125 if (checkbuf(term, (size_t)len + 1) == NULL)
126 return 0;
127 l = sprintf(term->_buf + term->_bufpos, fmt, num);
128 term->_bufpos += l;
129 return l;
132 static char *
133 _ti_tiparm(TERMINAL *term, const char *str, va_list parms)
135 const char *sp;
136 char c, fmt[64], *fp, *ostr;
137 int val, val2;
138 int dnums[26]; /* dynamic variables a-z, not preserved */
139 size_t l, max;
140 TPSTACK stack;
141 TPVAR params[9];
142 int done, dot, minus, width, precision, olen;
143 int piss[9]; /* Parameter IS String - piss ;) */
145 if (str == NULL)
146 return NULL;
149 If not passed a terminal, malloc a dummy one.
150 This means we can preserve buffers and variables per terminal and
151 still work with non thread safe functions (which sadly are still the
152 norm and standard).
155 if (term == NULL) {
156 if (dumbterm == NULL) {
157 dumbterm = malloc(sizeof(*dumbterm));
158 if (dumbterm == NULL)
159 return NULL;
160 dumbterm->_buflen = 0;
162 term = dumbterm;
165 term->_bufpos = 0;
166 /* Ensure we have an initial buffer */
167 if (term->_buflen == 0) {
168 term->_buf = malloc(BUFSIZ);
169 if (term->_buf == NULL)
170 return NULL;
171 term->_buflen = BUFSIZ;
175 Make a first pass through the string so we can work out
176 which parameters are ints and which are char *.
177 Basically we only use char * if %p[1-9] is followed by %l or %s.
179 memset(&piss, 0, sizeof(piss));
180 max = 0;
181 sp = str;
182 while ((c = *sp++) != '\0') {
183 if (c != '%')
184 continue;
185 c = *sp++;
186 if (c == '\0')
187 break;
188 if (c != 'p')
189 continue;
190 c = *sp++;
191 if (c < '1' || c > '9') {
192 errno = EINVAL;
193 continue;
195 l = c - '0';
196 if (l > max)
197 max = l;
198 if (*sp != '%')
199 continue;
200 /* Skip formatting */
201 sp++;
202 while (*sp == '.' || *sp == '#' || *sp == ' ' || *sp == ':' ||
203 *sp == '-' || isdigit((unsigned char)*sp))
204 sp++;
205 if (*sp == 'l' || *sp == 's')
206 piss[l - 1] = 1;
209 /* Put our parameters into variables */
210 memset(&params, 0, sizeof(params));
211 for (l = 0; l < max; l++) {
212 if (piss[l] == 0)
213 params[l].num = va_arg(parms, int);
214 else
215 params[l].string = va_arg(parms, char *);
218 term->_bufpos = 0;
219 memset(&stack, 0, sizeof(stack));
220 while ((c = *str++) != '\0') {
221 if (c != '%' || (c = *str++) == '%') {
222 if (c == '\0')
223 break;
224 if (ochar(term, c) == 0)
225 return NULL;
226 continue;
229 /* Handle formatting. */
230 fp = fmt;
231 *fp++ = '%';
232 done = dot = minus = width = precision = 0;
233 val = 0;
234 while (done == 0 && (size_t)(fp - fmt) < sizeof(fmt)) {
235 switch (c) {
236 case 'c': /* FALLTHROUGH */
237 case 'd': /* FALLTHROUGH */
238 case 'o': /* FALLTHROUGH */
239 case 'x': /* FALLTHROUGH */
240 case 'X': /* FALLTHROUGH */
241 case 's':
242 *fp++ = c;
243 done = 1;
244 break;
245 case '#': /* FALLTHROUGH */
246 case ' ':
247 *fp++ = c;
248 break;
249 case '.':
250 *fp++ = c;
251 if (dot == 0) {
252 dot = 1;
253 width = val;
254 } else
255 done = 2;
256 val = 0;
257 break;
258 case ':':
259 minus = 1;
260 break;
261 case '-':
262 if (minus)
263 *fp++ = c;
264 else
265 done = 1;
266 break;
267 default:
268 if (isdigit((unsigned char)c)) {
269 val = (val * 10) + (c - '0');
270 if (val > 10000)
271 done = 2;
272 else
273 *fp++ = c;
274 } else
275 done = 1;
277 if (done == 0)
278 c = *str++;
280 if (done == 2) {
281 /* Found an error in the format */
282 fp = fmt + 1;
283 *fp = *str;
284 olen = 0;
285 } else {
286 if (dot == 0)
287 width = val;
288 else
289 precision = val;
290 olen = (width > precision) ? width : precision;
292 *fp++ = '\0';
294 /* Handle commands */
295 switch (c) {
296 case 'c':
297 pop(&val, NULL, &stack);
298 if (ochar(term, (unsigned char)val) == 0)
299 return NULL;
300 break;
301 case 's':
302 pop(NULL, &ostr, &stack);
303 if (ostr != NULL) {
304 l = strlen(ostr);
305 if (l < (size_t)olen)
306 l = olen;
307 if (checkbuf(term, (size_t)(l + 1)) == NULL)
308 return NULL;
309 l = sprintf(term->_buf + term->_bufpos,
310 fmt, ostr);
311 term->_bufpos += l;
313 break;
314 case 'l':
315 pop(NULL, &ostr, &stack);
316 if (ostr == NULL)
317 l = 0;
318 else
319 l = strlen(ostr);
320 if (onum(term, "%d", (int)l, 0) == 0)
321 return NULL;
322 break;
323 case 'd': /* FALLTHROUGH */
324 case 'o': /* FALLTHROUGH */
325 case 'x': /* FALLTHROUGH */
326 case 'X':
327 pop(&val, NULL, &stack);
328 if (onum(term, fmt, val, olen) == 0)
329 return NULL;
330 break;
331 case 'p':
332 if (*str < '1' || *str > '9')
333 break;
334 l = *str++ - '1';
335 if (push(params[l].num, params[l].string, &stack))
336 return NULL;
337 break;
338 case 'P':
339 pop(&val, NULL, &stack);
340 if (*str >= 'a' && *str <= 'z')
341 dnums[*str - 'a'] = val;
342 else if (*str >= 'A' && *str <= 'Z')
343 term->_snums[*str - 'A'] = val;
344 break;
345 case 'g':
346 if (*str >= 'a' && *str <= 'z') {
347 if (push(dnums[*str - 'a'], NULL, &stack))
348 return NULL;
349 } else if (*str >= 'A' && *str <= 'Z') {
350 if (push(term->_snums[*str - 'A'],
351 NULL, &stack))
352 return NULL;
354 break;
355 case 'i':
356 if (piss[0] == 0)
357 params[0].num++;
358 if (piss[1] == 0)
359 params[1].num++;
360 break;
361 case '\'':
362 if (push((int)(unsigned char)*str++, NULL, &stack))
363 return NULL;
364 while (*str != '\0' && *str != '\'')
365 str++;
366 if (*str == '\'')
367 str++;
368 break;
369 case '{':
370 val = 0;
371 for (; isdigit((unsigned char)*str); str++)
372 val = (val * 10) + (*str - '0');
373 if (push(val, NULL, &stack))
374 return NULL;
375 while (*str != '\0' && *str != '}')
376 str++;
377 if (*str == '}')
378 str++;
379 break;
380 case '+': /* FALLTHROUGH */
381 case '-': /* FALLTHROUGH */
382 case '*': /* FALLTHROUGH */
383 case '/': /* FALLTHROUGH */
384 case 'm': /* FALLTHROUGH */
385 case 'A': /* FALLTHROUGH */
386 case 'O': /* FALLTHROUGH */
387 case '&': /* FALLTHROUGH */
388 case '|': /* FALLTHROUGH */
389 case '^': /* FALLTHROUGH */
390 case '=': /* FALLTHROUGH */
391 case '<': /* FALLTHROUGH */
392 case '>':
393 pop(&val, NULL, &stack);
394 pop(&val2, NULL, &stack);
395 switch (c) {
396 case '+':
397 val = val + val2;
398 break;
399 case '-':
400 val = val2 - val;
401 break;
402 case '*':
403 val = val * val2;
404 break;
405 case '/':
406 val = val ? val2 / val : 0;
407 break;
408 case 'm':
409 val = val ? val2 % val : 0;
410 break;
411 case 'A':
412 val = val && val2;
413 break;
414 case 'O':
415 val = val || val2;
416 break;
417 case '&':
418 val = val & val2;
419 break;
420 case '|':
421 val = val | val2;
422 break;
423 case '^':
424 val = val ^ val2;
425 break;
426 case '=':
427 val = val == val2;
428 break;
429 case '<':
430 val = val2 < val;
431 break;
432 case '>':
433 val = val2 > val;
434 break;
436 if (push(val, NULL, &stack))
437 return NULL;
438 break;
439 case '!':
440 case '~':
441 pop(&val, NULL, &stack);
442 switch (*str) {
443 case '!':
444 val = !val;
445 break;
446 case '~':
447 val = ~val;
448 break;
450 if (push(val, NULL, &stack))
451 return NULL;
452 break;
453 case '?': /* if */
454 break;
455 case 't': /* then */
456 pop(&val, NULL, &stack);
457 if (val != 0) {
458 l = 0;
459 for (; *str != '\0'; str++) {
460 if (*str != '%')
461 continue;
462 str++;
463 if (*str == '?')
464 l++;
465 else if (*str == ';') {
466 if (l > 0)
467 l--;
468 else
469 break;
470 } else if (*str == 'e' && l == 0)
471 break;
474 break;
475 case 'e': /* else */
476 l = 0;
477 for (; *str != '\0'; str++) {
478 if (*str != '%')
479 continue;
480 str++;
481 if (*str == '?')
482 l++;
483 else if (*str == ';') {
484 if (l > 0)
485 l--;
486 else
487 break;
490 break;
491 case ';': /* fi */
492 break;
495 term->_buf[term->_bufpos] = '\0';
496 return term->_buf;
499 char *
500 ti_tiparm(TERMINAL *term, const char *str, ...)
502 va_list va;
503 char *ret;
505 _DIAGASSERT(term != NULL);
506 _DIAGASSERT(str != NULL);
508 va_start(va, str);
509 ret = _ti_tiparm(term, str, va);
510 va_end(va);
511 return ret;
514 char *
515 tiparm(const char *str, ...)
517 va_list va;
518 char *ret;
520 _DIAGASSERT(str != NULL);
522 va_start(va, str);
523 ret = _ti_tiparm(NULL, str, va);
524 va_end(va);
525 return ret;
528 char *
529 tparm(const char *str,
530 long lp1, long lp2, long lp3, long lp4, long lp5,
531 long lp6, long lp7, long lp8, long lp9)
533 int p1 = lp1, p2 = lp2, p3 = lp3, p4 = lp4, p5 = lp5;
534 int p6 = lp6, p7 = lp7, p8 = lp8, p9 = lp9;
536 return tiparm(str, p1, p2, p3, p4, p5, p6, p7, p8, p9);