X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Flib_tparm.c;h=53205d1711bf06fb86c563edc4433e959ee9e995;hp=52352c9a3d30dd5222019eb6bc55e698f90610e5;hb=29b24b6ba47681c8a26007492567c3daecb3defe;hpb=c633e5103a29a38532cf1925257b91cea33fd090 diff --git a/ncurses/tinfo/lib_tparm.c b/ncurses/tinfo/lib_tparm.c index 52352c9a..53205d17 100644 --- a/ncurses/tinfo/lib_tparm.c +++ b/ncurses/tinfo/lib_tparm.c @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (c) 1998,2000 Free Software Foundation, Inc. * + * Copyright (c) 1998-2010,2011 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 * @@ -29,6 +29,7 @@ /**************************************************************************** * Author: Zeyd M. Ben-Halim 1992,1995 * * and: Eric S. Raymond * + * and: Thomas E. Dickey, 1996 on * ****************************************************************************/ /* @@ -39,10 +40,9 @@ #include #include -#include #include -MODULE_ID("$Id: lib_tparm.c,v 1.48 2000/10/14 17:45:00 Sergei.Ivanov Exp $") +MODULE_ID("$Id: lib_tparm.c,v 1.84 2011/10/22 15:48:47 tom Exp $") /* * char * @@ -104,281 +104,262 @@ MODULE_ID("$Id: lib_tparm.c,v 1.48 2000/10/14 17:45:00 Sergei.Ivanov Exp $") * resulting in x mod y, not the reverse. */ -#define STACKSIZE 20 +NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0; -typedef struct { - union { - unsigned int num; - char *str; - } data; - bool num_type; -} stack_frame; - -static stack_frame stack[STACKSIZE]; -static int stack_ptr; - -#ifdef TRACE -static const char *tname; -#endif /* TRACE */ - -static char *out_buff; -static size_t out_size; -static size_t out_used; +#define TPS(var) _nc_prescreen.tparm_state.var #if NO_LEAKS -void +NCURSES_EXPORT(void) _nc_free_tparm(void) { - if (out_buff != 0) { - FreeAndNull(out_buff); - out_size = 0; - out_used = 0; + if (TPS(out_buff) != 0) { + FreeAndNull(TPS(out_buff)); + TPS(out_size) = 0; + TPS(out_used) = 0; + FreeAndNull(TPS(fmt_buff)); + TPS(fmt_size) = 0; } } #endif -static void -really_get_space(size_t need) -{ - out_size = need * 2; - out_buff = typeRealloc(char, out_size, out_buff); - if (out_buff == 0) - _nc_err_abort("Out of memory"); -} - -static inline void +static NCURSES_INLINE void get_space(size_t need) { - need += out_used; - if (need > out_size) - really_get_space(need); + need += TPS(out_used); + if (need > TPS(out_size)) { + TPS(out_size) = need * 2; + TPS(out_buff) = typeRealloc(char, TPS(out_size), TPS(out_buff)); + if (TPS(out_buff) == 0) + _nc_err_abort(MSG_NO_MEMORY); + } } -static inline void +static NCURSES_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; + s_len = (size_t) len; get_space(s_len + 1); - (void) sprintf(out_buff + out_used, fmt, s); - out_used += strlen(out_buff + out_used); + (void) sprintf(TPS(out_buff) + TPS(out_used), fmt, s); + TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); } -static inline void +static NCURSES_INLINE void save_number(const char *fmt, int number, int len) { if (len < 30) len = 30; /* actually log10(MAX_INT)+1 */ - get_space(len + 1); + get_space((size_t) len + 1); - (void) sprintf(out_buff + out_used, fmt, number); - out_used += strlen(out_buff + out_used); + (void) sprintf(TPS(out_buff) + TPS(out_used), fmt, number); + TPS(out_used) += strlen(TPS(out_buff) + TPS(out_used)); } -static inline void +static NCURSES_INLINE void save_char(int c) { if (c == 0) c = 0200; - get_space(1); - out_buff[out_used++] = c; + get_space((size_t) 1); + TPS(out_buff)[TPS(out_used)++] = (char) c; } -static inline void +static NCURSES_INLINE void npush(int x) { - if (stack_ptr < STACKSIZE) { - stack[stack_ptr].num_type = TRUE; - stack[stack_ptr].data.num = x; - stack_ptr++; + if (TPS(stack_ptr) < STACKSIZE) { + TPS(stack)[TPS(stack_ptr)].num_type = TRUE; + TPS(stack)[TPS(stack_ptr)].data.num = x; + TPS(stack_ptr)++; + } else { + DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(TPS(tparam_base)))); + _nc_tparm_err++; } } -static inline int +static NCURSES_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; + if (TPS(stack_ptr) > 0) { + TPS(stack_ptr)--; + if (TPS(stack)[TPS(stack_ptr)].num_type) + result = TPS(stack)[TPS(stack_ptr)].data.num; + } else { + DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(TPS(tparam_base)))); + _nc_tparm_err++; } return result; } -static inline void +static NCURSES_INLINE void spush(char *x) { - if (stack_ptr < STACKSIZE) { - stack[stack_ptr].num_type = FALSE; - stack[stack_ptr].data.str = x; - stack_ptr++; + if (TPS(stack_ptr) < STACKSIZE) { + TPS(stack)[TPS(stack_ptr)].num_type = FALSE; + TPS(stack)[TPS(stack_ptr)].data.str = x; + TPS(stack_ptr)++; + } else { + DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(TPS(tparam_base)))); + _nc_tparm_err++; } } -static inline char * +static NCURSES_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; + if (TPS(stack_ptr) > 0) { + TPS(stack_ptr)--; + if (!TPS(stack)[TPS(stack_ptr)].num_type + && TPS(stack)[TPS(stack_ptr)].data.str != 0) + result = TPS(stack)[TPS(stack_ptr)].data.str; + } else { + DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(TPS(tparam_base)))); + _nc_tparm_err++; } return result; } -static inline const char * +static NCURSES_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 prec = 0; - int width = 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 { - dot = TRUE; - prec = value; - } - value = 0; - break; - case '#': - *format++ = *s++; - break; - case ' ': - *format++ = *s++; - break; - case ':': - s++; - allowminus = TRUE; - break; - case '-': - if (allowminus) { - *format++ = *s++; - } else { + if (format != 0) { + 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; - default: - if (isdigit(*s)) { - value = (value * 10) + (*s - '0'); - if (value > 10000) + 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++; - } else { - done = TRUE; + 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) { - prec = width = value = 0; - format = fmt; - *format++ = '%'; - *format++ = *s; - } - - if (dot) - width = value; - else - prec = value; + /* + * If we found an error, ignore (and remove) the flags. + */ + if (err) { + my_width = my_prec = value = 0; + format = fmt; + *format++ = '%'; + *format++ = *s; + } - *format = '\0'; - /* return maximum string length in print */ - *len = (prec > width) ? prec : width; + /* + * 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) +/* + * 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. + * + * 'number' counts coarsely the number of pop's we see in the string, and + * 'popcount' shows the highest parameter number in the string. We would like + * to simply use the latter count, but if we are reading termcap strings, there + * may be cases that we cannot see the explicit parameter numbers. + */ +NCURSES_EXPORT(int) +_nc_tparm_analyze(const char *string, char *p_is_s[NUM_PARM], int *popcount) { -#define NUM_VARS 26 - char *p_is_s[9]; - int 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; + int i; + int lastpop = -1; + int len; + int number = 0; + const char *cp = string; 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 (cp == 0) + return 0; - if ((len2 = strlen(string)) > len_fmt) { - len_fmt = len2 + len_fmt + 2; - if ((format = typeRealloc(char, len_fmt, format)) == 0) - return 0; + if ((len2 = strlen(cp)) > TPS(fmt_size)) { + TPS(fmt_size) = len2 + TPS(fmt_size) + 2; + TPS(fmt_buff) = typeRealloc(char, TPS(fmt_size), TPS(fmt_buff)); + if (TPS(fmt_buff) == 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)); + memset(p_is_s, 0, sizeof(p_is_s[0]) * NUM_PARM); + *popcount = 0; - /* - * 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. - * - * 'number' counts coarsely the number of pop's we see in the string, and - * 'popcount' shows the highest parameter number in the string. We would - * like to simply use the latter count, but if we are reading termcap - * strings, there may be cases that we cannot see the explicit parameter - * numbers. - */ - for (cp = string; (cp - string) < (int) len2;) { + while ((cp - string) < (int) len2) { if (*cp == '%') { cp++; - cp = parse_format(cp, format, &len); + cp = parse_format(cp, TPS(fmt_buff), &len); switch (*cp) { default: break; @@ -388,7 +369,8 @@ tparam_internal(const char *string, va_list ap) case 'x': /* FALLTHRU */ case 'X': /* FALLTHRU */ case 'c': /* FALLTHRU */ - number++; + if (lastpop <= 0) + number++; lastpop = -1; break; @@ -401,15 +383,19 @@ tparam_internal(const char *string, va_list ap) case 'p': cp++; - i = (*cp - '0'); - if (i >= 0 && i <= 9) { + i = (UChar(*cp) - '0'); + if (i >= 0 && i <= NUM_PARM) { lastpop = i; - if (lastpop > popcount) - popcount = lastpop; + if (lastpop > *popcount) + *popcount = lastpop; } break; case 'P': + ++number; + ++cp; + break; + case 'g': cp++; break; @@ -421,7 +407,7 @@ tparam_internal(const char *string, va_list ap) case L_BRACE: cp++; - while (*cp >= '0' && *cp <= '9') { + while (isdigit(UChar(*cp))) { cp++; } break; @@ -439,16 +425,18 @@ tparam_internal(const char *string, va_list ap) case '=': case '<': case '>': + lastpop = -1; + number += 2; + break; + case '!': case '~': lastpop = -1; - number += 2; + ++number; break; case 'i': - lastpop = -1; - if (popcount < 2) - popcount = 2; + /* will add 1 to first (usually two) parameters */ break; } } @@ -456,18 +444,62 @@ tparam_internal(const char *string, va_list ap) cp++; } - if (number > 9) - number = 9; - for (i = 0; i < max(popcount, number); i++) { + if (number > NUM_PARM) + number = NUM_PARM; + return number; +} + +static NCURSES_INLINE char * +tparam_internal(int use_TPARM_ARG, const char *string, va_list ap) +{ + char *p_is_s[NUM_PARM]; + TPARM_ARG param[NUM_PARM]; + int popcount = 0; + int number; + int num_args; + int len; + int level; + int x, y; + int i; + const char *cp = string; + size_t len2; + + if (cp == NULL) + return NULL; + + TPS(out_used) = 0; + len2 = strlen(cp); + + /* + * 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 = _nc_tparm_analyze(cp, p_is_s, &popcount); + if (TPS(fmt_buff) == 0) + return NULL; + + if (number > NUM_PARM) + number = NUM_PARM; + if (popcount > NUM_PARM) + popcount = NUM_PARM; + num_args = max(popcount, number); + + for (i = 0; i < num_args; i++) { /* * A few caps (such as plab_norm) have string-valued parms. * We'll have to assume that the caller knows the difference, since - * a char* and an int may not be the same size on the stack. + * a char* and an int may not be the same size on the stack. The + * normal prototype for this uses 9 long's, which is consistent with + * our va_arg() usage. */ if (p_is_s[i] != 0) { p_is_s[i] = va_arg(ap, char *); + param[i] = 0; + } else if (use_TPARM_ARG) { + param[i] = va_arg(ap, TPARM_ARG); } else { - param[i] = va_arg(ap, int); + param[i] = (TPARM_ARG) va_arg(ap, int); } } @@ -478,32 +510,37 @@ tparam_internal(const char *string, va_list ap) * the expansion of (for example) \E[%d;%dH work correctly in termcap * style, which means tparam() will expand termcap strings OK. */ - stack_ptr = 0; + TPS(stack_ptr) = 0; if (popcount == 0) { popcount = number; - for (i = number - 1; i >= 0; i--) - npush(param[i]); + for (i = number - 1; i >= 0; i--) { + if (p_is_s[i]) + spush(p_is_s[i]); + else + npush((int) param[i]); + } } #ifdef TRACE - if (_nc_tracing & TRACE_CALLS) { - for (i = 0; i < popcount; i++) { + if (USE_TRACEF(TRACE_CALLS)) { + for (i = 0; i < num_args; i++) { if (p_is_s[i] != 0) save_text(", %s", _nc_visbuf(p_is_s[i]), 0); else - save_number(", %d", param[i], 0); + save_number(", %d", (int) param[i], 0); } - _tracef(T_CALLED("%s(%s%s)"), tname, _nc_visbuf(string), out_buff); - out_used = 0; + _tracef(T_CALLED("%s(%s%s)"), TPS(tname), _nc_visbuf(cp), TPS(out_buff)); + TPS(out_used) = 0; + _nc_unlock_global(tracef); } #endif /* TRACE */ - while (*string) { - if (*string != '%') { - save_char(*string); + while ((cp - string) < (int) len2) { + if (*cp != '%') { + save_char(UChar(*cp)); } else { - string++; - string = parse_format(string, format, &len); - switch (*string) { + TPS(tparam_base) = cp++; + cp = parse_format(cp, TPS(fmt_buff), &len); + switch (*cp) { default: break; case '%': @@ -514,63 +551,66 @@ tparam_internal(const char *string, va_list ap) case 'o': /* FALLTHRU */ case 'x': /* FALLTHRU */ case 'X': /* FALLTHRU */ + save_number(TPS(fmt_buff), npop(), len); + break; + case 'c': /* FALLTHRU */ - save_number(format, npop(), len); + save_char(npop()); break; case 'l': - save_number("%d", strlen(spop()), 0); + save_number("%d", (int) strlen(spop()), 0); break; case 's': - save_text(format, spop(), len); + save_text(TPS(fmt_buff), spop(), len); break; case 'p': - string++; - i = (*string - '1'); - if (i >= 0 && i < 9) { + cp++; + i = (UChar(*cp) - '1'); + if (i >= 0 && i < NUM_PARM) { if (p_is_s[i]) spush(p_is_s[i]); else - npush(param[i]); + npush((int) param[i]); } break; case 'P': - string++; - if (isUPPER(*string)) { - i = (*string - 'A'); - static_vars[i] = npop(); - } else if (isLOWER(*string)) { - i = (*string - 'a'); - dynamic_var[i] = npop(); + cp++; + if (isUPPER(*cp)) { + i = (UChar(*cp) - 'A'); + TPS(static_vars)[i] = npop(); + } else if (isLOWER(*cp)) { + i = (UChar(*cp) - 'a'); + TPS(dynamic_var)[i] = npop(); } break; case 'g': - string++; - if (isUPPER(*string)) { - i = (*string - 'A'); - npush(static_vars[i]); - } else if (isLOWER(*string)) { - i = (*string - 'a'); - npush(dynamic_var[i]); + cp++; + if (isUPPER(*cp)) { + i = (UChar(*cp) - 'A'); + npush(TPS(static_vars)[i]); + } else if (isLOWER(*cp)) { + i = (UChar(*cp) - 'a'); + npush(TPS(dynamic_var)[i]); } break; case S_QUOTE: - string++; - npush(*string); - string++; + cp++; + npush(UChar(*cp)); + cp++; break; case L_BRACE: number = 0; - string++; - while (*string >= '0' && *string <= '9') { - number = number * 10 + *string - '0'; - string++; + cp++; + while (isdigit(UChar(*cp))) { + number = (number * 10) + (UChar(*cp) - '0'); + cp++; } npush(number); break; @@ -661,38 +701,38 @@ tparam_internal(const char *string, va_list ap) x = npop(); if (!x) { /* scan forward for %e or %; at level zero */ - string++; + cp++; level = 0; - while (*string) { - if (*string == '%') { - string++; - if (*string == '?') + while (*cp) { + if (*cp == '%') { + cp++; + if (*cp == '?') level++; - else if (*string == ';') { + else if (*cp == ';') { if (level > 0) level--; else break; - } else if (*string == 'e' && level == 0) + } else if (*cp == 'e' && level == 0) break; } - if (*string) - string++; + if (*cp) + cp++; } } break; case 'e': /* scan forward for a %; at level zero */ - string++; + cp++; level = 0; - while (*string) { - if (*string == '%') { - string++; - if (*string == '?') + while (*cp) { + if (*cp == '%') { + cp++; + if (*cp == '?') level++; - else if (*string == ';') { + else if (*cp == ';') { if (level > 0) level--; else @@ -700,41 +740,81 @@ tparam_internal(const char *string, va_list ap) } } - if (*string) - string++; + if (*cp) + cp++; } break; case ';': break; - } /* endswitch (*string) */ - } /* endelse (*string == '%') */ + } /* endswitch (*cp) */ + } /* endelse (*cp == '%') */ - if (*string == '\0') + if (*cp == '\0') break; - string++; - } /* endwhile (*string) */ + cp++; + } /* endwhile (*cp) */ - get_space(1); - out_buff[out_used] = '\0'; + get_space((size_t) 1); + TPS(out_buff)[TPS(out_used)] = '\0'; - T((T_RETURN("%s"), _nc_visbuf(out_buff))); - return (out_buff); + T((T_RETURN("%s"), _nc_visbuf(TPS(out_buff)))); + return (TPS(out_buff)); +} + +#if NCURSES_TPARM_VARARGS +#define tparm_varargs tparm +#else +#define tparm_proto tparm +#endif + +NCURSES_EXPORT(char *) +tparm_varargs(NCURSES_CONST char *string,...) +{ + va_list ap; + char *result; + + _nc_tparm_err = 0; + va_start(ap, string); +#ifdef TRACE + TPS(tname) = "tparm"; +#endif /* TRACE */ + result = tparam_internal(TRUE, string, ap); + va_end(ap); + return result; +} + +#if !NCURSES_TPARM_VARARGS +NCURSES_EXPORT(char *) +tparm_proto(NCURSES_CONST char *string, + TPARM_ARG a1, + TPARM_ARG a2, + TPARM_ARG a3, + TPARM_ARG a4, + TPARM_ARG a5, + TPARM_ARG a6, + TPARM_ARG a7, + TPARM_ARG a8, + TPARM_ARG a9) +{ + return tparm_varargs(string, a1, a2, a3, a4, a5, a6, a7, a8, a9); } +#endif /* NCURSES_TPARM_VARARGS */ -char * -tparm(NCURSES_CONST char *string,...) +NCURSES_EXPORT(char *) +tiparm(const char *string,...) { va_list ap; char *result; + _nc_tparm_err = 0; va_start(ap, string); #ifdef TRACE - tname = "tparm"; + TPS(tname) = "tiparm"; #endif /* TRACE */ - result = tparam_internal(string, ap); + result = tparam_internal(FALSE, string, ap); va_end(ap); return result; }