1 /* $NetBSD: tparm.c,v 1.2 2010/09/22 06:10:51 roy Exp $ */
4 * Copyright (c) 2009 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.2 2010/09/22 06:10:51 roy Exp $");
40 #include <term_private.h>
43 static TERMINAL
*dumbterm
; /* For non thread safe functions */
57 push(long num
, char *string
, TPSTACK
*stack
)
59 if (stack
->offset
> sizeof(stack
->nums
)) {
63 stack
->nums
[stack
->offset
] = num
;
64 stack
->strings
[stack
->offset
] = string
;
70 pop(long *num
, char **string
, TPSTACK
*stack
)
72 if (stack
->offset
== 0) {
78 *num
= stack
->nums
[stack
->offset
];
80 *string
= stack
->strings
[stack
->offset
];
85 checkbuf(TERMINAL
*term
, size_t len
)
89 if (term
->_bufpos
+ len
>= term
->_buflen
) {
90 len
= term
->_buflen
+ BUFSIZ
;
91 buf
= realloc(term
->_buf
, len
);
101 ochar(TERMINAL
*term
, int c
)
105 /* Check we have space and a terminator */
106 if (checkbuf(term
, 2) == NULL
)
108 term
->_buf
[term
->_bufpos
++] = (char)c
;
113 onum(TERMINAL
*term
, const char *fmt
, long num
, int len
)
117 /* Assume we never have natural number longer than 64 chars */
120 if (checkbuf(term
, (size_t)len
+ 1) == NULL
)
122 l
= sprintf(term
->_buf
+ term
->_bufpos
, fmt
, num
);
128 _ti_vtparm(TERMINAL
*term
, const char *str
, va_list parms
)
131 char c
, fmt
[64], *fp
, *ostr
;
133 long dnums
[26]; /* dynamic variables a-z, not preserved */
137 int done
, dot
, minus
, width
, precision
, olen
;
138 int piss
[9]; /* Parameter IS String - piss ;) */
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
150 if (dumbterm
== NULL
) {
151 dumbterm
= malloc(sizeof(*dumbterm
));
152 if (dumbterm
== NULL
)
154 dumbterm
->_buflen
= 0;
160 /* Ensure we have an initial buffer */
161 if (term
->_buflen
== 0) {
162 term
->_buf
= malloc(BUFSIZ
);
163 if (term
->_buf
== 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
));
176 while ((c
= *sp
++) != '\0') {
185 if (c
< '1' || c
> '9') {
194 /* Skip formatting */
196 while (*sp
== '.' || *sp
== '#' || *sp
== ' ' || *sp
== ':' ||
197 *sp
== '-' || isdigit((unsigned char)*sp
))
199 if (*sp
== 'l' || *sp
== 's')
203 /* Put our parameters into variables */
204 memset(¶ms
, 0, sizeof(params
));
205 for (l
= 0; l
< max
; l
++) {
207 params
[l
].num
= va_arg(parms
, long);
209 params
[l
].string
= va_arg(parms
, char *);
213 memset(&stack
, 0, sizeof(stack
));
214 while ((c
= *str
++) != '\0') {
215 if (c
!= '%' || (c
= *str
++) == '%') {
218 if (ochar(term
, c
) == 0)
223 /* Handle formatting. */
226 done
= dot
= minus
= width
= precision
= 0;
228 while (done
== 0 && (size_t)(fp
- fmt
) < sizeof(fmt
)) {
230 case 'c': /* FALLTHROUGH */
231 case 'd': /* FALLTHROUGH */
232 case 'o': /* FALLTHROUGH */
233 case 'x': /* FALLTHROUGH */
234 case 'X': /* FALLTHROUGH */
239 case '#': /* FALLTHROUGH */
262 if (isdigit((unsigned char)c
)) {
263 val
= (val
* 10) + (c
- '0');
275 /* Found an error in the format */
284 olen
= (width
> precision
) ? width
: precision
;
288 /* Handle commands */
291 if (pop(&val
, NULL
, &stack
))
293 if (ochar(term
, (unsigned char)val
) == 0)
297 if (pop(NULL
, &ostr
, &stack
))
301 if (l
< (size_t)olen
)
303 if (checkbuf(term
, (size_t)(l
+ 1)) == NULL
)
305 l
= sprintf(term
->_buf
+ term
->_bufpos
,
311 if (pop(NULL
, &ostr
, &stack
))
317 if (onum(term
, "%d", (long)l
, 0) == 0)
320 case 'd': /* FALLTHROUGH */
321 case 'o': /* FALLTHROUGH */
322 case 'x': /* FALLTHROUGH */
324 if (pop(&val
, NULL
, &stack
))
326 if (onum(term
, fmt
, val
, olen
) == 0)
330 if (*str
< '1' || *str
> '9') {
335 if (push(params
[l
].num
, params
[l
].string
, &stack
))
339 if (pop(&val
, NULL
, &stack
))
342 if (*str
>= 'a' && *str
<= 'z')
343 dnums
[*str
- 'a'] = val
;
344 else if (*str
>= 'A' && *str
<= 'Z')
345 term
->_snums
[*str
- 'A'] = val
;
349 if (*str
>= 'a' && *str
<= 'z') {
350 if (push(dnums
[*str
- 'a'], NULL
, &stack
))
352 } else if (*str
>= 'A' && *str
<= 'Z') {
353 if (push(term
->_snums
[*str
- 'A'],
365 if (push((long)(unsigned char)*str
++, NULL
, &stack
))
367 while (*str
!= '\0' && *str
!= '\'')
374 for (str
++; isdigit((unsigned char)*str
); str
++)
375 val
= (val
* 10) + (*str
- '0');
376 if (push(val
, NULL
, &stack
))
378 while (*str
!= '\0' && *str
!= '}')
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 */
396 if (pop(&val
, NULL
, &stack
) ||
397 pop(&val2
, NULL
, &stack
))
410 val
= val
? val2
/ val
: 0;
413 val
= val
? val2
% val
: 0;
440 if (push(val
, NULL
, &stack
))
445 if (pop(&val
, NULL
, &stack
))
455 if (push(val
, NULL
, &stack
))
461 if (pop(&val
, NULL
, &stack
))
465 for (; *str
!= '\0'; str
++) {
471 else if (*str
== ';') {
476 } else if (*str
== 'e' && l
== 0)
483 for (; *str
!= '\0'; str
++) {
489 else if (*str
== ';') {
501 term
->_buf
[term
->_bufpos
] = '\0';
506 t_vparm(TERMINAL
*term
, const char *str
, ...)
511 _DIAGASSERT(term
!= NULL
);
512 _DIAGASSERT(str
!= NULL
);
515 ret
= _ti_vtparm(term
, str
, va
);
521 vtparm(const char *str
, ...)
526 _DIAGASSERT(str
!= NULL
);
529 ret
= _ti_vtparm(NULL
, str
, va
);
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
);
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
);