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