X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=ncurses%2Ftinfo%2Flib_tparm.c;fp=ncurses%2Flib_tparm.c;h=71b82916a356e405a4bab93694fc6de3e5824543;hp=02125b67966eb6d7aa600f6a14987b7230904098;hb=refs%2Ftags%2Fv5.0;hpb=661078ddbde3ce0f3b06e95642fbb9b5fef7dca1 diff --git a/ncurses/lib_tparm.c b/ncurses/tinfo/lib_tparm.c similarity index 72% rename from ncurses/lib_tparm.c rename to ncurses/tinfo/lib_tparm.c index 02125b67..71b82916 100644 --- a/ncurses/lib_tparm.c +++ b/ncurses/tinfo/lib_tparm.c @@ -39,9 +39,11 @@ #include +#include #include +#include -MODULE_ID("$Id: lib_tparm.c,v 1.22 1998/02/11 12:13:54 tom Exp $") +MODULE_ID("$Id: lib_tparm.c,v 1.39 1999/06/06 00:04:55 tom Exp $") /* * char * @@ -59,33 +61,29 @@ MODULE_ID("$Id: lib_tparm.c,v 1.22 1998/02/11 12:13:54 tom Exp $") * 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 `%' - * %d print pop() like %d in printf() - * %2d print pop() like %2d in printf() - * %02d print pop() like %02d in printf() - * %3d print pop() like %3d in printf() - * %03d print pop() like %03d in printf() - * %2x print pop() like %2x in printf() - * %02x print pop() like %02x in printf() - * %3x print pop() like %3x in printf() - * %03x print pop() like %03x in printf() * %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 + * * %p[1-9] push ith parm - * %P[a-z] set variable [a-z] to pop() - * %g[a-z] get variable [a-z] and push it + * %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()) @@ -93,21 +91,18 @@ MODULE_ID("$Id: lib_tparm.c,v 1.22 1998/02/11 12:13:54 tom Exp $") * %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 L_BRACE '{' -#define R_BRACE '}' - #define STACKSIZE 20 typedef union { @@ -136,44 +131,58 @@ void _nc_free_tparm(void) } #endif -static void save_text(char *s) +static void really_get_space(size_t need) { - size_t want = strlen(s); - size_t need = want + out_used + 1; - - if (need > out_size) { - out_size = need * 2; - if (out_buff == 0) - out_buff = malloc(out_size); - else - out_buff = realloc(out_buff, out_size); - } - (void)strcpy(out_buff + out_used, s); - out_used += want; + 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 get_space(size_t need) +{ + need += out_used; + if (need > out_size) + really_get_space(need); +} + +static inline void save_text(const char *fmt, 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 void save_number(const char *fmt, int number) +static inline void save_number(const char *fmt, int number, int len) { - char temp[80]; - (void)sprintf(temp, fmt, number); - save_text(temp); + if (len < 30) + len = 30; /* actually log10(MAX_INT)+1 */ + + get_space(len + 1); + + (void)sprintf(out_buff+out_used, fmt, number); + out_used += strlen(out_buff+out_used); } static inline void save_char(int c) { - static char text[2]; if (c == 0) c = 0200; - text[0] = c; - save_text(text); + get_space(1); + out_buff[out_used++] = c; } static inline void npush(int x) { if (stack_ptr < STACKSIZE) { stack[stack_ptr].num = x; - stack_ptr++; - } + stack_ptr++; + } } static inline int npop(void) @@ -183,22 +192,88 @@ static inline int npop(void) static inline char *spop(void) { - return (stack_ptr > 0 ? stack[--stack_ptr].str : 0); + static char dummy[] = ""; /* avoid const-cast */ + return (stack_ptr > 0 ? stack[--stack_ptr].str : dummy); +} + +static inline const char *parse_format(const char *s, char *format, int *len) +{ + bool done = FALSE; + bool allowminus = FALSE; + bool dot = FALSE; + int prec = 0; + int width = 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++; + dot = TRUE; + 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(*s)) { + if (dot) + prec = (prec * 10) + (*s - '0'); + else + width = (width * 10) + (*s - '0'); + *format++ = *s++; + } else { + done = TRUE; + } + } + } + *format = '\0'; + /* return maximum string length in print */ + *len = (prec > width) ? prec : width; + 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 int param[9]; int popcount; -int variable[NUM_VARS]; -char len; int number; +int len; int level; int x, y; int i; -int varused = -1; register const char *cp; +static size_t len_fmt; +static char *format; +static int dynamic_var[NUM_VARS]; +static int static_vars[NUM_VARS]; out_used = 0; if (string == NULL) @@ -235,6 +310,11 @@ register const char *cp; } } } + if ((size_t)(cp - string) > len_fmt) { + len_fmt = (cp - string) + len_fmt + 2; + if ((format = typeRealloc(char, len_fmt, format)) == 0) + return 0; + } if (number > 9) number = 9; for (i = 0; i < max(popcount, number); i++) { @@ -247,7 +327,7 @@ register const char *cp; /* * This is a termcap compatibility hack. If there are no explicit pop - * operations in the string, load the stack in such a way that + * operations in the string, load the stack in such a way that * successive pops will grab successive parameters. That will make * the expansion of (for example) \E[%d;%dH work correctly in termcap * style, which means tparam() will expand termcap strings OK. @@ -262,17 +342,18 @@ register const char *cp; #ifdef TRACE if (_nc_tracing & TRACE_CALLS) { for (i = 0; i < popcount; i++) - save_number(", %d", param[i]); + save_number(", %d", param[i], 0); _tracef(T_CALLED("%s(%s%s)"), tname, _nc_visbuf(string), out_buff); out_used = 0; - } + } #endif /* TRACE */ while (*string) { - if (*string != '%') + if (*string != '%') { save_char(*string); - else { + } else { string++; + string = parse_format(string, format, &len); switch (*string) { default: break; @@ -280,61 +361,20 @@ register const char *cp; save_char('%'); break; - case 'd': - save_number("%d", npop()); - break; - - case 'x': - save_number("%x", npop()); - break; - - case '0': - string++; - len = *string; - if (len == '2' || len == '3') - { - ++string; - if (*string == 'd') { - if (len == '2') - save_number("%02d", npop()); - else - save_number("%03d", npop()); - } - else if (*string == 'x') { - if (len == '2') - save_number("%02x", npop()); - else - save_number("%03x", npop()); - } - } - break; - - case '2': - string++; - if (*string == 'd') { - save_number("%2d", npop()); - } - else if (*string == 'x') { - save_number("%2x", npop()); - } - break; - - case '3': - string++; - if (*string == 'd') { - save_number("%3d", npop()); - } - else if (*string == 'x') { - save_number("%3x", npop()); - } + case 'd': /* FALLTHRU */ + case 'o': /* FALLTHRU */ + case 'x': /* FALLTHRU */ + case 'X': /* FALLTHRU */ + case 'c': + save_number(format, npop(), len); break; - case 'c': - save_char(npop()); + case 'l': + save_number("%d", strlen(spop()), 0); break; case 's': - save_text(spop()); + save_text(format, spop(), len); break; case 'p': @@ -345,25 +385,27 @@ register const char *cp; case 'P': string++; - i = (*string - 'a'); - if (i >= 0 && i < NUM_VARS) { - while (varused < i) - variable[++varused] = 0; - variable[i] = npop(); + if (isUPPER(*string)) { + i = (*string - 'A'); + static_vars[i] = npop(); + } else if (isLOWER(*string)) { + i = (*string - 'a'); + dynamic_var[i] = npop(); } break; case 'g': string++; - i = (*string - 'a'); - if (i >= 0 && i < NUM_VARS) { - while (varused < i) - variable[++varused] = 0; - npush(variable[i]); + if (isUPPER(*string)) { + i = (*string - 'A'); + npush(static_vars[i]); + } else if (isLOWER(*string)) { + i = (*string - 'a'); + npush(dynamic_var[i]); } break; - case '\'': + case S_QUOTE: string++; npush(*string); string++; @@ -396,13 +438,13 @@ register const char *cp; case '/': y = npop(); x = npop(); - npush(x / y); + npush(y ? (x / y) : 0); break; case 'm': y = npop(); x = npop(); - npush(x % y); + npush(y ? (x % y) : 0); break; case 'A': @@ -520,16 +562,15 @@ register const char *cp; string++; } /* endwhile (*string) */ - if (out_buff == 0) - out_buff = calloc(1,1); - if (out_used == 0) - *out_buff = '\0'; + if (out_buff == 0 && (out_buff = typeCalloc(char,1)) == NULL) + return(NULL); + out_buff[out_used] = '\0'; T((T_RETURN("%s"), _nc_visbuf(out_buff))); return(out_buff); } -char *tparm(const char *string, ...) +char *tparm(NCURSES_CONST char *string, ...) { va_list ap; char *result; @@ -542,21 +583,3 @@ char *result; va_end(ap); return result; } - -#ifdef __UNUSED__ /* we never documented this, and it confuses Emacs */ -char *tparam(const char *string, char *buffer, int bufsiz, ...) -{ -va_list ap; -char *result = 0; - - va_start(ap, bufsiz); -#ifdef TRACE - tname = "tparam"; -#endif /* TRACE */ - if (tparam_internal(string, ap) != 0 - && (int)out_used < bufsiz) - result = strcpy(buffer, out_buff); - va_end(ap); - return result; -} -#endif /* __UNUSED__ */