]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:05:58 +0000 (21:05 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:05:58 +0000 (21:05 +0000)
sys/share/tclib.c [new file with mode: 0644]

diff --git a/sys/share/tclib.c b/sys/share/tclib.c
new file mode 100644 (file)
index 0000000..4cd1a39
--- /dev/null
@@ -0,0 +1,482 @@
+/*     SCCS Id: @(#)tclib.c    3.3     96/02/25        */
+/* Copyright (c) Robert Patrick Rankin, 1995                     */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* termcap library implementation */
+
+#include "config.h"
+
+#ifndef TERMCAP                /* name of default termcap file */
+#define TERMCAP "/etc/termcap"
+#endif
+#ifndef TCBUFSIZ       /* size of tgetent buffer; Unix man page says 1024 */
+#define TCBUFSIZ 1024
+#endif
+#define ESC    '\033'  /* termcap's '\E' */
+#define BEL    '\007'  /* ANSI C's '\a' (we assume ASCII here...) */
+
+/* exported variables, as per man page */
+char  PC;
+char *BC, *UP;
+short ospeed;
+
+/* exported routines */
+int   FDECL(tgetent,  (char *,const char *));
+int   FDECL(tgetflag, (const char *));
+int   FDECL(tgetnum,  (const char *));
+char *FDECL(tgetstr,  (const char *,char **));
+char *FDECL(tgoto,    (const char *,int,int));
+char *FDECL(tparam,   (const char *,char *,int,int,int,int,int));
+void  FDECL(tputs,    (const char *,int,int (*)()));
+
+/* local support data */
+static char *tc_entry;
+static char bc_up_buf[24];
+#ifndef NO_DELAY_PADDING
+/* `ospeed' to baud rate conversion table, adapted from GNU termcap-1.2 */
+static short baud_rates[] = {
+       0,   50,   75,  110,  135,  150,
+# ifdef VMS
+           300,  600, 1200, 1800, 2000, 2400, 3600, 4800, 7200,
+# else         /* assume Unix */
+      200,  300,  600, 1200, 1800,       2400,       4800,
+# endif
+     9600, -192, -384,         /* negative is used as `100 * abs(entry)' */
+# ifdef VMS
+     -576, -768, -1152,
+# endif
+};
+#endif /* !NO_DELAY_PADDING */
+
+/* local support code */
+static int        FDECL(tc_store, (const char *,const char *));
+static char      *FDECL(tc_find,  (FILE *,const char *,char *,int));
+static char      *FDECL(tc_name,  (const char *,char *));
+static const char *FDECL(tc_field, (const char *,const char **));
+
+#ifndef min
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+/* retrieve the specified terminal entry and return it in `entbuf' */
+int
+tgetent(entbuf, term)
+    char *entbuf;      /* size must be at least [TCBUFSIZ] */
+    const char *term;
+{
+    int result;
+    FILE *fp;
+    char *tc = getenv("TERMCAP");
+
+    tc_entry = entbuf;
+    if (!entbuf || !term)
+       return -1;
+    /* if ${TERMCAP} is found as a file, it's not an inline termcap entry */
+    if ((fp = fopen(tc ? tc : TERMCAP, "r")) != 0)
+       tc = 0;
+    /* if ${TERMCAP} isn't a file and `term' matches ${TERM}, use ${TERMCAP} */
+    if (tc) {
+       char *tm = getenv("TERM");
+       if (tm && strcmp(tm, term) == 0)
+           return tc_store(term, tc);
+       fp = fopen(TERMCAP, "r");
+    }
+    /* otherwise, look `term' up in the file */
+    if (fp) {
+       char wrkbuf[TCBUFSIZ];
+       tc = tc_find(fp, term, wrkbuf, (int)(sizeof wrkbuf - strlen(term)));
+       result = tc_store(term, tc);
+       (void) fclose(fp);
+    } else {
+       result = -1;
+    }
+    return result;
+}
+
+/* copy the entry into the output buffer */
+static int
+tc_store(trm, ent)
+    const char *trm, *ent;
+{
+    const char *bar, *col;
+    char *s;
+    size_t n;
+    int k;
+
+    if (!ent || !*ent || !trm || !*trm || (col = index(ent, ':')) == 0)
+       return 0;
+    (void) strcpy(tc_entry, trm);
+    if (((bar = index(ent, '|')) != 0 && bar < col)
+     || ((long)(n = strlen(trm)) == (long)(col - ent)
+           && strncmp(ent, trm, n) == 0))
+       (void) strcat(tc_entry, col);
+    else if (*ent == ':')
+       (void) strcat(tc_entry, ent);
+    else
+       (void) strcat(strcat(tc_entry, ":"), ent);
+
+    /* initialize global variables */
+    k = tgetnum("pc");
+    PC = (k == -1) ? '\0' : (char)k;
+    BC = s = bc_up_buf;
+    if (!tgetstr("bc", &s))  (void)strcpy(s, "\b"),  s += 2;
+    UP = s;
+    (void)tgetstr("up", &s);
+#ifndef NO_DELAY_PADDING
+    /* caller must set `ospeed' */
+    if ((int)ospeed >= (int)SIZE(baud_rates))
+       ospeed = (short)(SIZE(baud_rates) - 1);
+    else if (ospeed < 0)
+       ospeed = 0;
+#endif /* !NO_DELAY_PADDING */
+
+    return 1;
+}
+
+/* search for an entry in the termcap file */
+static char *
+tc_find(fp, term, buffer, bufsiz)
+    FILE *fp;
+    const char *term;
+    char *buffer;
+    int bufsiz;
+{
+    int in, len, first, skip;
+    char *ip, *op, *tc_fetch, tcbuf[TCBUFSIZ];
+
+    buffer[0] = '\0';
+    do {
+       ip = tcbuf,  in = min(bufsiz,TCBUFSIZ);
+       first = 1,  skip = 0;
+       /* load entire next entry, including any continuations */
+       do {
+           if (!fgets(ip, min(in,BUFSIZ), fp))  break;
+           if (first)  skip = (*ip == '#'),  first = 0;
+           len = (int)strlen(ip);
+           if (!skip && len > 1
+            && *(ip + len - 1) == '\n' && *(ip + len - 2) == '\\')
+               len -= 2;
+           ip += len,  in -= len;
+       } while (*(ip - 1) != '\n' && in > 0);
+       if (ferror(fp) || ip == buffer || *(ip - 1) != '\n')
+           return (char *)0;
+       *--ip = '\0';           /* strip newline */
+       if (!skip)  ip = tc_name(term, tcbuf);
+    } while (skip || !ip);
+
+    /* we have the desired entry; strip cruft and look for :tc=other: */
+    tc_fetch = 0;
+    for (op = buffer; *ip; ip++) {
+       if (op == buffer || *(op - 1) != ':'
+        || (*ip != ' ' && *ip != '\t' && *ip != ':'))
+           *op++ = *ip,  bufsiz -= 1;
+       if (ip[0] == ':' && ip[1] == 't' && ip[2] == 'c' && ip[3] == '=') {
+           tc_fetch = &ip[4];
+           if ((ip = index(tc_fetch, ':')) != 0)  *ip = '\0';
+           break;
+       }
+    }
+    *op = '\0';
+
+    if (tc_fetch) {
+       rewind(fp);
+       tc_fetch = tc_find(fp, tc_fetch, tcbuf, min(bufsiz,TCBUFSIZ));
+       if (!tc_fetch)
+           return (char *)0;
+       if (op > buffer && *(op - 1) == ':' && *tc_fetch == ':')
+           ++tc_fetch;
+       strcpy(op, tc_fetch);
+    }
+    return buffer;
+}
+
+/* check whether `ent' contains `nam'; return start of field entries */
+static char *
+tc_name(nam, ent)
+    const char *nam;
+    char *ent;
+{
+    char *nxt, *lst, *p = ent;
+    size_t n = strlen(nam);
+
+    if ((lst = index(p, ':')) == 0)  lst = p + strlen(p);
+
+    while (p < lst) {
+       if ((nxt = index(p, '|')) == 0 || nxt > lst)  nxt = lst;
+       if ((long)(nxt - p) == (long)n && strncmp(p, nam, n) == 0)
+           return lst;
+       p = nxt + 1;
+    }
+    return (char *)0;
+}
+
+/* look up a numeric entry */
+int
+tgetnum(which)
+    const char *which;
+{
+    const char *q, *p = tc_field(which, &q);
+    char numbuf[32];
+    size_t n;
+
+    if (!p || p[2] != '#')
+       return -1;
+    p += 3;
+    if ((n = (size_t)(q - p)) >= sizeof numbuf)
+       return -1;
+    (void) strncpy(numbuf, p, n);
+    numbuf[n] = '\0';
+    return atoi(numbuf);
+}
+
+/* look up a boolean entry */
+int
+tgetflag(which)
+    const char *which;
+{
+    const char *p = tc_field(which, (const char **)0);
+
+    return (!p || p[2] != ':') ? 0 : 1;
+}
+
+/* look up a string entry; update `*outptr' */
+char *
+tgetstr(which, outptr)
+    const char *which;
+    char **outptr;
+{
+    int n;
+    char c, *r, *result;
+    const char *q, *p = tc_field(which, &q);
+
+    if (!p || p[2] != '=')
+       return (char *)0;
+    p += 3;
+    if ((q = index(p, ':')) == 0)  q = p + strlen(p);
+    r = result = *outptr;
+    while (p < q) {
+       switch ((*r = *p++)) {
+        case '\\':
+           switch ((c = *p++)) {
+            case 'E':  *r = ESC;   break;
+            case 'a':  *r = BEL;   break;
+            case 'b':  *r = '\b';  break;
+            case 'f':  *r = '\f';  break;
+            case 'n':  *r = '\n';  break;
+            case 'r':  *r = '\r';  break;
+            case 't':  *r = '\t';  break;
+            case '0': case '1': case '2': case '3':
+            case '4': case '5': case '6': case '7':
+                       n = c - '0';
+                       if (*p >= '0' && *p <= '7')  n = 8 * n + (*p++ - '0');
+                       if (*p >= '0' && *p <= '7')  n = 8 * n + (*p++ - '0');
+                       *r = (char)n;
+                       break;
+         /* case '^': case '\\': */
+            default:   *r = c;     break;
+           }
+           break;
+        case '^':
+           *r = (*p++ & 037);
+           if (!*r)  *r = (char)'\200';
+           break;
+        default:
+           break;
+       }
+       ++r;
+    }
+    *r++ = '\0';
+    *outptr = r;
+    return result;
+}
+
+/* look for a particular field name */
+static const char *
+tc_field(field, tc_end)
+    const char *field;
+    const char **tc_end;
+{
+    const char *end, *q, *p = tc_entry;
+
+    end = p + strlen(p);
+    while (p < end) {
+       if ((p = index(p, ':')) == 0)
+           break;
+       ++p;
+       if (p[0] == field[0] && p[1] == field[1]
+        && (p[2] == ':' || p[2] == '=' || p[2] == '#' || p[2] == '@'))
+           break;
+    }
+    if (tc_end) {
+       if (p) {
+           if ((q = index(p + 2, ':')) == 0)  q = end;
+       } else
+           q = 0;
+       *tc_end = q;
+    }
+    return p;
+}
+
+static char cmbuf[64];
+
+/* produce a string which will position the cursor at <row,col> if output */
+char *
+tgoto(cm, col, row)
+    const char *cm;
+    int col, row;
+{
+    return tparam(cm, cmbuf, (int)(sizeof cmbuf), row, col, 0, 0);
+}
+
+/* format a parameterized string, ala sprintf */
+char *
+tparam(ctl, buf, buflen, row, col, row2, col2)
+    const char *ctl;   /* parameter control string */
+    char *buf;         /* output buffer */
+    int buflen;                /* ought to have been `size_t'... */
+    int row, col, row2, col2;
+{
+    int atmp, ac, av[5];
+    char c, *r, *z, *bufend, numbuf[32];
+    const char *fmt;
+#ifndef NO_SPECIAL_CHARS_FIXUP
+    int bc = 0, up = 0;
+#endif
+
+    av[0] = row,  av[1] = col,  av[2] = row2,  av[3] = col2,  av[4] = 0;
+    ac = 0;
+    r = buf,  bufend = r + buflen - 1;
+    while (*ctl) {
+       if ((*r = *ctl++) == '%') {
+           if (ac > 4)  ac = 4;
+           fmt = 0;
+           switch ((c = *ctl++)) {
+            case '%':                  break;  /* '%' already copied */
+            case 'd':  fmt = "%d";     break;
+            case '2':  fmt = "%02d";   break;
+            case '3':  fmt = "%03d";   break;
+            case '+':  /*FALLTHRU*/
+            case '.':  *r = (char)av[ac++];
+                       if (c == '+')  *r += *ctl++;
+                       if (!*r) {
+                           *r = (char)'\200';
+                       } else {
+#ifndef NO_SPECIAL_CHARS_FIXUP
+                           /* avoid terminal driver intervention for
+                              various control characters, to prevent
+                              LF from becoming CR+LF, for instance; only
+                              makes sense if this is a cursor positioning
+                              sequence, but we have no way to check that */
+                           while (index("\004\t\n\013\f\r", *r)) {
+                               if (ac & 1) {           /* row */
+                                   if (!UP || !*UP)  break;    /* can't fix */
+                                   ++up;   /* incr row now, later move up */
+                               } else {                /* column */
+                                   if (!BC || !*BC)  break;    /* can't fix */
+                                   ++bc;   /* incr column, later backspace */
+                               }
+                               (*r)++;
+                           }
+#endif /* !NO_SPECIAL_CHARS_FIXUP */
+                       }                                               break;
+            case '>':  if (av[ac] > (*ctl++ & 0377))
+                           av[ac] += *ctl;
+                       ++ctl;                                          break;
+            case 'r':  atmp = av[0];  av[0] = av[1];  av[1] = atmp;
+                       atmp = av[2];  av[2] = av[3];  av[3] = atmp;
+                       --r;                                            break;
+            case 'i':  ++av[0];  ++av[1];  ++av[2];  ++av[3];
+                       --r;                                            break;
+            case 'n':  av[0] ^= 0140;  av[1] ^= 0140;
+                       av[2] ^= 0140;  av[3] ^= 0140;
+                       --r;                                            break;
+            case 'B':  av[0] = ((av[0] / 10) << 4) + (av[0] % 10);
+                       av[1] = ((av[1] / 10) << 4) + (av[1] % 10);
+                       av[2] = ((av[2] / 10) << 4) + (av[2] % 10);
+                       av[3] = ((av[3] / 10) << 4) + (av[3] % 10);
+                       --r;                                            break;
+            case 'D':  av[0] -= (av[0] & 15) << 1;
+                       av[1] -= (av[1] & 15) << 1;
+                       av[2] -= (av[2] & 15) << 1;
+                       av[3] -= (av[3] & 15) << 1;
+                       --r;                                            break;
+            default:   *++r = c;       break;  /* erroneous entry... */
+           }
+           if (fmt) {
+               (void) sprintf(numbuf, fmt, av[ac++]);
+               for (z = numbuf; *z && r <= bufend; z++)
+                   *r++ = *z;
+               --r;            /* will be re-incremented below */
+           }
+       }
+       if (++r > bufend)
+           return (char *)0;
+    }
+#ifndef NO_SPECIAL_CHARS_FIXUP
+    if (bc || up) {
+       while (--bc >= 0)
+           for (z = BC; *z && r <= bufend; z++)
+               *r++ = *z;
+       while (--up >= 0)
+           for (z = UP; *z && r <= bufend; z++)
+               *r++ = *z;
+       if (r > bufend)
+           return (char *)0;
+    }
+#endif /* !NO_SPECIAL_CHARS_FIXUP */
+    *r = '\0';
+    return buf;
+}
+
+/* send a string to the terminal, possibly padded with trailing NULs */
+void
+tputs( string, range, output_func )
+const char *string;    /* characters to output */
+int range;             /* number of lines affected, used for `*' delays */
+int (*output_func)();  /* actual output routine; return value ignored */
+{
+    register int c, num = 0;
+    register const char *p = string;
+
+    if (!p || !*p)
+       return;
+
+    /* pick out padding prefix, if any */
+    if (*p >= '0' && *p <= '9') {
+       do {            /* note: scale `num' by 10 to accommodate fraction */
+           num += (*p++ - '0'),  num *= 10;
+       } while (*p >= '0' && *p <= '9');
+       if (*p == '.')
+           ++p,  num += (*p >= '0' && *p <= '9') ? (*p++ - '0') : 0;
+       if (*p == '*')
+           ++p,  num *= range;
+    }
+
+    /* output the string */
+    while ((c = *p++) != '\0') {
+       if (c == '\200')  c = '\0';     /* undo tgetstr's encoding */
+       (void) (*output_func)(c);
+    }
+
+#ifndef NO_DELAY_PADDING
+    /* perform padding */
+    if (num) {
+       long pad;
+
+       /* figure out how many chars needed to produce desired elapsed time */
+       pad = (long)baud_rates[ospeed];
+       if (pad < 0)  pad *= -100L;
+       pad *= (long)num;
+       /* 100000 == 10 bits/char * (1000 millisec/sec scaled by 10) */
+       num = (int)(pad / 100000L);     /* number of characters */
+
+       c = PC;         /* assume output_func isn't allowed to change PC */
+       while (--num >= 0)
+           (void) (*output_func)(c);
+    }
+#endif /* !NO_DELAY_PADDING */
+
+    return;
+}
+
+/*tclib.c*/