1 /* $NetBSD: tparm.c,v 1.8 2012/06/02 19:10:33 roy Exp $ */
4 * Copyright (c) 2009, 2011 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.8 2012/06/02 19:10:33 roy Exp $");
32 #include <sys/param.h>
41 #include <term_private.h>
44 static TERMINAL
*dumbterm
; /* For non thread safe functions */
58 push(int num
, char *string
, TPSTACK
*stack
)
60 if (stack
->offset
> sizeof(stack
->nums
)) {
64 stack
->nums
[stack
->offset
] = num
;
65 stack
->strings
[stack
->offset
] = string
;
71 pop(int *num
, char **string
, TPSTACK
*stack
)
73 if (stack
->offset
== 0) {
83 *num
= stack
->nums
[stack
->offset
];
85 *string
= stack
->strings
[stack
->offset
];
90 checkbuf(TERMINAL
*term
, size_t len
)
94 if (term
->_bufpos
+ len
>= term
->_buflen
) {
95 len
= term
->_buflen
+ MAX(len
, BUFSIZ
);
96 buf
= realloc(term
->_buf
, len
);
106 ochar(TERMINAL
*term
, int c
)
110 /* Check we have space and a terminator */
111 if (checkbuf(term
, 2) == NULL
)
113 term
->_buf
[term
->_bufpos
++] = (char)c
;
118 onum(TERMINAL
*term
, const char *fmt
, int num
, int len
)
122 /* Assume we never have natural number longer than 64 chars */
125 if (checkbuf(term
, (size_t)len
+ 1) == NULL
)
127 l
= sprintf(term
->_buf
+ term
->_bufpos
, fmt
, num
);
133 _ti_tiparm(TERMINAL
*term
, const char *str
, va_list parms
)
136 char c
, fmt
[64], *fp
, *ostr
;
138 int dnums
[26]; /* dynamic variables a-z, not preserved */
142 int done
, dot
, minus
, width
, precision
, olen
;
143 int piss
[9]; /* Parameter IS String - piss ;) */
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
156 if (dumbterm
== NULL
) {
157 dumbterm
= malloc(sizeof(*dumbterm
));
158 if (dumbterm
== NULL
)
160 dumbterm
->_buflen
= 0;
166 /* Ensure we have an initial buffer */
167 if (term
->_buflen
== 0) {
168 term
->_buf
= malloc(BUFSIZ
);
169 if (term
->_buf
== 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
));
182 while ((c
= *sp
++) != '\0') {
191 if (c
< '1' || c
> '9') {
200 /* Skip formatting */
202 while (*sp
== '.' || *sp
== '#' || *sp
== ' ' || *sp
== ':' ||
203 *sp
== '-' || isdigit((unsigned char)*sp
))
205 if (*sp
== 'l' || *sp
== 's')
209 /* Put our parameters into variables */
210 memset(¶ms
, 0, sizeof(params
));
211 for (l
= 0; l
< max
; l
++) {
213 params
[l
].num
= va_arg(parms
, int);
215 params
[l
].string
= va_arg(parms
, char *);
219 memset(&stack
, 0, sizeof(stack
));
220 while ((c
= *str
++) != '\0') {
221 if (c
!= '%' || (c
= *str
++) == '%') {
224 if (ochar(term
, c
) == 0)
229 /* Handle formatting. */
232 done
= dot
= minus
= width
= precision
= 0;
234 while (done
== 0 && (size_t)(fp
- fmt
) < sizeof(fmt
)) {
236 case 'c': /* FALLTHROUGH */
237 case 'd': /* FALLTHROUGH */
238 case 'o': /* FALLTHROUGH */
239 case 'x': /* FALLTHROUGH */
240 case 'X': /* FALLTHROUGH */
245 case '#': /* FALLTHROUGH */
268 if (isdigit((unsigned char)c
)) {
269 val
= (val
* 10) + (c
- '0');
281 /* Found an error in the format */
290 olen
= (width
> precision
) ? width
: precision
;
294 /* Handle commands */
297 pop(&val
, NULL
, &stack
);
298 if (ochar(term
, (unsigned char)val
) == 0)
302 pop(NULL
, &ostr
, &stack
);
305 if (l
< (size_t)olen
)
307 if (checkbuf(term
, (size_t)(l
+ 1)) == NULL
)
309 l
= sprintf(term
->_buf
+ term
->_bufpos
,
315 pop(NULL
, &ostr
, &stack
);
320 if (onum(term
, "%d", (int)l
, 0) == 0)
323 case 'd': /* FALLTHROUGH */
324 case 'o': /* FALLTHROUGH */
325 case 'x': /* FALLTHROUGH */
327 pop(&val
, NULL
, &stack
);
328 if (onum(term
, fmt
, val
, olen
) == 0)
332 if (*str
< '1' || *str
> '9')
335 if (push(params
[l
].num
, params
[l
].string
, &stack
))
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
;
346 if (*str
>= 'a' && *str
<= 'z') {
347 if (push(dnums
[*str
- 'a'], NULL
, &stack
))
349 } else if (*str
>= 'A' && *str
<= 'Z') {
350 if (push(term
->_snums
[*str
- 'A'],
362 if (push((int)(unsigned char)*str
++, NULL
, &stack
))
364 while (*str
!= '\0' && *str
!= '\'')
371 for (; isdigit((unsigned char)*str
); str
++)
372 val
= (val
* 10) + (*str
- '0');
373 if (push(val
, NULL
, &stack
))
375 while (*str
!= '\0' && *str
!= '}')
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 */
393 pop(&val
, NULL
, &stack
);
394 pop(&val2
, NULL
, &stack
);
406 val
= val
? val2
/ val
: 0;
409 val
= val
? val2
% val
: 0;
436 if (push(val
, NULL
, &stack
))
441 pop(&val
, NULL
, &stack
);
450 if (push(val
, NULL
, &stack
))
456 pop(&val
, NULL
, &stack
);
459 for (; *str
!= '\0'; str
++) {
465 else if (*str
== ';') {
470 } else if (*str
== 'e' && l
== 0)
477 for (; *str
!= '\0'; str
++) {
483 else if (*str
== ';') {
495 term
->_buf
[term
->_bufpos
] = '\0';
500 ti_tiparm(TERMINAL
*term
, const char *str
, ...)
505 _DIAGASSERT(term
!= NULL
);
506 _DIAGASSERT(str
!= NULL
);
509 ret
= _ti_tiparm(term
, str
, va
);
515 tiparm(const char *str
, ...)
520 _DIAGASSERT(str
!= NULL
);
523 ret
= _ti_tiparm(NULL
, str
, va
);
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
);