]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - tack/edit.c
ncurses 5.0
[ncurses.git] / tack / edit.c
diff --git a/tack/edit.c b/tack/edit.c
new file mode 100644 (file)
index 0000000..5685d92
--- /dev/null
@@ -0,0 +1,977 @@
+/*
+** Copyright (C) 1997 Free Software Foundation, Inc.
+** 
+** This file is part of TACK.
+** 
+** TACK is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2, or (at your option)
+** any later version.
+** 
+** TACK is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+** 
+** You should have received a copy of the GNU General Public License
+** along with TACK; see the file COPYING.  If not, write to
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA 02111-1307, USA.
+*/
+
+#include <tack.h>
+#include <time.h>
+#include <tic.h>
+
+MODULE_ID("$Id: edit.c,v 1.3 1999/06/16 00:43:43 tom Exp $")
+
+/*
+ * Terminfo edit features
+ */
+static void show_info(struct test_list *, int *, int *);
+static void show_value(struct test_list *, int *, int *);
+static void show_untested(struct test_list *, int *, int *);
+static void show_changed(struct test_list *, int *, int *);
+
+#define SHOW_VALUE     1
+#define SHOW_EDIT      2
+#define SHOW_DELETE    3
+
+struct test_list edit_test_list[] = {
+       {MENU_CLEAR, 0, 0, 0, "i) display current terminfo", show_info, 0},
+       {0, 0, 0, 0, "w) write the current terminfo to a file", save_info, 0},
+       {SHOW_VALUE, 3, 0, 0, "v) show value of a selected cap", show_value, 0},
+       {SHOW_EDIT, 4, 0, 0, "e) edit value of a selected cap", show_value, 0},
+       {SHOW_DELETE, 3, 0, 0, "d) delete string", show_value, 0},
+       {0, 3, 0, 0, "m) show caps that have been modified", show_changed, 0},
+       {MENU_CLEAR + FLAG_CAN_TEST, 0, 0, 0, "c) show caps that can be tested", show_report, 0},
+       {MENU_CLEAR + FLAG_TESTED, 0, 0, 0, "t) show caps that have been tested", show_report, 0},
+       {MENU_CLEAR + FLAG_FUNCTION_KEY, 0, 0, 0, "f) show a list of function keys", show_report, 0},
+       {MENU_CLEAR, 0, 0, 0, "u) show caps defined that can not be tested", show_untested, 0},
+       {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+static char change_pad_text[MAX_CHANGES][80];
+struct test_list change_pad_list[MAX_CHANGES] = {
+       {MENU_LAST, 0, 0, 0, 0, 0, 0}
+};
+
+static void build_change_menu(struct test_menu *);
+static void change_one_entry(struct test_list *, int *, int *);
+
+struct test_menu change_pad_menu = {
+       0, 'q', 0,
+       "Select cap name", "change", 0,
+       build_change_menu, change_pad_list, 0, 0, 0
+};
+
+extern struct test_results *pads[STRCOUNT];    /* save pad results here */
+
+static TERMTYPE        original_term;          /* terminal type description */
+
+static char flag_boolean[BOOLCOUNT];   /* flags for booleans */
+static char flag_numerics[NUMCOUNT];   /* flags for numerics */
+static char flag_strings[STRCOUNT];    /* flags for strings */
+static int xon_index;                  /* Subscript for (xon) */
+int xon_shadow;
+
+static int start_display;              /* the display has just started */
+static int display_lines;              /* number of lines displayed */
+
+/*
+**     send_info_string(str)
+**
+**     Return the terminfo string prefixed by the correct seperator
+*/
+static void
+send_info_string(
+       const char *str,
+       int *ch)
+{
+       int len;
+
+       if (display_lines == -1) {
+               return;
+       }
+       len = strlen(str);
+       if (len + char_count + 3 >= columns) {
+               if (start_display == 0) {
+                       put_str(",");
+               }
+               put_crlf();
+               if (++display_lines > lines) {
+                       ptext("-- more -- ");
+                       *ch = wait_here();
+                       if (*ch == 'q') {
+                               display_lines = -1;
+                               return;
+                       }
+                       display_lines = 0;
+               }
+               if (len >= columns) {
+                       /* if the terminal does not (am) then this loses */
+                       if (columns) {
+                               display_lines += ((strlen(str) + 3) / columns) + 1;
+                       }
+                       put_str("   ");
+                       put_str(str);
+                       start_display = 0;
+                       return;
+               }
+               ptext("   ");
+       } else
+       if (start_display == 0) {
+               ptext(", ");
+       } else {
+               ptext("   ");
+       }
+       ptext(str);
+       start_display = 0;
+}
+
+/*
+**     show_info(test_list, status, ch)
+**
+**     Display the current terminfo
+*/
+static void
+show_info(
+       struct test_list *t GCC_UNUSED,
+       int *state GCC_UNUSED,
+       int *ch)
+{
+       int i;
+       char buf[1024];
+
+       display_lines = 1;
+       start_display = 1;
+       for (i = 0; i < BOOLCOUNT; i++) {
+               if ((i == xon_index) ? xon_shadow : CUR Booleans[i]) {
+                       send_info_string(boolnames[i], ch);
+               }
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               if (CUR Numbers[i] >= 0) {
+                       sprintf(buf, "%s#%d", numnames[i], CUR Numbers[i]);
+                       send_info_string(buf, ch);
+               }
+       }
+       for (i = 0; i < STRCOUNT; i++) {
+               if (CUR Strings[i]) {
+                       sprintf(buf, "%s=%s", strnames[i],
+                               print_expand(CUR Strings[i]));
+                       send_info_string(buf, ch);
+               }
+       }
+       put_newlines(2);
+       *ch = REQUEST_PROMPT;
+}
+
+/*
+**     save_info_string(str, fp)
+**
+**     Write the terminfo string prefixed by the correct seperator
+*/
+static void
+save_info_string(
+       const char *str,
+       FILE *fp)
+{
+       int len;
+
+       len = strlen(str);
+       if (len + display_lines >= 77) {
+               if (display_lines > 0) {
+                       (void) fprintf(fp, "\n\t");
+               }
+               display_lines = 8;
+       } else
+       if (display_lines > 0) {
+               (void) fprintf(fp, " ");
+               display_lines++;
+       } else {
+               (void) fprintf(fp, "\t");
+               display_lines = 8;
+       }
+       (void) fprintf(fp, "%s,", str);
+       display_lines += len + 1;
+}
+
+/*
+**     save_info(test_list, status, ch)
+**
+**     Write the current terminfo to a file
+*/
+void
+save_info(
+       struct test_list *t,
+       int *state,
+       int *ch)
+{
+       int i;
+       FILE *fp;
+       time_t now;
+       char buf[1024];
+
+       if ((fp = fopen(tty_basename, "w")) == (FILE *) NULL) {
+               (void) sprintf(temp, "can't open: %s", tty_basename);
+               ptextln(temp);
+               generic_done_message(t, state, ch);
+               return;
+       }
+       time(&now);
+       /* Note: ctime() returns a newline at the end of the string */
+       (void) fprintf(fp, "# Terminfo created by TACK for TERM=%s on %s",
+               tty_basename, ctime(&now));
+       (void) fprintf(fp, "%s|%s,\n", tty_basename, longname());
+
+       display_lines = 0;
+       for (i = 0; i < BOOLCOUNT; i++) {
+               if (i == xon_index ? xon_shadow : CUR Booleans[i]) {
+                       save_info_string(boolnames[i], fp);
+               }
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               if (CUR Numbers[i] >= 0) {
+                       sprintf(buf, "%s#%d", numnames[i], CUR Numbers[i]);
+                       save_info_string(buf, fp);
+               }
+       }
+       for (i = 0; i < STRCOUNT; i++) {
+               if (CUR Strings[i]) {
+                       sprintf(buf, "%s=%s", strnames[i],
+                               _nc_tic_expand(CUR Strings[i], TRUE, TRUE));
+                       save_info_string(buf, fp);
+               }
+       }
+       (void) fprintf(fp, "\n");
+       (void) fclose(fp);
+       sprintf(temp, "Terminfo saved as file: %s", tty_basename);
+       ptextln(temp);
+}
+
+/*
+**     show_value(test_list, status, ch)
+**
+**     Display the value of a selected cap
+*/
+static void
+show_value(
+       struct test_list *t,
+       int *state GCC_UNUSED,
+       int *ch)
+{
+       struct name_table_entry const *nt;
+       char *s;
+       int n, op, b;
+       char buf[1024];
+       char tmp[1024];
+
+       ptext("enter name: ");
+       read_string(buf, 80);
+       if (buf[0] == '\0' || buf[1] == '\0') {
+               *ch = buf[0];
+               return;
+       }
+       if (line_count + 2 >= lines) {
+               put_clear();
+       }
+       op = t->flags & 255;
+       if ((nt = _nc_find_entry(buf, _nc_info_hash_table))) {
+               switch (nt->nte_type) {
+               case BOOLEAN:
+                       if (op == SHOW_DELETE) {
+                               if (nt->nte_index == xon_index) {
+                                       xon_shadow = 0;
+                               } else {
+                                       CUR Booleans[nt->nte_index] = 0;
+                               }
+                               return;
+                       }
+                       b = nt->nte_index == xon_index ? xon_shadow :
+                               CUR Booleans[nt->nte_index];
+                       sprintf(temp, "boolean  %s %s", buf,
+                               b ? "True" : "False");
+                       break;
+               case STRING:
+                       if (op == SHOW_DELETE) {
+                               CUR Strings[nt->nte_index] = (char *) 0;
+                               return;
+                       }
+                       if (CUR Strings[nt->nte_index]) {
+                               sprintf(temp, "string  %s %s", buf,
+                                       expand(CUR Strings[nt->nte_index]));
+                       } else {
+                               sprintf(temp, "undefined string %s", buf);
+                       }
+                       break;
+               case NUMBER:
+                       if (op == SHOW_DELETE) {
+                               CUR Numbers[nt->nte_index] = -1;
+                               return;
+                       }
+                       sprintf(temp, "numeric  %s %d", buf,
+                               CUR Numbers[nt->nte_index]);
+                       break;
+               default:
+                       sprintf(temp, "unknown");
+                       break;
+               }
+               ptextln(temp);
+       } else {
+               sprintf(temp, "Cap not found: %s", buf);
+               ptextln(temp);
+               return;
+       }
+       if (op != SHOW_EDIT) {
+               return;
+       }
+       if (nt->nte_type == BOOLEAN) {
+               ptextln("Value flipped");
+               if (nt->nte_index == xon_index) {
+                       xon_shadow = !xon_shadow;
+               } else {
+                       CUR Booleans[nt->nte_index] = !CUR Booleans[nt->nte_index];
+               }
+               return;
+       }
+       ptextln("Enter new value");
+       read_string(buf, sizeof(buf));
+
+       switch (nt->nte_type) {
+       case STRING:
+               _nc_reset_input((FILE *) 0, buf);
+               _nc_trans_string(tmp);
+               s = (char *)malloc(strlen(tmp) + 1);
+               strcpy(s, tmp);
+               CUR Strings[nt->nte_index] = s;
+               sprintf(temp, "new string value  %s", nt->nte_name);
+               ptextln(temp);
+               ptextln(expand(CUR Strings[nt->nte_index]));
+               break;
+       case NUMBER:
+               if (sscanf(buf, "%d", &n) == 1) {
+                       CUR Numbers[nt->nte_index] = n;
+                       sprintf(temp, "new numeric value  %s %d",
+                               nt->nte_name, n);
+                       ptextln(temp);
+               } else {
+                       sprintf(temp, "Illegal number: %s", buf);
+                       ptextln(temp);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+**     get_string_cap_byname(name, long_name)
+**
+**     Given a cap name, find the value
+**     Errors are quietly ignored.
+*/
+char *
+get_string_cap_byname(
+       const char *name,
+       const char **long_name)
+{
+       struct name_table_entry const *nt;
+
+       if ((nt = _nc_find_entry(name, _nc_info_hash_table))) {
+               if (nt->nte_type == STRING) {
+                       *long_name = strfnames[nt->nte_index];
+                       return (CUR Strings[nt->nte_index]);
+               }
+       }
+       *long_name = "??";
+       return (char *) 0;
+}
+
+/*
+**     get_string_cap_byvalue(value)
+**
+**     Given a capability string, find its position in the data base.
+**     Return the index or -1 if not found.
+*/
+int
+get_string_cap_byvalue(
+       const char *value)
+{
+       int i;
+
+       if (value) {
+               for (i = 0; i < STRCOUNT; i++) {
+                       if (CUR Strings[i] == value) {
+                               return i;
+                       }
+               }
+               /* search for translated strings */
+               for (i = 0; i < TM_last; i++) {
+                       if (TM_string[i].value == value) {
+                               return TM_string[i].index;
+                       }
+               }
+       }
+       return -1;
+}
+
+/*
+**     show_changed(test_list, status, ch)
+**
+**     Display a list of caps that have been changed.
+*/
+static void
+show_changed(
+       struct test_list *t GCC_UNUSED,
+       int *state GCC_UNUSED,
+       int *ch)
+{
+       int i, header = 1, v;
+       const char *a;
+       const char *b;
+       static char title[] = "                     old value   cap  new value";
+       char abuf[1024];
+
+       for (i = 0; i < BOOLCOUNT; i++) {
+               v = (i == xon_index) ? xon_shadow : CUR Booleans[i];
+               if (original_term.Booleans[i] != v) {
+                       if (header) {
+                               ptextln(title);
+                               header = 0;
+                       }
+                       sprintf(temp, "%30d %6s %d",
+                               original_term.Booleans[i], boolnames[i], v);
+                       ptextln(temp);
+               }
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               if (original_term.Numbers[i] != CUR Numbers[i]) {
+                       if (header) {
+                               ptextln(title);
+                               header = 0;
+                       }
+                       sprintf(temp, "%30d %6s %d",
+                               original_term.Numbers[i], numnames[i],
+                               CUR Numbers[i]);
+                       ptextln(temp);
+               }
+       }
+       for (i = 0; i < STRCOUNT; i++) {
+               a = original_term.Strings[i] ? original_term.Strings[i] : "";
+               b = CUR Strings[i] ?  CUR Strings[i] : "";
+               if (strcmp(a, b)) {
+                       if (header) {
+                               ptextln(title);
+                               header = 0;
+                       }
+                       strcpy(abuf, _nc_tic_expand(a, TRUE, TRUE));
+                       sprintf(temp, "%30s %6s %s", abuf, strnames[i],
+                               _nc_tic_expand(b, TRUE, TRUE));
+                       putln(temp);
+               }
+       }
+       if (header) {
+               ptextln("No changes");
+       }
+       put_crlf();
+       *ch = REQUEST_PROMPT;
+}
+
+/*
+**     user_modified()
+**
+**     Return TRUE if the user has modified the terminfo
+*/
+int
+user_modified(void)
+{
+       const char *a, *b;
+       int i, v;
+
+       for (i = 0; i < BOOLCOUNT; i++) {
+               v = (i == xon_index) ? xon_shadow : CUR Booleans[i];
+               if (original_term.Booleans[i] != v) {
+                       return TRUE;
+               }
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               if (original_term.Numbers[i] != CUR Numbers[i]) {
+                       return TRUE;
+               }
+       }
+       for (i = 0; i < STRCOUNT; i++) {
+               a = original_term.Strings[i] ? original_term.Strings[i] : "";
+               b = CUR Strings[i] ?  CUR Strings[i] : "";
+               if (strcmp(a, b)) {
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+/*****************************************************************************
+ *
+ * Maintain the list of capabilities that can be tested
+ *
+ *****************************************************************************/
+
+/*
+**     mark_cap(name, flag)
+**
+**     Mark the cap data base with the flag provided.
+*/
+static void
+mark_cap(
+       char *name,
+       int flag)
+{
+       struct name_table_entry const *nt;
+
+       if ((nt = _nc_find_entry(name, _nc_info_hash_table))) {
+               switch (nt->nte_type) {
+               case BOOLEAN:
+                       flag_boolean[nt->nte_index] |= flag;
+                       break;
+               case STRING:
+                       flag_strings[nt->nte_index] |= flag;
+                       break;
+               case NUMBER:
+                       flag_numerics[nt->nte_index] |= flag;
+                       break;
+               default:
+                       sprintf(temp, "unknown cap type (%s)", name);
+                       ptextln(temp);
+                       break;
+               }
+       } else {
+               sprintf(temp, "Cap not found: %s", name);
+               ptextln(temp);
+               (void) wait_here();
+       }
+}
+
+/*
+**     can_test(name-list, flags)
+**
+**     Scan the name list and get the names.
+**     Enter each name into the can-test data base.
+**     <space> ( and ) may be used as seperators.
+*/
+void
+can_test(
+       const char *s,
+       int flags)
+{
+       int ch, i, j;
+       char name[32];
+
+       if (s) {
+               for (i = j = 0; (name[j] = ch = *s); s++) {
+                       if (ch == ' ' || ch == ')' || ch == '(') {
+                               if (j) {
+                                       name[j] = '\0';
+                                       mark_cap(name, flags);
+                               }
+                               j = 0;
+                       } else {
+                               j++;
+                       }
+               }
+               if (j) {
+                       mark_cap(name, flags);
+               }
+       }
+}
+
+/*
+**     cap_index(name-list, index-list)
+**
+**     Scan the name list and return a list of indexes.
+**     <space> ( and ) may be used as seperators.
+**     This list is terminated with -1.
+*/
+void
+cap_index(
+       const char *s,
+       int *inx)
+{
+       struct name_table_entry const *nt;
+       int ch, i, j;
+       char name[32];
+
+       if (s) {
+               for (i = j = 0; ; s++) {
+                       name[j] = ch = *s;
+                       if (ch == ' ' || ch == ')' || ch == '(' || ch == 0) {
+                               if (j) {
+                                       name[j] = '\0';
+                                       if ((nt = _nc_find_entry(name,
+                                               _nc_info_hash_table)) &&
+                                               (nt->nte_type == STRING)) {
+                                               *inx++ = nt->nte_index;
+                                       }
+                               }
+                               if (ch == 0) {
+                                       break;
+                               }
+                               j = 0;
+                       } else {
+                               j++;
+                       }
+               }
+       }
+       *inx = -1;
+}
+
+/*
+**     cap_match(name-list, cap)
+**
+**     Scan the name list and see if the cap is in the list.
+**     Return TRUE if we find an exact match.
+**     <space> ( and ) may be used as seperators.
+*/
+int
+cap_match(
+       const char *names,
+       const char *cap)
+{
+       char *s;
+       int c, l, t;
+
+       if (names) {
+               l = strlen(cap);
+               while ((s = strstr(names, cap))) {
+                       c = (names == s) ? 0 : *(s - 1);
+                       t = s[l];
+                       if ((c == 0 || c == ' ' || c == '(') &&
+                               (t == 0 || t == ' ' || t == ')')) {
+                               return TRUE;
+                       }
+                       if (t == 0) {
+                               break;
+                       }
+                       names = s + l;
+               }
+       }
+       return FALSE;
+}
+
+/*
+**     show_report(test_list, status, ch)
+**
+**     Display a list of caps that can be tested
+*/
+void
+show_report(
+       struct test_list *t,
+       int *state GCC_UNUSED,
+       int *ch)
+{
+       int i, j, nc, flag;
+       const char *s;
+       const char *nx[BOOLCOUNT + NUMCOUNT + STRCOUNT];
+
+       flag = t->flags & 255;
+       nc = 0;
+       for (i = 0; i < BOOLCOUNT; i++) {
+               if (flag_boolean[i] & flag) {
+                       nx[nc++] = boolnames[i];
+               }
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               if (flag_numerics[i] & flag) {
+                       nx[nc++] = numnames[i];
+               }
+       }
+       for (i = 0; i < STRCOUNT; i++) {
+               if (flag_strings[i] & flag) {
+                       nx[nc++] = strnames[i];
+               }
+       }
+       /* sort */
+       for (i = 0; i < nc - 1; i++) {
+               for (j = i + 1; j < nc; j++) {
+                       if (strcmp(nx[i], nx[j]) > 0) {
+                               s = nx[i];
+                               nx[i] = nx[j];
+                               nx[j] = s;
+                       }
+               }
+       }
+       if (flag & FLAG_FUNCTION_KEY) {
+               ptextln("The following function keys can be tested:");
+       } else
+       if (flag & FLAG_CAN_TEST) {
+               ptextln("The following capabilities can be tested:");
+       } else
+       if (flag & FLAG_TESTED) {
+               ptextln("The following capabilities have been tested:");
+       }
+       put_crlf();
+       for (i = 0; i < nc; i++) {
+               sprintf(temp, "%s ", nx[i]);
+               ptext(temp);
+       }
+       put_newlines(1);
+       *ch = REQUEST_PROMPT;
+}
+
+/*
+**     show_untested(test_list, status, ch)
+**
+**     Display a list of caps that are defined but cannot be tested.
+**     Don't bother to sort this list.
+*/
+static void
+show_untested(
+       struct test_list *t GCC_UNUSED,
+       int *state GCC_UNUSED,
+       int *ch)
+{
+       int i;
+
+       ptextln("Caps that are defined but cannot be tested:");
+       for (i = 0; i < BOOLCOUNT; i++) {
+               if (flag_boolean[i] == 0 && CUR Booleans[i]) {
+                       sprintf(temp, "%s ", boolnames[i]);
+                       ptext(temp);
+               }
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               if (flag_numerics[i] == 0 && CUR Numbers[i] >= 0) {
+                       sprintf(temp, "%s ", numnames[i]);
+                       ptext(temp);
+               }
+       }
+       for (i = 0; i < STRCOUNT; i++) {
+               if (flag_strings[i] == 0 && CUR Strings[i]) {
+                       sprintf(temp, "%s ", strnames[i]);
+                       ptext(temp);
+               }
+       }
+       put_newlines(1);
+       *ch = REQUEST_PROMPT;
+}
+
+/*
+**     edit_init()
+**
+**     Initialize the function key data base
+*/
+void
+edit_init(void)
+{
+       int i, j, lc;
+       char *lab;
+       struct name_table_entry const *nt;
+       int label_strings[STRCOUNT];
+
+       _nc_copy_termtype(&original_term, &cur_term->type);
+       for (i = 0; i < BOOLCOUNT; i++) {
+               original_term.Booleans[i] = CUR Booleans[i];
+       }
+       for (i = 0; i < NUMCOUNT; i++) {
+               original_term.Numbers[i] = CUR Numbers[i];
+       }
+       /* scan for labels */
+       for (i = lc = 0; i < STRCOUNT; i++) {
+               original_term.Strings[i] = CUR Strings[i];
+               if (strncmp(strnames[i], "lf", 2) == 0) {
+                       flag_strings[i] |= FLAG_LABEL;
+                       if (CUR Strings[i]) {
+                               label_strings[lc++] = i;
+                       }
+               }
+       }
+       /* scan for function keys */
+       for (i = 0; i < STRCOUNT; i++) {
+               if ((strnames[i][0] == 'k') && strcmp(strnames[i], "kmous")) {
+                       flag_strings[i] |= FLAG_FUNCTION_KEY;
+                       lab = (char *) 0;
+                       for (j = 0; j < lc; j++) {
+                               if (!strcmp(&strnames[i][1],
+                                       &strnames[label_strings[j]][1])) {
+                                       lab = CUR Strings[label_strings[j]];
+                                       break;
+                               }
+                       }
+                       enter_key(strnames[i], CUR Strings[i], lab);
+               }
+       }
+       /* Lookup the translated strings */
+       for (i = 0; i < TM_last; i++) {
+               if ((nt = _nc_find_entry(TM_string[i].name,
+                       _nc_info_hash_table)) && (nt->nte_type == STRING)) {
+                       TM_string[i].index = nt->nte_index;
+               } else {
+                       sprintf(temp, "TM_string lookup failed for: %s",
+                               TM_string[i].name);
+                       ptextln(temp);
+               }
+       }
+       if ((nt = _nc_find_entry("xon", _nc_info_hash_table)) != 0) {
+               xon_index = nt->nte_index;
+       }
+       xon_shadow = xon_xoff;
+}
+
+/*
+**     change_one_entry(test_list, status, ch)
+**
+**     Change the padding on the selected cap
+*/
+static void
+change_one_entry(
+       struct test_list *test,
+       int *state,
+       int *chp)
+{
+       struct name_table_entry const *nt;
+       int i, j, x, star, slash,  v, dot, ch;
+       const char *s;
+       char *t, *p;
+       const char *current_string;
+       char buf[1024];
+       char pad[1024];
+
+       i = test->flags & 255;
+       if (i == 255) {
+               /* read the cap name from the user */
+               ptext("enter name: ");
+               read_string(pad, 32);
+               if (pad[0] == '\0' || pad[1] == '\0') {
+                       *chp = pad[0];
+                       return;
+               }
+               if ((nt = _nc_find_entry(pad, _nc_info_hash_table)) &&
+                       (nt->nte_type == STRING)) {
+                       x = nt->nte_index;
+                       current_string = CUR Strings[x];
+               } else {
+                       sprintf(temp, "%s is not a string capability", pad);
+                       ptext(temp);
+                       generic_done_message(test, state, chp);
+                       return;
+               }
+       } else {
+               x = tx_index[i];
+               current_string = tx_cap[i];
+               strcpy(pad, strnames[x]);
+       }
+       if (!current_string) {
+               ptextln("That string is not currently defined.  Please enter a new value, including the padding delay:");
+               read_string(buf, sizeof(buf));
+               _nc_reset_input((FILE *) 0, buf);
+               _nc_trans_string(pad);
+               t = (char *)malloc(strlen(pad) + 1);
+               strcpy(t, pad);
+               CUR Strings[x] = t;
+               sprintf(temp, "new string value  %s", strnames[x]);
+               ptextln(temp);
+               ptextln(expand(t));
+               return;
+       }
+       sprintf(buf, "Current value: (%s) %s", pad, _nc_tic_expand(current_string, TRUE, TRUE));
+       putln(buf);
+       ptextln("Enter new pad.  0 for no pad.  CR for no change.");
+       read_string(buf, 32);
+       if (buf[0] == '\0' || (buf[1] == '\0' && isalpha(buf[0]))) {
+               *chp = buf[0];
+               return;
+       }
+       star = slash = FALSE;
+       for (j = v = dot = 0; (ch = buf[j]); j++) {
+               if (ch >= '0' && ch <= '9') {
+                       v = ch - '0' + v * 10;
+                       if (dot) {
+                               dot++;
+                       }
+               } else if (ch == '*') {
+                       star = TRUE;
+               } else if (ch == '/') {
+                       slash = TRUE;
+               } else if (ch == '.') {
+                       dot = 1;
+               } else {
+                       sprintf(temp, "Illegal character: %c", ch);
+                       ptextln(temp);
+                       ptext("General format:  99.9*/  ");
+                       generic_done_message(test, state, chp);
+                       return;
+               }
+       }
+       while (dot > 2) {
+               v /= 10;
+               dot--;
+       }
+       if (dot == 2) {
+               sprintf(pad, "%d.%d%s%s", v / 10, v % 10,
+                               star ? "*" : "", slash ? "/" : "");
+       } else {
+               sprintf(pad, "%d%s%s",
+                       v, star ? "*" : "", slash ? "/" : "");
+       }
+       s = current_string;
+       t = buf;
+       for (v = 0; (ch = *t = *s++); t++) {
+               if (v == '$' && ch == '<') {
+                       while ((ch = *s++) && (ch != '>'));
+                       for (p = pad; (*++t = *p++); );
+                       *t++ = '>';
+                       while ((*t++ = *s++));
+                       pad[0] = '\0';
+                       break;
+               }
+               v = ch;
+       }
+       if (pad[0]) {
+               sprintf(t, "$<%s>", pad);
+       }
+       if ((t = (char *)malloc(strlen(buf) + 1))) {
+               strcpy(t, buf);
+               CUR Strings[x] = t;
+               if (i != 255) {
+                       tx_cap[i] = t;
+               }
+       }
+       generic_done_message(test, state, chp);
+}
+
+/*
+**     build_change_menu(menu_list)
+**
+**     Build the change pad menu list
+*/
+static void
+build_change_menu(
+       struct test_menu *m)
+{
+       int i, j, k;
+       char *s;
+
+       for (i = j = 0; i < txp; i++) {
+               if ((k = tx_index[i]) >= 0) {
+                       s = _nc_tic_expand(tx_cap[i], TRUE, TRUE);
+                       s[40] = '\0';
+                       sprintf(change_pad_text[j], "%c) (%s) %s",
+                               'a' + j, strnames[k], s);
+                       change_pad_list[j].flags = i;
+                       change_pad_list[j].lines_needed = 4;
+                       change_pad_list[j].menu_entry = change_pad_text[j];
+                       change_pad_list[j].test_procedure = change_one_entry;
+                       j++;
+               }
+       }
+       strcpy(change_pad_text[j], "z) enter name");
+       change_pad_list[j].flags = 255;
+       change_pad_list[j].lines_needed = 4;
+       change_pad_list[j].menu_entry = change_pad_text[j];
+       change_pad_list[j].test_procedure = change_one_entry;
+       j++;
+       change_pad_list[j].flags = MENU_LAST;
+       if (m->menu_title) {
+               put_crlf();
+               ptextln(m->menu_title);
+       }
+}