1 /* $NetBSD: tparm.c,v 1.15 2013/06/07 13:16:18 roy Exp $ */
4 * Copyright (c) 2009, 2011, 2013 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.15 2013/06/07 13:16:18 roy Exp $");
32 #include <sys/param.h>
41 #include <term_private.h>
44 #define LONG_STR_MAX ((CHAR_BIT * sizeof(long)) / 3)
45 #define BUFINC 128 /* Size to increament the terminal buffer by */
47 #define VA_LONG_LONG 1
49 //#define VA_CHAR_LONG 3 /* No need for this yet */
51 static TERMINAL
*dumbterm
; /* For non thread safe functions */
65 push(long num
, char *string
, TPSTACK
*stack
)
67 if (stack
->offset
>= sizeof(stack
->nums
)) {
71 stack
->nums
[stack
->offset
] = num
;
72 stack
->strings
[stack
->offset
] = string
;
78 pop(long *num
, char **string
, TPSTACK
*stack
)
80 if (stack
->offset
== 0) {
90 *num
= stack
->nums
[stack
->offset
];
92 *string
= stack
->strings
[stack
->offset
];
97 checkbuf(TERMINAL
*term
, size_t len
)
101 if (term
->_bufpos
+ len
>= term
->_buflen
) {
102 len
= term
->_buflen
+ MAX(len
, BUFINC
);
103 buf
= realloc(term
->_buf
, len
);
113 ochar(TERMINAL
*term
, int c
)
117 /* Check we have space and a terminator */
118 if (checkbuf(term
, 2) == NULL
)
120 term
->_buf
[term
->_bufpos
++] = (char)c
;
125 onum(TERMINAL
*term
, const char *fmt
, int num
, unsigned int len
)
129 if (len
< LONG_STR_MAX
)
131 if (checkbuf(term
, len
+ 2) == NULL
)
133 l
= sprintf(term
->_buf
+ term
->_bufpos
, fmt
, num
);
139 Make a pass through the string so we can work out
140 which parameters are ints and which are char *.
141 Basically we only use char * if %p[1-9] is followed by %l or %s.
144 _ti_parm_analyse(const char *str
, int *piss
, int piss_len
)
151 while ((c
= *str
++) != '\0') {
156 case 'l': /* FALLTHROUGH */
159 if (lpop
<= piss_len
)
167 if (c
< '1' || c
> '9') {
185 _ti_tiparm(TERMINAL
*term
, const char *str
, int va_type
, va_list parms
)
187 char c
, fmt
[64], *fp
, *ostr
;
189 long dnums
[26]; /* dynamic variables a-z, not preserved */
192 TPVAR params
[TPARM_MAX
];
193 unsigned int done
, dot
, minus
, width
, precision
, olen
;
194 int piss
[TPARM_MAX
]; /* Parameter IS String - piss ;) */
200 If not passed a terminal, malloc a dummy one.
201 This means we can preserve buffers and variables per terminal and
202 still work with non thread safe functions (which sadly are still the
206 if (dumbterm
== NULL
) {
207 dumbterm
= malloc(sizeof(*dumbterm
));
208 if (dumbterm
== NULL
)
210 dumbterm
->_buflen
= 0;
216 /* Ensure we have an initial buffer */
217 if (term
->_buflen
== 0) {
218 term
->_buf
= malloc(BUFINC
);
219 if (term
->_buf
== NULL
)
221 term
->_buflen
= BUFINC
;
224 memset(&piss
, 0, sizeof(piss
));
225 max
= _ti_parm_analyse(str
, piss
, TPARM_MAX
);
227 /* Put our parameters into variables */
228 memset(¶ms
, 0, sizeof(params
));
229 for (l
= 0; l
< max
; l
++) {
231 if (va_type
== VA_LONG_LONG
) {
232 /* This only works if char * fits into a long
233 * on this platform. */
234 if (sizeof(char *) <= sizeof(long)/*CONSTCOND*/)
236 (char *)va_arg(parms
, long);
242 params
[l
].string
= va_arg(parms
, char *);
244 if (va_type
== VA_CHAR_INT
)
245 params
[l
].num
= (long)va_arg(parms
, int);
247 params
[l
].num
= va_arg(parms
, long);
251 memset(&stack
, 0, sizeof(stack
));
252 while ((c
= *str
++) != '\0') {
253 if (c
!= '%' || (c
= *str
++) == '%') {
256 if (ochar(term
, c
) == 0)
261 /* Handle formatting. */
264 done
= dot
= minus
= width
= precision
= 0;
266 while (done
== 0 && (size_t)(fp
- fmt
) < sizeof(fmt
)) {
268 case 'c': /* FALLTHROUGH */
273 case 'd': /* FALLTHROUGH */
274 case 'o': /* FALLTHROUGH */
275 case 'x': /* FALLTHROUGH */
276 case 'X': /* FALLTHROUGH */
281 case '#': /* FALLTHROUGH */
304 if (isdigit((unsigned char)c
)) {
305 val
= (val
* 10) + (c
- '0');
317 /* Found an error in the format */
326 olen
= MAX(width
, precision
);
330 /* Handle commands */
333 pop(&val
, NULL
, &stack
);
334 if (ochar(term
, (unsigned char)val
) == 0)
338 pop(NULL
, &ostr
, &stack
);
341 if (l
< (size_t)olen
)
343 if (checkbuf(term
, (size_t)(l
+ 1)) == NULL
)
345 l
= sprintf(term
->_buf
+ term
->_bufpos
,
351 pop(NULL
, &ostr
, &stack
);
356 #ifdef NCURSES_COMPAT_57
357 if (onum(term
, "%ld", (long)l
, 0) == 0)
360 push((long)l
, NULL
, &stack
);
363 case 'd': /* FALLTHROUGH */
364 case 'o': /* FALLTHROUGH */
365 case 'x': /* FALLTHROUGH */
367 pop(&val
, NULL
, &stack
);
368 if (onum(term
, fmt
, (int)val
, olen
) == 0)
372 if (*str
< '1' || *str
> '9')
375 if (push(params
[l
].num
, params
[l
].string
, &stack
))
379 pop(&val
, NULL
, &stack
);
380 if (*str
>= 'a' && *str
<= 'z')
381 dnums
[*str
- 'a'] = val
;
382 else if (*str
>= 'A' && *str
<= 'Z')
383 term
->_snums
[*str
- 'A'] = val
;
386 if (*str
>= 'a' && *str
<= 'z') {
387 if (push(dnums
[*str
- 'a'], NULL
, &stack
))
389 } else if (*str
>= 'A' && *str
<= 'Z') {
390 if (push(term
->_snums
[*str
- 'A'],
402 if (push((long)(unsigned char)*str
++, NULL
, &stack
))
404 while (*str
!= '\0' && *str
!= '\'')
411 for (; isdigit((unsigned char)*str
); str
++)
412 val
= (val
* 10) + (*str
- '0');
413 if (push(val
, NULL
, &stack
))
415 while (*str
!= '\0' && *str
!= '}')
420 case '+': /* FALLTHROUGH */
421 case '-': /* FALLTHROUGH */
422 case '*': /* FALLTHROUGH */
423 case '/': /* FALLTHROUGH */
424 case 'm': /* FALLTHROUGH */
425 case 'A': /* FALLTHROUGH */
426 case 'O': /* FALLTHROUGH */
427 case '&': /* FALLTHROUGH */
428 case '|': /* FALLTHROUGH */
429 case '^': /* FALLTHROUGH */
430 case '=': /* FALLTHROUGH */
431 case '<': /* FALLTHROUGH */
433 pop(&val
, NULL
, &stack
);
434 pop(&val2
, NULL
, &stack
);
446 val
= val
? val2
/ val
: 0;
449 val
= val
? val2
% val
: 0;
476 if (push(val
, NULL
, &stack
))
481 pop(&val
, NULL
, &stack
);
490 if (push(val
, NULL
, &stack
))
496 pop(&val
, NULL
, &stack
);
499 for (; *str
!= '\0'; str
++) {
505 else if (*str
== ';') {
512 } else if (*str
== 'e' && l
== 0) {
521 for (; *str
!= '\0'; str
++) {
527 else if (*str
== ';') {
541 term
->_buf
[term
->_bufpos
] = '\0';
546 ti_tiparm(TERMINAL
*term
, const char *str
, ...)
551 _DIAGASSERT(term
!= NULL
);
552 _DIAGASSERT(str
!= NULL
);
555 ret
= _ti_tiparm(term
, str
, VA_CHAR_INT
, va
);
561 tiparm(const char *str
, ...)
566 _DIAGASSERT(str
!= NULL
);
569 ret
= _ti_tiparm(NULL
, str
, VA_CHAR_INT
, va
);
576 ti_tlparm(TERMINAL
*term
, const char *str
, ...)
581 _DIAGASSERT(term
!= NULL
);
582 _DIAGASSERT(str
!= NULL
);
585 ret
= _ti_tiparm(term
, str
, VA_CHAR_LONG
, va
);
591 tlparm(const char *str
, ...)
596 _DIAGASSERT(str
!= NULL
);
599 ret
= _ti_tiparm(NULL
, str
, VA_CHAR_LONG
, va
);
606 _tparm(const char *str
, ...)
611 _DIAGASSERT(str
!= NULL
);
614 ret
= _ti_tiparm(NULL
, str
, VA_LONG_LONG
, va
);
620 tparm(const char *str
,
621 long p1
, long p2
, long p3
, long p4
, long p5
,
622 long p6
, long p7
, long p8
, long p9
)
625 return _tparm(str
, p1
, p2
, p3
, p4
, p5
, p6
, p7
, p8
, p9
);