lib_tpar.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 770 行 · 第 1/2 页
C
770 行
/****************************************************************************
* Copyright (c) 1998-2001,2002 Free Software Foundation, Inc. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, distribute with modifications, sublicense, and/or sell *
* copies of the Software, and to permit persons to whom the Software is *
* furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included *
* in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
* *
* Except as contained in this notice, the name(s) of the above copyright *
* holders shall not be used in advertising or otherwise to promote the *
* sale, use or other dealings in this Software without prior written *
* authorization. *
****************************************************************************/
/****************************************************************************
* Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 *
* and: Eric S. Raymond <esr@snark.thyrsus.com> *
* and: Thomas E. Dickey, 1996 on *
****************************************************************************/
/*
* tparm.c
*
*/
#include <curses_p.h>
#include <ctype.h>
#include <term.h>
#include <tic.h>
MODULE_ID("$Id: lib_tparm.c,v 1.62 2002/10/05 19:33:24 Frank.Henigman Exp $")
/*
* char *
* tparm(string, ...)
*
* Substitute the given parameters into the given string by the following
* rules (taken from terminfo(5)):
*
* Cursor addressing and other strings requiring parame-
* ters in the terminal are described by a parameterized string
* capability, with like escapes %x in it. For example, to
* address the cursor, the cup capability is given, using two
* parameters: the row and column to address to. (Rows and
* columns are numbered from zero and refer to the physical
* screen visible to the user, not to any unseen memory.) If
* the terminal has memory relative cursor addressing, that can
* be indicated by
*
* The parameter mechanism uses a stack and special %
* codes to manipulate it. Typically a sequence will push one
* of the parameters onto the stack and then print it in some
* format. Often more complex operations are necessary.
*
* The % encodings have the following meanings:
*
* %% outputs `%'
* %c print pop() like %c in printf()
* %s print pop() like %s in printf()
* %[[:]flags][width[.precision]][doxXs]
* as in printf, flags are [-+#] and space
* The ':' is used to avoid making %+ or %-
* patterns (see below).
*
* %p[1-9] push ith parm
* %P[a-z] set dynamic variable [a-z] to pop()
* %g[a-z] get dynamic variable [a-z] and push it
* %P[A-Z] set static variable [A-Z] to pop()
* %g[A-Z] get static variable [A-Z] and push it
* %l push strlen(pop)
* %'c' push char constant c
* %{nn} push integer constant nn
*
* %+ %- %* %/ %m
* arithmetic (%m is mod): push(pop() op pop())
* %& %| %^ bit operations: push(pop() op pop())
* %= %> %< logical operations: push(pop() op pop())
* %A %O logical and & or operations for conditionals
* %! %~ unary operations push(op pop())
* %i add 1 to first two parms (for ANSI terminals)
*
* %? expr %t thenpart %e elsepart %;
* if-then-else, %e elsepart is optional.
* else-if's are possible ala Algol 68:
* %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
*
* For those of the above operators which are binary and not commutative,
* the stack works in the usual way, with
* %gx %gy %m
* resulting in x mod y, not the reverse.
*/
#define STACKSIZE 20
typedef struct {
union {
int num;
char *str;
} data;
bool num_type;
} stack_frame;
NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0;
static stack_frame stack[STACKSIZE];
static int stack_ptr;
static const char *tparam_base = "";
#ifdef TRACE
static const char *tname;
#endif /* TRACE */
static char *out_buff;
static size_t out_size;
static size_t out_used;
#if NO_LEAKS
NCURSES_EXPORT(void)
_nc_free_tparm(void)
{
if (out_buff != 0) {
FreeAndNull(out_buff);
out_size = 0;
out_used = 0;
}
}
#endif
static inline void
get_space(size_t need)
{
need += out_used;
if (need > out_size) {
out_size = need * 2;
out_buff = typeRealloc(char, out_size, out_buff);
if (out_buff == 0)
_nc_err_abort(MSG_NO_MEMORY);
}
}
static inline void
save_text(const char *fmt, const char *s, int len)
{
size_t s_len = strlen(s);
if (len > (int) s_len)
s_len = len;
get_space(s_len + 1);
(void) sprintf(out_buff + out_used, fmt, s);
out_used += strlen(out_buff + out_used);
}
static inline void
save_number(const char *fmt, int number, int len)
{
if (len < 30)
len = 30; /* actually log10(MAX_INT)+1 */
get_space((unsigned) len + 1);
(void) sprintf(out_buff + out_used, fmt, number);
out_used += strlen(out_buff + out_used);
}
static inline void
save_char(int c)
{
if (c == 0)
c = 0200;
get_space(1);
out_buff[out_used++] = c;
}
static inline void
npush(int x)
{
if (stack_ptr < STACKSIZE) {
stack[stack_ptr].num_type = TRUE;
stack[stack_ptr].data.num = x;
stack_ptr++;
} else {
DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(tparam_base)));
_nc_tparm_err++;
}
}
static inline int
npop(void)
{
int result = 0;
if (stack_ptr > 0) {
stack_ptr--;
if (stack[stack_ptr].num_type)
result = stack[stack_ptr].data.num;
} else {
DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(tparam_base)));
_nc_tparm_err++;
}
return result;
}
static inline void
spush(char *x)
{
if (stack_ptr < STACKSIZE) {
stack[stack_ptr].num_type = FALSE;
stack[stack_ptr].data.str = x;
stack_ptr++;
} else {
DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(tparam_base)));
_nc_tparm_err++;
}
}
static inline char *
spop(void)
{
static char dummy[] = ""; /* avoid const-cast */
char *result = dummy;
if (stack_ptr > 0) {
stack_ptr--;
if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
result = stack[stack_ptr].data.str;
} else {
DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(tparam_base)));
_nc_tparm_err++;
}
return result;
}
static inline const char *
parse_format(const char *s, char *format, int *len)
{
bool done = FALSE;
bool allowminus = FALSE;
bool dot = FALSE;
bool err = FALSE;
char *fmt = format;
int my_width = 0;
int my_prec = 0;
int value = 0;
*len = 0;
*format++ = '%';
while (*s != '\0' && !done) {
switch (*s) {
case 'c': /* FALLTHRU */
case 'd': /* FALLTHRU */
case 'o': /* FALLTHRU */
case 'x': /* FALLTHRU */
case 'X': /* FALLTHRU */
case 's':
*format++ = *s;
done = TRUE;
break;
case '.':
*format++ = *s++;
if (dot) {
err = TRUE;
} else { /* value before '.' is the width */
dot = TRUE;
my_width = value;
}
value = 0;
break;
case '#':
*format++ = *s++;
break;
case ' ':
*format++ = *s++;
break;
case ':':
s++;
allowminus = TRUE;
break;
case '-':
if (allowminus) {
*format++ = *s++;
} else {
done = TRUE;
}
break;
default:
if (isdigit(UChar(*s))) {
value = (value * 10) + (*s - '0');
if (value > 10000)
err = TRUE;
*format++ = *s++;
} else {
done = TRUE;
}
}
}
/*
* If we found an error, ignore (and remove) the flags.
*/
if (err) {
my_width = my_prec = value = 0;
format = fmt;
*format++ = '%';
*format++ = *s;
}
/*
* Any value after '.' is the precision. If we did not see '.', then
* the value is the width.
*/
if (dot)
my_prec = value;
else
my_width = value;
*format = '\0';
/* return maximum string length in print */
*len = (my_width > my_prec) ? my_width : my_prec;
return s;
}
#define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
#define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
static inline char *
tparam_internal(const char *string, va_list ap)
{
#define NUM_VARS 26
char *p_is_s[9];
long param[9];
int lastpop;
int popcount;
int number;
int len;
int level;
int x, y;
int i;
size_t len2;
register const char *cp;
static size_t len_fmt;
static char dummy[] = "";
static char *format;
static int dynamic_var[NUM_VARS];
static int static_vars[NUM_VARS];
out_used = 0;
if (string == NULL)
return NULL;
if ((len2 = strlen(string)) > len_fmt) {
len_fmt = len2 + len_fmt + 2;
if ((format = typeRealloc(char, len_fmt, format)) == 0)
return 0;
}
/*
* Find the highest parameter-number referred to in the format string.
* Use this value to limit the number of arguments copied from the
* variable-length argument list.
*/
number = 0;
lastpop = -1;
popcount = 0;
memset(p_is_s, 0, sizeof(p_is_s));
/*
* Analyze the string to see how many parameters we need from the varargs
* list, and what their types are. We will only accept string parameters
* if they appear as a %l or %s format following an explicit parameter
* reference (e.g., %p2%s). All other parameters are numbers.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?