]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/tinfo/lib_tparm.c
ncurses 5.0
[ncurses.git] / ncurses / tinfo / lib_tparm.c
similarity index 72%
rename from ncurses/lib_tparm.c
rename to ncurses/tinfo/lib_tparm.c
index 02125b67966eb6d7aa600f6a14987b7230904098..71b82916a356e405a4bab93694fc6de3e5824543 100644 (file)
 
 #include <curses.priv.h>
 
+#include <ctype.h>
 #include <term.h>
+#include <tic.h>
 
-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__ */