~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/term/tparm.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Robert Millan, Updated translations
  • Date: 2010-11-22 12:24:56 UTC
  • mfrom: (1.26.4 upstream) (17.3.36 sid)
  • mto: (17.3.43 sid)
  • mto: This revision was merged to the branch mainline in revision 89.
  • Revision ID: james.westby@ubuntu.com-20101122122456-y82z3sfb7k4zfdcc
Tags: 1.99~20101122-1
[ Colin Watson ]
* New Bazaar snapshot.  Too many changes to list in full, but some of the
  more user-visible ones are as follows:
  - GRUB script:
    + Function parameters, "break", "continue", "shift", "setparams",
      "return", and "!".
    + "export" command supports multiple variable names.
    + Multi-line quoted strings support.
    + Wildcard expansion.
  - sendkey support.
  - USB hotunplugging and USB serial support.
  - Rename CD-ROM to cd on BIOS.
  - Add new --boot-directory option to grub-install, grub-reboot, and
    grub-set-default; the old --root-directory option is still accepted
    but was often confusing.
  - Basic btrfs detection/UUID support (but no file reading yet).
  - bash-completion for utilities.
  - If a device is listed in device.map, always assume that it is
    BIOS-visible rather than using extra layers such as LVM or RAID.
  - Add grub-mknetdir script (closes: #550658).
  - Remove deprecated "root" command.
  - Handle RAID devices containing virtio components.
  - GRUB Legacy configuration file support (via grub-menulst2cfg).
  - Keyboard layout support (via grub-mklayout and grub-kbdcomp).
  - Check generated grub.cfg for syntax errors before saving.
  - Pause execution for at most ten seconds if any errors are displayed,
    so that the user has a chance to see them.
  - Support submenus.
  - Write embedding zone using Reed-Solomon, so that it's robust against
    being partially overwritten (closes: #550702, #591416, #593347).
  - GRUB_DISABLE_LINUX_RECOVERY and GRUB_DISABLE_NETBSD_RECOVERY merged
    into a single GRUB_DISABLE_RECOVERY variable.
  - Fix loader memory allocation failure (closes: #551627).
  - Don't call savedefault on recovery entries (closes: #589325).
  - Support triple-indirect blocks on ext2 (closes: #543924).
  - Recognise DDF1 fake RAID (closes: #603354).

[ Robert Millan ]
* Use dpkg architecture wildcards.

[ Updated translations ]
* Slovenian (Vanja Cvelbar).  Closes: #604003
* Dzongkha (dawa pemo via Tenzin Dendup).  Closes: #604102

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 1998-2003,2004,2005 Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
/**********************************************************************
 
20
 * This code is a modification of lib_tparm.c found in ncurses-5.2. The
 
21
 * modification are for use in grub by replacing all libc function through
 
22
 * special grub functions. This also meant to delete all dynamic memory
 
23
 * allocation and replace it by a number of fixed buffers.
 
24
 *
 
25
 * Modifications by Tilmann Bubeck <t.bubeck@reinform.de> 2002
 
26
 *
 
27
 * Resync with ncurses-5.4 by Omniflux <omniflux+devel@omniflux.com> 2005
 
28
 **********************************************************************/
 
29
 
 
30
/****************************************************************************
 
31
 *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
 
32
 *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
 
33
 *     and: Thomas E. Dickey, 1996 on                                       *
 
34
 ****************************************************************************/
 
35
 
 
36
/*
 
37
 *      tparm.c
 
38
 *
 
39
 */
 
40
 
 
41
#include <grub/misc.h>
 
42
#include <grub/mm.h>
 
43
#include <grub/types.h>
 
44
#include <grub/tparm.h>
 
45
 
 
46
/*
 
47
 * Common/troublesome character definitions
 
48
 */
 
49
typedef char grub_bool_t;
 
50
#ifndef FALSE
 
51
# define FALSE (0)
 
52
#endif
 
53
#ifndef TRUE
 
54
# define TRUE (!FALSE)
 
55
#endif
 
56
 
 
57
#define NUM_PARM 9
 
58
#define NUM_VARS 26
 
59
#define STACKSIZE 20
 
60
#define MAX_FORMAT_LEN 256
 
61
 
 
62
#define max(a,b) ((a) > (b) ? (a) : (b))
 
63
#define isdigit(c) ((c) >= '0' && (c) <= '9')
 
64
#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
 
65
#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
 
66
 
 
67
#define UChar(c) ((unsigned char)(c))
 
68
 
 
69
//MODULE_ID("$Id$")
 
70
 
 
71
/*
 
72
 *      char *
 
73
 *      tparm(string, ...)
 
74
 *
 
75
 *      Substitute the given parameters into the given string by the following
 
76
 *      rules (taken from terminfo(5)):
 
77
 *
 
78
 *           Cursor addressing and other strings  requiring  parame-
 
79
 *      ters in the terminal are described by a parameterized string
 
80
 *      capability, with like escapes %x in  it.   For  example,  to
 
81
 *      address  the  cursor, the cup capability is given, using two
 
82
 *      parameters: the row and column to  address  to.   (Rows  and
 
83
 *      columns  are  numbered  from  zero and refer to the physical
 
84
 *      screen visible to the user, not to any  unseen  memory.)  If
 
85
 *      the terminal has memory relative cursor addressing, that can
 
86
 *      be indicated by
 
87
 *
 
88
 *           The parameter mechanism uses  a  stack  and  special  %
 
89
 *      codes  to manipulate it.  Typically a sequence will push one
 
90
 *      of the parameters onto the stack and then print it  in  some
 
91
 *      format.  Often more complex operations are necessary.
 
92
 *
 
93
 *           The % encodings have the following meanings:
 
94
 *
 
95
 *           %%        outputs `%'
 
96
 *           %c        print pop() like %c in printf()
 
97
 *           %s        print pop() like %s in printf()
 
98
 *           %[[:]flags][width[.precision]][doxXs]
 
99
 *                     as in printf, flags are [-+#] and space
 
100
 *                     The ':' is used to avoid making %+ or %-
 
101
 *                     patterns (see below).
 
102
 *
 
103
 *           %p[1-9]   push ith parm
 
104
 *           %P[a-z]   set dynamic variable [a-z] to pop()
 
105
 *           %g[a-z]   get dynamic variable [a-z] and push it
 
106
 *           %P[A-Z]   set static variable [A-Z] to pop()
 
107
 *           %g[A-Z]   get static variable [A-Z] and push it
 
108
 *           %l        push strlen(pop)
 
109
 *           %'c'      push char constant c
 
110
 *           %{nn}     push integer constant nn
 
111
 *
 
112
 *           %+ %- %* %/ %m
 
113
 *                     arithmetic (%m is mod): push(pop() op pop())
 
114
 *           %& %| %^  bit operations: push(pop() op pop())
 
115
 *           %= %> %<  logical operations: push(pop() op pop())
 
116
 *           %A %O     logical and & or operations for conditionals
 
117
 *           %! %~     unary operations push(op pop())
 
118
 *           %i        add 1 to first two parms (for ANSI terminals)
 
119
 *
 
120
 *           %? expr %t thenpart %e elsepart %;
 
121
 *                     if-then-else, %e elsepart is optional.
 
122
 *                     else-if's are possible ala Algol 68:
 
123
 *                     %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
 
124
 *
 
125
 *      For those of the above operators which are binary and not commutative,
 
126
 *      the stack works in the usual way, with
 
127
 *                      %gx %gy %m
 
128
 *      resulting in x mod y, not the reverse.
 
129
 */
 
130
 
 
131
typedef struct {
 
132
    union {
 
133
        int num;
 
134
        char *str;
 
135
    } data;
 
136
    grub_bool_t num_type;
 
137
} stack_frame;
 
138
 
 
139
static stack_frame stack[STACKSIZE];
 
140
static int stack_ptr;
 
141
static const char *tparam_base = "";
 
142
 
 
143
static char *out_buff;
 
144
static grub_size_t out_size;
 
145
static grub_size_t out_used;
 
146
 
 
147
static char *fmt_buff;
 
148
static grub_size_t fmt_size;
 
149
 
 
150
static inline void
 
151
get_space(grub_size_t need)
 
152
{
 
153
    need += out_used;
 
154
    if (need > out_size) {
 
155
        out_size = need * 2;
 
156
        out_buff = grub_realloc(out_buff, out_size*sizeof(char));
 
157
        /* FIX ME! handle out_buff == 0.  */
 
158
    }
 
159
}
 
160
 
 
161
static inline void
 
162
save_text(const char *fmt, const char *s, int len)
 
163
{
 
164
    grub_size_t s_len = grub_strlen(s);
 
165
    if (len > (int) s_len)
 
166
        s_len = len;
 
167
 
 
168
    get_space(s_len + 1);
 
169
 
 
170
    (void) grub_snprintf(out_buff + out_used, s_len + 1, fmt, s);
 
171
    out_used += grub_strlen(out_buff + out_used);
 
172
}
 
173
 
 
174
static inline void
 
175
save_number(const char *fmt, int number, int len)
 
176
{
 
177
    if (len < 30)
 
178
        len = 30;               /* actually log10(MAX_INT)+1 */
 
179
 
 
180
    get_space((unsigned) len + 1);
 
181
 
 
182
    (void) grub_snprintf(out_buff + out_used, len + 1, fmt, number);
 
183
    out_used += grub_strlen(out_buff + out_used);
 
184
}
 
185
 
 
186
static inline void
 
187
save_char(int c)
 
188
{
 
189
    if (c == 0)
 
190
        c = 0200;
 
191
    get_space(1);
 
192
    out_buff[out_used++] = c;
 
193
}
 
194
 
 
195
static inline void
 
196
npush(int x)
 
197
{
 
198
    if (stack_ptr < STACKSIZE) {
 
199
        stack[stack_ptr].num_type = TRUE;
 
200
        stack[stack_ptr].data.num = x;
 
201
        stack_ptr++;
 
202
    }
 
203
}
 
204
 
 
205
static inline int
 
206
npop(void)
 
207
{
 
208
    int result = 0;
 
209
    if (stack_ptr > 0) {
 
210
        stack_ptr--;
 
211
        if (stack[stack_ptr].num_type)
 
212
            result = stack[stack_ptr].data.num;
 
213
    }
 
214
    return result;
 
215
}
 
216
 
 
217
static inline void
 
218
spush(char *x)
 
219
{
 
220
    if (stack_ptr < STACKSIZE) {
 
221
        stack[stack_ptr].num_type = FALSE;
 
222
        stack[stack_ptr].data.str = x;
 
223
        stack_ptr++;
 
224
    }
 
225
}
 
226
 
 
227
static inline char *
 
228
spop(void)
 
229
{
 
230
    static char dummy[] = "";   /* avoid const-cast */
 
231
    char *result = dummy;
 
232
    if (stack_ptr > 0) {
 
233
        stack_ptr--;
 
234
        if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
 
235
            result = stack[stack_ptr].data.str;
 
236
    }
 
237
    return result;
 
238
}
 
239
 
 
240
static inline const char *
 
241
parse_format(const char *s, char *format, int *len)
 
242
{
 
243
    *len = 0;
 
244
    if (format != 0) {
 
245
        grub_bool_t done = FALSE;
 
246
        grub_bool_t allowminus = FALSE;
 
247
        grub_bool_t dot = FALSE;
 
248
        grub_bool_t err = FALSE;
 
249
        char *fmt = format;
 
250
        int my_width = 0;
 
251
        int my_prec = 0;
 
252
        int value = 0;
 
253
 
 
254
        *len = 0;
 
255
        *format++ = '%';
 
256
        while (*s != '\0' && !done) {
 
257
            switch (*s) {
 
258
            case 'c':           /* FALLTHRU */
 
259
            case 'd':           /* FALLTHRU */
 
260
            case 'o':           /* FALLTHRU */
 
261
            case 'x':           /* FALLTHRU */
 
262
            case 'X':           /* FALLTHRU */
 
263
            case 's':
 
264
                *format++ = *s;
 
265
                done = TRUE;
 
266
                break;
 
267
            case '.':
 
268
                *format++ = *s++;
 
269
                if (dot) {
 
270
                    err = TRUE;
 
271
                } else {        /* value before '.' is the width */
 
272
                    dot = TRUE;
 
273
                    my_width = value;
 
274
                }
 
275
                value = 0;
 
276
                break;
 
277
            case '#':
 
278
                *format++ = *s++;
 
279
                break;
 
280
            case ' ':
 
281
                *format++ = *s++;
 
282
                break;
 
283
            case ':':
 
284
                s++;
 
285
                allowminus = TRUE;
 
286
                break;
 
287
            case '-':
 
288
                if (allowminus) {
 
289
                    *format++ = *s++;
 
290
                } else {
 
291
                    done = TRUE;
 
292
                }
 
293
                break;
 
294
            default:
 
295
                if (isdigit(UChar(*s))) {
 
296
                    value = (value * 10) + (*s - '0');
 
297
                    if (value > 10000)
 
298
                        err = TRUE;
 
299
                    *format++ = *s++;
 
300
                } else {
 
301
                    done = TRUE;
 
302
                }
 
303
            }
 
304
        }
 
305
 
 
306
        /*
 
307
         * If we found an error, ignore (and remove) the flags.
 
308
         */
 
309
        if (err) {
 
310
            my_width = my_prec = value = 0;
 
311
            format = fmt;
 
312
            *format++ = '%';
 
313
            *format++ = *s;
 
314
        }
 
315
 
 
316
        /*
 
317
         * Any value after '.' is the precision.  If we did not see '.', then
 
318
         * the value is the width.
 
319
         */
 
320
        if (dot)
 
321
            my_prec = value;
 
322
        else
 
323
            my_width = value;
 
324
 
 
325
        *format = '\0';
 
326
        /* return maximum string length in print */
 
327
        *len = (my_width > my_prec) ? my_width : my_prec;
 
328
    }
 
329
    return s;
 
330
}
 
331
 
 
332
/*
 
333
 * Analyze the string to see how many parameters we need from the varargs list,
 
334
 * and what their types are.  We will only accept string parameters if they
 
335
 * appear as a %l or %s format following an explicit parameter reference (e.g.,
 
336
 * %p2%s).  All other parameters are numbers.
 
337
 *
 
338
 * 'number' counts coarsely the number of pop's we see in the string, and
 
339
 * 'popcount' shows the highest parameter number in the string.  We would like
 
340
 * to simply use the latter count, but if we are reading termcap strings, there
 
341
 * may be cases that we cannot see the explicit parameter numbers.
 
342
 */
 
343
static inline int
 
344
analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount)
 
345
{
 
346
    grub_size_t len2;
 
347
    int i;
 
348
    int lastpop = -1;
 
349
    int len;
 
350
    int number = 0;
 
351
    const char *cp = string;
 
352
    static char dummy[] = "";
 
353
 
 
354
    *popcount = 0;
 
355
 
 
356
    if (cp == 0)
 
357
        return 0;
 
358
 
 
359
    if ((len2 = grub_strlen(cp)) > fmt_size) {
 
360
        fmt_size = len2 + fmt_size + 2;
 
361
        if ((fmt_buff = grub_realloc(fmt_buff, fmt_size*sizeof(char))) == 0)
 
362
              return 0;
 
363
    }
 
364
 
 
365
    grub_memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM);
 
366
 
 
367
    while ((cp - string) < (int) len2) {
 
368
        if (*cp == '%') {
 
369
            cp++;
 
370
            cp = parse_format(cp, fmt_buff, &len);
 
371
            switch (*cp) {
 
372
            default:
 
373
                break;
 
374
 
 
375
            case 'd':           /* FALLTHRU */
 
376
            case 'o':           /* FALLTHRU */
 
377
            case 'x':           /* FALLTHRU */
 
378
            case 'X':           /* FALLTHRU */
 
379
            case 'c':           /* FALLTHRU */
 
380
                if (lastpop <= 0)
 
381
                    number++;
 
382
                lastpop = -1;
 
383
                break;
 
384
 
 
385
            case 'l':
 
386
            case 's':
 
387
                if (lastpop > 0)
 
388
                    p_is_s[lastpop - 1] = dummy;
 
389
                ++number;
 
390
                break;
 
391
 
 
392
            case 'p':
 
393
                cp++;
 
394
                i = (UChar(*cp) - '0');
 
395
                if (i >= 0 && i <= NUM_PARM) {
 
396
                    lastpop = i;
 
397
                    if (lastpop > *popcount)
 
398
                        *popcount = lastpop;
 
399
                }
 
400
                break;
 
401
 
 
402
            case 'P':
 
403
                ++number;
 
404
                ++cp;
 
405
                break;
 
406
 
 
407
            case 'g':
 
408
                cp++;
 
409
                break;
 
410
 
 
411
            case '\'':
 
412
                cp += 2;
 
413
                lastpop = -1;
 
414
                break;
 
415
 
 
416
            case '{':
 
417
                cp++;
 
418
                while (isdigit(UChar(*cp))) {
 
419
                    cp++;
 
420
                }
 
421
                break;
 
422
 
 
423
            case '+':
 
424
            case '-':
 
425
            case '*':
 
426
            case '/':
 
427
            case 'm':
 
428
            case 'A':
 
429
            case 'O':
 
430
            case '&':
 
431
            case '|':
 
432
            case '^':
 
433
            case '=':
 
434
            case '<':
 
435
            case '>':
 
436
                lastpop = -1;
 
437
                number += 2;
 
438
                break;
 
439
 
 
440
            case '!':
 
441
            case '~':
 
442
                lastpop = -1;
 
443
                ++number;
 
444
                break;
 
445
 
 
446
            case 'i':
 
447
                /* will add 1 to first (usually two) parameters */
 
448
                break;
 
449
            }
 
450
        }
 
451
        if (*cp != '\0')
 
452
            cp++;
 
453
    }
 
454
 
 
455
    if (number > NUM_PARM)
 
456
        number = NUM_PARM;
 
457
    return number;
 
458
}
 
459
 
 
460
static inline char *
 
461
tparam_internal(const char *string, va_list ap)
 
462
{
 
463
    char *p_is_s[NUM_PARM];
 
464
    long param[NUM_PARM];
 
465
    int popcount;
 
466
    int number;
 
467
    int len;
 
468
    int level;
 
469
    int x, y;
 
470
    int i;
 
471
    const char *cp = string;
 
472
    grub_size_t len2;
 
473
    static int dynamic_var[NUM_VARS];
 
474
    static int static_vars[NUM_VARS];
 
475
 
 
476
    if (cp == 0)
 
477
        return 0;
 
478
 
 
479
    out_used = out_size = fmt_size = 0;
 
480
 
 
481
    len2 = (int) grub_strlen(cp);
 
482
 
 
483
    /*
 
484
     * Find the highest parameter-number referred to in the format string.
 
485
     * Use this value to limit the number of arguments copied from the
 
486
     * variable-length argument list.
 
487
     */
 
488
    number = analyze(cp, p_is_s, &popcount);
 
489
    if (fmt_buff == 0)
 
490
        return 0;
 
491
 
 
492
    for (i = 0; i < max(popcount, number); i++) {
 
493
        /*
 
494
         * A few caps (such as plab_norm) have string-valued parms.
 
495
         * We'll have to assume that the caller knows the difference, since
 
496
         * a char* and an int may not be the same size on the stack.
 
497
         */
 
498
        if (p_is_s[i] != 0) {
 
499
            p_is_s[i] = va_arg(ap, char *);
 
500
        } else {
 
501
            param[i] = va_arg(ap, long int);
 
502
        }
 
503
    }
 
504
 
 
505
    /*
 
506
     * This is a termcap compatibility hack.  If there are no explicit pop
 
507
     * operations in the string, load the stack in such a way that
 
508
     * successive pops will grab successive parameters.  That will make
 
509
     * the expansion of (for example) \E[%d;%dH work correctly in termcap
 
510
     * style, which means tparam() will expand termcap strings OK.
 
511
     */
 
512
    stack_ptr = 0;
 
513
    if (popcount == 0) {
 
514
        popcount = number;
 
515
        for (i = number - 1; i >= 0; i--)
 
516
            npush(param[i]);
 
517
    }
 
518
 
 
519
    while ((cp - string) < (int) len2) {
 
520
        if (*cp != '%') {
 
521
            save_char(UChar(*cp));
 
522
        } else {
 
523
            tparam_base = cp++;
 
524
            cp = parse_format(cp, fmt_buff, &len);
 
525
            switch (*cp) {
 
526
            default:
 
527
                break;
 
528
            case '%':
 
529
                save_char('%');
 
530
                break;
 
531
 
 
532
            case 'd':           /* FALLTHRU */
 
533
            case 'o':           /* FALLTHRU */
 
534
            case 'x':           /* FALLTHRU */
 
535
            case 'X':           /* FALLTHRU */
 
536
                save_number(fmt_buff, npop(), len);
 
537
                break;
 
538
 
 
539
            case 'c':           /* FALLTHRU */
 
540
                save_char(npop());
 
541
                break;
 
542
 
 
543
            case 'l':
 
544
                save_number("%d", (int) grub_strlen(spop()), 0);
 
545
                break;
 
546
 
 
547
            case 's':
 
548
                save_text(fmt_buff, spop(), len);
 
549
                break;
 
550
 
 
551
            case 'p':
 
552
                cp++;
 
553
                i = (UChar(*cp) - '1');
 
554
                if (i >= 0 && i < NUM_PARM) {
 
555
                    if (p_is_s[i])
 
556
                        spush(p_is_s[i]);
 
557
                    else
 
558
                        npush(param[i]);
 
559
                }
 
560
                break;
 
561
 
 
562
            case 'P':
 
563
                cp++;
 
564
                if (isUPPER(*cp)) {
 
565
                    i = (UChar(*cp) - 'A');
 
566
                    static_vars[i] = npop();
 
567
                } else if (isLOWER(*cp)) {
 
568
                    i = (UChar(*cp) - 'a');
 
569
                    dynamic_var[i] = npop();
 
570
                }
 
571
                break;
 
572
 
 
573
            case 'g':
 
574
                cp++;
 
575
                if (isUPPER(*cp)) {
 
576
                    i = (UChar(*cp) - 'A');
 
577
                    npush(static_vars[i]);
 
578
                } else if (isLOWER(*cp)) {
 
579
                    i = (UChar(*cp) - 'a');
 
580
                    npush(dynamic_var[i]);
 
581
                }
 
582
                break;
 
583
 
 
584
            case '\'':
 
585
                cp++;
 
586
                npush(UChar(*cp));
 
587
                cp++;
 
588
                break;
 
589
 
 
590
            case '{':
 
591
                number = 0;
 
592
                cp++;
 
593
                while (isdigit(UChar(*cp))) {
 
594
                    number = (number * 10) + (UChar(*cp) - '0');
 
595
                    cp++;
 
596
                }
 
597
                npush(number);
 
598
                break;
 
599
 
 
600
            case '+':
 
601
                npush(npop() + npop());
 
602
                break;
 
603
 
 
604
            case '-':
 
605
                y = npop();
 
606
                x = npop();
 
607
                npush(x - y);
 
608
                break;
 
609
 
 
610
            case '*':
 
611
                npush(npop() * npop());
 
612
                break;
 
613
 
 
614
            case '/':
 
615
                y = npop();
 
616
                x = npop();
 
617
                npush(y ? (x / y) : 0);
 
618
                break;
 
619
 
 
620
            case 'm':
 
621
                y = npop();
 
622
                x = npop();
 
623
                npush(y ? (x % y) : 0);
 
624
                break;
 
625
 
 
626
            case 'A':
 
627
                npush(npop() && npop());
 
628
                break;
 
629
 
 
630
            case 'O':
 
631
                npush(npop() || npop());
 
632
                break;
 
633
 
 
634
            case '&':
 
635
                npush(npop() & npop());
 
636
                break;
 
637
 
 
638
            case '|':
 
639
                npush(npop() | npop());
 
640
                break;
 
641
 
 
642
            case '^':
 
643
                npush(npop() ^ npop());
 
644
                break;
 
645
 
 
646
            case '=':
 
647
                y = npop();
 
648
                x = npop();
 
649
                npush(x == y);
 
650
                break;
 
651
 
 
652
            case '<':
 
653
                y = npop();
 
654
                x = npop();
 
655
                npush(x < y);
 
656
                break;
 
657
 
 
658
            case '>':
 
659
                y = npop();
 
660
                x = npop();
 
661
                npush(x > y);
 
662
                break;
 
663
 
 
664
            case '!':
 
665
                npush(!npop());
 
666
                break;
 
667
 
 
668
            case '~':
 
669
                npush(~npop());
 
670
                break;
 
671
 
 
672
            case 'i':
 
673
                if (p_is_s[0] == 0)
 
674
                    param[0]++;
 
675
                if (p_is_s[1] == 0)
 
676
                    param[1]++;
 
677
                break;
 
678
 
 
679
            case '?':
 
680
                break;
 
681
 
 
682
            case 't':
 
683
                x = npop();
 
684
                if (!x) {
 
685
                    /* scan forward for %e or %; at level zero */
 
686
                    cp++;
 
687
                    level = 0;
 
688
                    while (*cp) {
 
689
                        if (*cp == '%') {
 
690
                            cp++;
 
691
                            if (*cp == '?')
 
692
                                level++;
 
693
                            else if (*cp == ';') {
 
694
                                if (level > 0)
 
695
                                    level--;
 
696
                                else
 
697
                                    break;
 
698
                            } else if (*cp == 'e' && level == 0)
 
699
                                break;
 
700
                        }
 
701
 
 
702
                        if (*cp)
 
703
                            cp++;
 
704
                    }
 
705
                }
 
706
                break;
 
707
 
 
708
            case 'e':
 
709
                /* scan forward for a %; at level zero */
 
710
                cp++;
 
711
                level = 0;
 
712
                while (*cp) {
 
713
                    if (*cp == '%') {
 
714
                        cp++;
 
715
                        if (*cp == '?')
 
716
                            level++;
 
717
                        else if (*cp == ';') {
 
718
                            if (level > 0)
 
719
                                level--;
 
720
                            else
 
721
                                break;
 
722
                        }
 
723
                    }
 
724
 
 
725
                    if (*cp)
 
726
                        cp++;
 
727
                }
 
728
                break;
 
729
 
 
730
            case ';':
 
731
                break;
 
732
 
 
733
            }                   /* endswitch (*cp) */
 
734
        }                       /* endelse (*cp == '%') */
 
735
 
 
736
        if (*cp == '\0')
 
737
            break;
 
738
 
 
739
        cp++;
 
740
    }                           /* endwhile (*cp) */
 
741
 
 
742
    get_space(1);
 
743
    out_buff[out_used] = '\0';
 
744
 
 
745
    return (out_buff);
 
746
}
 
747
 
 
748
char *
 
749
grub_terminfo_tparm (const char *string, ...)
 
750
{
 
751
    va_list ap;
 
752
    char *result;
 
753
 
 
754
    if (!string)
 
755
      return "";
 
756
 
 
757
    va_start (ap, string);
 
758
    result = tparam_internal (string, ap);
 
759
    va_end (ap);
 
760
    return result;
 
761
}