1 /****************************************************************************
2 * Copyright (c) 1998,2000,2002 Free Software Foundation, Inc. *
4 * Permission is hereby granted, free of charge, to any person obtaining a *
5 * copy of this software and associated documentation files (the *
6 * "Software"), to deal in the Software without restriction, including *
7 * without limitation the rights to use, copy, modify, merge, publish, *
8 * distribute, distribute with modifications, sublicense, and/or sell *
9 * copies of the Software, and to permit persons to whom the Software is *
10 * furnished to do so, subject to the following conditions: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
23 * Except as contained in this notice, the name(s) of the above copyright *
24 * holders shall not be used in advertising or otherwise to promote the *
25 * sale, use or other dealings in this Software without prior written *
27 ****************************************************************************/
29 /**********************************************************************
30 * This code is a modification of lib_tparm.c found in ncurses-5.2. The
31 * modification are for use in grub by replacing all libc function through
32 * special grub functions. This also meant to delete all dynamic memory
33 * allocation and replace it by a number of fixed buffers.
35 * Modifications by Tilmann Bubeck <t.bubeck@reinform.de> 2002
36 **********************************************************************/
38 /****************************************************************************
39 * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
40 * and: Eric S. Raymond <esr@snark.thyrsus.com> *
41 ****************************************************************************/
53 * Common/troublesome character definitions
55 typedef char grub_bool
;
57 #define isdigit(c) ((c) >= '0' && (c) <= '9')
62 # define TRUE (!FALSE)
64 #define MAX_FORMAT_LEN 256
65 #define max(a,b) ((a) > (b) ? (a) : (b))
67 //MODULE_ID("$Id: tparm.c,v 1.1.1.1 2003/11/20 02:04:59 fengshuo Exp $")
73 * Substitute the given parameters into the given string by the following
74 * rules (taken from terminfo(5)):
76 * Cursor addressing and other strings requiring parame-
77 * ters in the terminal are described by a parameterized string
78 * capability, with like escapes %x in it. For example, to
79 * address the cursor, the cup capability is given, using two
80 * parameters: the row and column to address to. (Rows and
81 * columns are numbered from zero and refer to the physical
82 * screen visible to the user, not to any unseen memory.) If
83 * the terminal has memory relative cursor addressing, that can
86 * The parameter mechanism uses a stack and special %
87 * codes to manipulate it. Typically a sequence will push one
88 * of the parameters onto the stack and then print it in some
89 * format. Often more complex operations are necessary.
91 * The % encodings have the following meanings:
94 * %c print pop() like %c in printf()
95 * %s print pop() like %s in printf()
96 * %[[:]flags][width[.precision]][doxXs]
97 * as in printf, flags are [-+#] and space
98 * The ':' is used to avoid making %+ or %-
99 * patterns (see below).
101 * %p[1-9] push ith parm
102 * %P[a-z] set dynamic variable [a-z] to pop()
103 * %g[a-z] get dynamic variable [a-z] and push it
104 * %P[A-Z] set static variable [A-Z] to pop()
105 * %g[A-Z] get static variable [A-Z] and push it
106 * %l push strlen(pop)
107 * %'c' push char constant c
108 * %{nn} push integer constant nn
111 * arithmetic (%m is mod): push(pop() op pop())
112 * %& %| %^ bit operations: push(pop() op pop())
113 * %= %> %< logical operations: push(pop() op pop())
114 * %A %O logical and & or operations for conditionals
115 * %! %~ unary operations push(op pop())
116 * %i add 1 to first two parms (for ANSI terminals)
118 * %? expr %t thenpart %e elsepart %;
119 * if-then-else, %e elsepart is optional.
120 * else-if's are possible ala Algol 68:
121 * %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
123 * For those of the above operators which are binary and not commutative,
124 * the stack works in the usual way, with
126 * resulting in x mod y, not the reverse.
139 static stack_frame stack
[STACKSIZE
];
140 static int stack_ptr
;
142 static char out_buff
[256];
143 static int out_size
= 256;
150 if (need
> out_size
) {
151 // FIX ME! buffer full, what now?
157 save_text(const char *fmt
, const char *s
, int len
)
159 int s_len
= grub_strlen(s
);
160 if (len
> (int) s_len
)
163 get_space(s_len
+ 1);
165 (void) grub_sprintf(out_buff
+ out_used
, fmt
, s
);
166 out_used
+= grub_strlen(out_buff
+ out_used
);
170 save_number(const char *fmt
, int number
, int len
)
173 len
= 30; /* actually log10(MAX_INT)+1 */
177 (void) grub_sprintf(out_buff
+ out_used
, fmt
, number
);
178 out_used
+= grub_strlen(out_buff
+ out_used
);
187 out_buff
[out_used
++] = c
;
193 if (stack_ptr
< STACKSIZE
) {
194 stack
[stack_ptr
].num_type
= TRUE
;
195 stack
[stack_ptr
].data
.num
= x
;
206 if (stack
[stack_ptr
].num_type
)
207 result
= stack
[stack_ptr
].data
.num
;
215 if (stack_ptr
< STACKSIZE
) {
216 stack
[stack_ptr
].num_type
= FALSE
;
217 stack
[stack_ptr
].data
.str
= x
;
225 static char dummy
[] = ""; /* avoid const-cast */
226 char *result
= dummy
;
229 if (!stack
[stack_ptr
].num_type
&& stack
[stack_ptr
].data
.str
!= 0)
230 result
= stack
[stack_ptr
].data
.str
;
235 static inline const char *
236 parse_format(const char *s
, char *format
, int *len
)
238 grub_bool done
= FALSE
;
239 grub_bool allowminus
= FALSE
;
240 grub_bool dot
= FALSE
;
241 grub_bool err
= FALSE
;
249 while (*s
!= '\0' && !done
) {
251 case 'c': /* FALLTHRU */
252 case 'd': /* FALLTHRU */
253 case 'o': /* FALLTHRU */
254 case 'x': /* FALLTHRU */
255 case 'X': /* FALLTHRU */
289 value
= (value
* 10) + (*s
- '0');
300 * If we found an error, ignore (and remove) the flags.
303 prec
= width
= value
= 0;
315 /* return maximum string length in print */
316 *len
= (prec
> width
) ? prec
: width
;
320 #define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
321 #define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
324 tparam_internal(const char *string
, int *dataptr
)
337 register const char *cp
;
338 static int len_fmt
= MAX_FORMAT_LEN
;
339 static char dummy
[] = "";
340 static char format
[MAX_FORMAT_LEN
];
341 static int dynamic_var
[NUM_VARS
];
342 static int static_vars
[NUM_VARS
];
348 if ((len2
= grub_strlen(string
)) > len_fmt
) {
353 * Find the highest parameter-number referred to in the format string.
354 * Use this value to limit the number of arguments copied from the
355 * variable-length argument list.
361 grub_memset(p_is_s
, 0, sizeof(p_is_s
));
364 * Analyze the string to see how many parameters we need from the varargs
365 * list, and what their types are. We will only accept string parameters
366 * if they appear as a %l or %s format following an explicit parameter
367 * reference (e.g., %p2%s). All other parameters are numbers.
369 * 'number' counts coarsely the number of pop's we see in the string, and
370 * 'popcount' shows the highest parameter number in the string. We would
371 * like to simply use the latter count, but if we are reading termcap
372 * strings, there may be cases that we cannot see the explicit parameter
375 for (cp
= string
; (cp
- string
) < (int) len2
;) {
378 cp
= parse_format(cp
, format
, &len
);
383 case 'd': /* FALLTHRU */
384 case 'o': /* FALLTHRU */
385 case 'x': /* FALLTHRU */
386 case 'X': /* FALLTHRU */
387 case 'c': /* FALLTHRU */
395 p_is_s
[lastpop
- 1] = dummy
;
402 if (i
>= 0 && i
<= 9) {
404 if (lastpop
> popcount
)
421 while (*cp
>= '0' && *cp
<= '9') {
458 for (i
= 0; i
< max(popcount
, number
); i
++) {
460 * A few caps (such as plab_norm) have string-valued parms.
461 * We'll have to assume that the caller knows the difference, since
462 * a char* and an int may not be the same size on the stack.
464 if (p_is_s
[i
] != 0) {
465 p_is_s
[i
] = (char *)(*(dataptr
++));
467 param
[i
] = (int)(*(dataptr
++));
472 * This is a termcap compatibility hack. If there are no explicit pop
473 * operations in the string, load the stack in such a way that
474 * successive pops will grab successive parameters. That will make
475 * the expansion of (for example) \E[%d;%dH work correctly in termcap
476 * style, which means tparam() will expand termcap strings OK.
481 for (i
= number
- 1; i
>= 0; i
--)
486 /* skip delay timings */
487 if (*string
== '$' && *(string
+ 1) == '<') {
488 while( *string
&& *string
!= '>')
490 if ( *string
== '>' ) string
++;
491 } else if ( *string
== '%') {
493 string
= parse_format(string
, format
, &len
);
501 case 'd': /* FALLTHRU */
502 case 'o': /* FALLTHRU */
503 case 'x': /* FALLTHRU */
504 case 'X': /* FALLTHRU */
505 case 'c': /* FALLTHRU */
506 save_number(format
, npop(), len
);
510 save_number("%d", strlen(spop()), 0);
514 save_text(format
, spop(), len
);
520 if (i
>= 0 && i
< 9) {
530 if (isUPPER(*string
)) {
532 static_vars
[i
] = npop();
533 } else if (isLOWER(*string
)) {
535 dynamic_var
[i
] = npop();
541 if (isUPPER(*string
)) {
543 npush(static_vars
[i
]);
544 } else if (isLOWER(*string
)) {
546 npush(dynamic_var
[i
]);
559 while (*string
>= '0' && *string
<= '9') {
560 number
= number
* 10 + *string
- '0';
567 npush(npop() + npop());
577 npush(npop() * npop());
583 npush(y
? (x
/ y
) : 0);
589 npush(y
? (x
% y
) : 0);
593 npush(npop() && npop());
597 npush(npop() || npop());
601 npush(npop() & npop());
605 npush(npop() | npop());
609 npush(npop() ^ npop());
651 /* scan forward for %e or %; at level zero */
655 if (*string
== '%') {
659 else if (*string
== ';') {
664 } else if (*string
== 'e' && level
== 0)
675 /* scan forward for a %; at level zero */
679 if (*string
== '%') {
683 else if (*string
== ';') {
699 } /* endswitch (*string) */
700 } else { /* endelse (*string == '%') */
708 } /* endwhile (*string) */
711 out_buff
[out_used
] = '\0';
717 grub_tparm(const char *string
,...)
720 int *dataptr
= (int *) &string
;
724 result
= tparam_internal(string
, dataptr
);