aboutsummaryrefslogtreecommitdiff
path: root/pkg/ecl/eparam.c
diff options
context:
space:
mode:
authorJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
committerJoe Hunkeler <jhunkeler@gmail.com>2015-08-11 16:51:37 -0400
commit40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch)
tree4464880c571602d54f6ae114729bf62a89518057 /pkg/ecl/eparam.c
downloadiraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/ecl/eparam.c')
-rw-r--r--pkg/ecl/eparam.c2156
1 files changed, 2156 insertions, 0 deletions
diff --git a/pkg/ecl/eparam.c b/pkg/ecl/eparam.c
new file mode 100644
index 00000000..942b1a21
--- /dev/null
+++ b/pkg/ecl/eparam.c
@@ -0,0 +1,2156 @@
+/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+ */
+
+#define import_stdio
+#define import_libc
+#define import_error
+#define import_ctype
+#define import_ttset
+#define import_fset
+#define import_spp
+#include <iraf.h>
+
+#include "config.h"
+#include "mem.h"
+#include "operand.h"
+#include "errs.h"
+#include "param.h"
+#include "grammar.h"
+#include "task.h"
+#include "eparam.h"
+
+/*
+ * EPARAM -- Screen editor for parameter files.
+ *
+ * epset (pset) # edit any pset by name
+ * eparam (cx, &update, &cmd, &newpset) # edit incore pfile struct
+ *
+ * EHIST -- Screen editor for the history list.
+ *
+ * edit_history_directive (raw_cmd, new_cmd)
+ *
+ * Both of these primary functions use the following internal editing
+ * functions (and many more). These use EDCAP to describe the editor
+ * language to be used, and TERMCAP to describe the terminal to be driven.
+ *
+ * e_ttyinit enter edit mode
+ * e_ttyexit exit edit mode
+ *
+ * editstring screen editor for a string
+ *
+ * e_clear clear the screen
+ * e_clrline clear the current line
+ * e_ctrl send control sequence to the terminal
+ * e_display display text at addressed coordinates
+ * e_goto move cursor
+ * e_putline put a line to terminal with escape translation
+ *
+ * E_TTYINIT must be called to initialize the editor database and put the
+ * terminal into edit mode before calling any of these functions.
+ */
+
+extern int cldebug;
+static char dbg[SZ_LINE]; /* for formatting msgs */
+#define E_DEBUG(str) e_display(str,cmdline,1) /* debug msg on last line */
+
+struct param *parmlist[G_MAXPARAM]; /* assoc. keyword with param */
+static struct pfile *pfilep;
+static int keylines[G_MAXPARAM]; /* starting linenos of each keyword */
+static int firstelement[G_MAXPARAM]; /* first element on row for array */
+static int topkeys[G_MAXPAGES]; /* array of topkeys for each page */
+
+static int maxpage; /* maximum page number */
+static int cmdline; /* last line on screen */
+static int maxcol; /* last column on screen */
+static int line, topline, botline; /* current, top, bottom lines */
+static int col, startcol, nextcol; /* current, first, last columns */
+static XINT tty_fd, tty; /* define the terminal globally */
+static int botkeyline, nextline, /* various global variables for */
+ keyid, numkeys, topkey, /* keeping track of lines and keys */
+ botkey, nextkey;
+static int error_displayed = 0; /* flag for error messages */
+
+static int standout; /* flag for turning standout mode off */
+static int e_ucasein=NO,e_ucaseout=NO; /* tt case flags for raw mode i/o */
+static int ep_status = OK; /* OK=normal exit, ERR=ctrl/c exit */
+static int ep_filemode = NO; /* editing a file not a task */
+static int ep_nextcmd; /* next eparam command upon exit */
+static int ep_update; /* update pfile upon exit */
+static char e_nextpset[SZ_FNAME+1]; /* next pset to be edited */
+static struct ep_context *e_cx; /* current context */
+
+/* These global variables are reset by parse_clmodes() in modes.c whenever the
+ * appropriate CL parameter is changed.
+ */
+int ep_standout = YES; /* eparam default for standout */
+int ep_showall = NO; /* display all params, incl. hiddens */
+int eh_standout = YES; /* ehist default for standout */
+int eh_bol = NO; /* start ehist at beginning of line */
+int eh_verify = NO; /* use ehist with history meta-chars */
+#ifdef NO_READLINE
+int eh_readline = NO; /* no readline() available here */
+#else
+int eh_readline = YES; /* use readline() for terminal input */
+#endif
+int eh_longprompt = YES; /* print full package name as prompt */
+
+char *e_tonextword(), *e_toprevword(), *index();
+
+char epar_cmdbuf[SZ_LINE];
+
+
+
+/* EPSET -- Edit a parameter set. Once in the parameter set editor, editor
+ * colon commands may be used to edit any other parameter set, to save psets
+ * in pfiles, load psets from pfiles, and so on. ERR is returned if the user
+ * wants to quit altogether, e.g., when epset is called in a loop.
+ */
+int
+epset (
+ char *pset /* ltaskname or pfilename */
+)
+{
+ struct ep_context context[20], *cx;
+ char newpset[SZ_FNAME+1];
+ char runcmd[SZ_LINE+1];
+ int update, cmd;
+
+ cx = context;
+ cx->e_mpfp = NULL;
+ strcpy (cx->e_pset, pset);
+
+ while (cx >= context) {
+ /* Open the pfile to be edited. */
+ if (cx->e_mpfp == NULL) {
+ cx->e_topd = topd;
+ cx->e_mpfp = pfilesrch (cx->e_pset);
+ cx->e_cpfp = pfilecopy (cx->e_mpfp);
+ cx->e_init = YES;
+ }
+
+ /* Edit pset. If ERR is returned exit immediately without
+ * updating any pfiles, returning ERR to our caller.
+ */
+ if (eparam (cx, &update, &cmd, newpset) == ERR) {
+ for (; cx >= context; --cx) {
+ pfileunlink (cx->e_cpfp);
+ if (dereference (cx->e_mpfp) >= cx->e_topd)
+ pfileunlink (cx->e_mpfp);
+ topd = cx->e_topd;
+ }
+ return (ERR);
+ }
+
+ /* If we are done with this pfile (not descending into a pset)
+ * update the pfile on disk and free memory.
+ */
+ if (cmd != EP_DESCEND) {
+ if (update) {
+ pfcopyback (cx->e_cpfp);
+ pfileupdate (cx->e_mpfp);
+ } else
+ pfileunlink (cx->e_cpfp);
+
+ if (dereference (cx->e_mpfp) >= cx->e_topd)
+ pfileunlink (cx->e_mpfp);
+ cx->e_mpfp = NULL;
+ cx->e_cpfp = NULL;
+ topd = cx->e_topd;
+ }
+
+ /* Decide what to do next. */
+ switch (cmd) {
+ case EP_EOF: /* pop context */
+ --cx;
+ break;
+ case EP_EDIT: /* edit a new pfile */
+ strcpy (cx->e_pset, newpset);
+ break;
+ case EP_DESCEND: /* push context & edit */
+ cx++;
+ cx->e_mpfp = NULL;
+ strcpy (cx->e_pset, newpset);
+ break;
+ case EP_RUN: /* run the task */
+ sprintf (runcmd, "%s (mode='h')\n", newpset);
+ if (eh_readline == NO)
+ c_ungetline (fileno (prevtask->t_in), runcmd);
+ else
+ strcpy (epar_cmdbuf, runcmd);
+ return (OK);
+ default:
+ eprintf ("eparam: unrecognized command\n");
+ --cx;
+ break;
+ }
+ }
+
+ return (OK);
+}
+
+
+/* EPARAM -- Edit a parameter set which has already been loaded into a
+ * pfile structure. Most editor colon commands will cause an exit,
+ * returning the user command to the caller, e.g., to edit a new pset or
+ * quit. The context of the editor is saved upon exit in the context
+ * structure, allowing the editor to be reentered at the same point
+ * on the old pset.
+ */
+int
+eparam (
+ struct ep_context *cx, /* eparam editor context */
+ int *update, /* update pset upon exit */
+ int *nextcmd, /* receives next command */
+ char *nextpset /* receives next pset name */
+)
+{
+ char string[G_MAXSTRING];
+
+ pfilep = cx->e_cpfp; /* save in global variables */
+ e_cx = cx;
+
+ standout = ep_standout; /* set standout value */
+ e_ttyinit(); /* initialize the terminal */
+ edtinit(); /* and initialize the editor */
+
+ /* When we are called to edit a file, the ltask ptr is NULL.
+ */
+ if (ep_filemode = (pfilep->pf_ltp == NULL))
+ topline--; /* room for one more param line */
+
+ numkeys = e_makelist (pfilep); /* initialize parameter list */
+ if (numkeys < 1) /* nothing to edit */
+ goto exit;
+
+ ep_status = OK;
+ ep_nextcmd = EP_EOF; /* default if no :cmd */
+ ep_update = YES; /* default unless cleared */
+
+ if (cx->e_init) {
+ /* New pfile: start at the top. */
+ topkey = 1;
+ line = topline;
+ col = startcol;
+ nextkey = topkey;
+ nextline = topline;
+ } else {
+ /* Reentering an old pfile: start where we left off. */
+ topkey = cx->e_topkey;
+ line = cx->e_line;
+ col = cx->e_col;
+ nextkey = cx->e_nextkey;
+ nextline = cx->e_nextline;
+ }
+
+ if (parmlist[topkey]->p_type & PT_ARRAY) /* add line for array */
+ line++, nextline++;
+
+ e_repaint();
+
+ /* Main EPARAM loop.
+ */
+ while (nextline != cmdline) {
+ keyid = nextkey;
+ line = nextline;
+ col = startcol;
+
+ e_goto (col, line);
+ fflush (stdout);
+
+ /* Encode value string and call the string editor to give the
+ * user a chance to edit it.
+ */
+ e_encode_vstring (parmlist[keyid], string);
+
+ if (editstring (string, YES) > 0)
+ e_check_vals (string);
+
+ e_scrollit();
+ }
+exit:
+ /* Save our context in case we reenter this pfile. */
+ cx->e_topkey = topkey;
+ cx->e_line = line;
+ cx->e_col = col;
+ cx->e_nextkey = keyid;
+ cx->e_nextline = line;
+ cx->e_init = 0;
+
+ e_goto (1, cmdline);
+ e_clrline();
+
+ edtexit();
+ e_ttyexit();
+
+ *update = ep_update;
+ *nextcmd = ep_nextcmd;
+ strcpy (nextpset, e_nextpset);
+
+ return (ep_status);
+}
+
+
+/* E_MAKELIST -- Make a list of pointers to each parameter structure to aid
+ * speedy access. Return the number of parameters in the list. For a
+ * multiline prompt environment, we need a table of pointers to the firstline
+ * of each keyword.
+ */
+int
+e_makelist (struct pfile *pfileptr)
+{
+ register struct param *pp;
+ register char c, *p;
+ int numnew; /* number of newlines */
+ int totlines; /* count of current total lines */
+
+ topkeys[0] = 1;
+ totlines = 0;
+ maxpage = 0;
+
+ /* Scan the parameter list, adding each parameter to the EPARAM
+ * list. Hidden parameters are skipped if ep_showall=no (in epinit).
+ */
+ for (pp = pfileptr->pf_pp, numkeys = 0; pp != NULL; pp = pp->p_np) {
+
+ if ((pp->p_mode & M_HIDDEN) && (ep_showall == NO))
+ continue;
+
+ numkeys++;
+ parmlist[numkeys] = pp;
+
+ /* Count the number of newlines in the prompt, add to keylines.
+ */
+ numnew = 0;
+ p = pp->p_prompt;
+
+ while ((c = *p) != '\0') {
+ if (c == '\n')
+ numnew++;
+ p++;
+ }
+
+ totlines += numnew + 1;
+ keylines[numkeys] = numnew + 1;
+ firstelement[numkeys] = 1;
+
+ if (pp->p_type & PT_ARRAY) {
+ int numonrow, nextelement;
+ int dim, d, alines;
+ short *plen, len, flen;
+
+ keylines[numkeys]++; /* 1 extra line for arrays */
+ totlines++;
+ totlines = e_testtop (totlines, numnew+1+1);
+
+ dim = pp->p_val.v_a->a_dim;
+ plen = &(pp->p_val.v_a->a_len);
+ flen = *plen; /* first length */
+ alines = (flen - 1) / MAX_ON_ROW + 1;
+ numonrow = (flen > MAX_ON_ROW) ? MAX_ON_ROW : flen;
+
+ for (d=1; d < dim; d++) {
+ len = *(plen + 2*d);
+ alines *= len;
+ }
+
+ nextelement = 1;
+ for (d=1, numkeys++; d < alines; d++, numkeys++) {
+ parmlist[numkeys] = pp;
+ keylines[numkeys] = 1;
+
+ nextelement += numonrow;
+ firstelement[numkeys] = nextelement;
+
+ totlines++;
+ totlines = e_testtop (totlines, numnew+1+1+d);
+ }
+
+ --numkeys;
+
+ } else {
+ totlines = e_testtop (totlines, numnew+1);
+ }
+ }
+
+ if (cldebug) {
+ int i;
+ for (i=1; i <= numkeys; i++) {
+ sprintf (dbg, "parmlist: %d %d %d ",
+ parmlist[i], keylines[i], firstelement[i]);
+ E_DEBUG (dbg);
+ }
+ sprintf (dbg, " maxpage = %d ", maxpage);
+ E_DEBUG (dbg);
+ for (i=1; i<= maxpage; i++) {
+ sprintf (dbg, "topkeys : %d ", topkeys[i]);
+ E_DEBUG (dbg);
+ }
+ sprintf (dbg, "numkeys = %d ", numkeys);
+ E_DEBUG (dbg);
+ }
+
+ return (numkeys);
+}
+
+
+/* E_TESTTOP -- Check to see if we have filled up a screen and if so,
+ * start a new page.
+ */
+int
+e_testtop (
+ int cur, /* current line count on screen */
+ int new /* new count, returned if new page */
+)
+{
+ if (cur > (botline - topline + 1)) {
+ topkeys[++maxpage] = numkeys;
+ return (new);
+ } else
+ return (cur);
+}
+
+
+/* E_REPAINT -- Repaint the current screen.
+ */
+int
+e_repaint (void)
+{
+ static char *static_prompt = "--------- parameter array ---------";
+ char promptbuf[MAXPROMPT];
+ char outbuf[MAXPROMPT];
+ int i, keylin, ll, cc;
+ char *p;
+
+ /* More keys than can fit on the screen?
+ */
+ keylin = topline;
+ for (i=topkey; i <= numkeys && (keylin+keylines[i] <= (botline+1)); ) {
+ botkeyline = keylin;
+ keylin += keylines[i++];
+ }
+
+ botkey = i - 1;
+ if (parmlist[botkey]->p_type & PT_ARRAY)
+ botkeyline += keylines[botkey] - 1;
+
+ e_pheader (pfilep, cmdline, maxcol);
+
+ ll = line;
+ cc = col;
+ line = topline;
+ col = startcol;
+
+ for (keyid=topkey; keyid <= botkey; keyid++) {
+
+ if ((parmlist[keyid]->p_type & PT_ARRAY) &&
+ (firstelement[keyid] == 1)) {
+
+ /* Print the array parameter name. If hidden, enclose it in ()
+ * as in lparam.
+ */
+ if (parmlist[keyid]->p_mode & M_HIDDEN)
+ sprintf (outbuf, "(%-7.7s) ", parmlist[keyid]->p_name);
+ else
+ sprintf (outbuf, "%-8.8s ", parmlist[keyid]->p_name);
+ e_display (outbuf, line, 1);
+
+ /* Display the prompt over the values, to allow user to
+ * label columns (if desired).
+ */
+ p = parmlist[keyid]->p_prompt;
+ if (p == NULL || *p == NULL)
+ p = static_prompt;
+
+ /* e_indent_prompt (p, promptbuf, startcol); */
+ e_display (p, line, startcol);
+
+ line += keylines[keyid] - 1;
+ e_drawkey();
+ line++;
+
+ } else {
+ e_drawkey();
+ line += keylines[keyid];
+ }
+
+ fflush (stdout);
+ }
+
+ e_moreflag (topkey);
+
+ keyid = topkey;
+ e_goto (cc, ll);
+ line = ll;
+ col = cc;
+}
+
+
+/* E_PHEADER -- Print the EPARAM form header.
+ */
+int
+e_pheader (
+ struct pfile *pfp, /* pfile pointer */
+ int cmdline, /* terminal command line number */
+ int maxcol /* max cols on a line */
+)
+{
+ static char *logo = " I R A F ";
+ static char *title= "Image Reduction and Analysis Facility";
+ char string[SZ_LINE+1];
+ int i, col;
+
+ e_clear();
+
+ /* Print logo and title lines.
+ */
+ col = (maxcol - strlen(logo)) / 2;
+ e_ctrl ("so");
+ e_goto (col, 1);
+ e_putline (logo);
+
+ col = (maxcol - strlen(title)) / 2;
+ e_ctrl ("se");
+ e_ctrl ("us");
+ e_goto (col, 2);
+ e_putline (title);
+
+ /* Identify object being edited.
+ */
+ e_goto (1, 3);
+ e_ctrl ("ue");
+ if (ep_filemode) {
+ sprintf (string, "PARFILE = %s\r\n", pfp->pf_pfilename);
+ e_putline (string);
+ } else {
+ struct ltask *ltp = pfp->pf_ltp;
+ sprintf (string, "PACKAGE = %s\r\n", ltp->lt_pkp->pk_name);
+ e_putline (string);
+ sprintf (string, " TASK = %s\r\n", ltp->lt_lname);
+ e_putline (string);
+ }
+
+ for (col=0; col < maxcol; col++)
+ string[col] = ' ';
+ string[maxcol] = '\0';
+ e_ctrl ("us");
+ e_goto (1, cmdline-1); /* draw line across bottom of screen */
+ e_putline (string);
+
+ e_ctrl ("ue");
+ e_ctrl ("so");
+ e_goto (maxcol - 18, cmdline);
+
+ for (i=FIRST_CMD; (i<=numcommands) && (command[i].cmd != GET_HELP); i++)
+ ;
+ e_putline (command[i].keystroke); /* show the help command */
+ e_ctrl ("se");
+ e_putline (" for HELP");
+
+ fflush (stdout);
+}
+
+
+/* E_DRAWKEY -- Format and display the keyline. It is assumed that for
+ * arrays, the prompt occurs above the first array line. This enables the
+ * user to label his columns. We must handle multiline prompts as well.
+ * For maximum drawing speed output is optimized using line clears and screen
+ * gotos rather than blanks to erase and position text.
+ */
+int
+e_drawkey (void)
+{
+ char valuebuf[MAXPROMPT];
+ char tempbuf[MAXPROMPT];
+ int offset, nchars;
+ char *p;
+
+ e_encode_vstring (parmlist[keyid], valuebuf);
+ e_goto (1, line);
+ e_clrline();
+
+ if (parmlist[keyid]->p_type & PT_ARRAY) {
+ e_putline ("\t= ");
+ e_putline (valuebuf);
+ } else {
+ int hidden;
+
+ hidden = (parmlist[keyid]->p_mode & M_HIDDEN);
+
+ /* Print parameter name. Enclose hidden parameters in (), as in
+ * lparam. We lose a character in the name, but at least we know
+ * when a parameter is hidden.
+ */
+ if (hidden)
+ sprintf (tempbuf, "(%-7.7s=", parmlist[keyid]->p_name);
+ else
+ sprintf (tempbuf, "%-8.8s=", parmlist[keyid]->p_name);
+ e_putline (tempbuf);
+
+ /* Print the value string right justified in the value field.
+ */
+ nchars = strlen (valuebuf);
+ offset = PROMPTOFFSET - nchars - 1;
+ offset = (VALUEOFFSET > offset) ? VALUEOFFSET : offset;
+ e_goto (offset, line);
+
+ if (hidden) /* closing ) for hidden parameters */
+ strcat (valuebuf, ")");
+ e_putline (valuebuf);
+
+ /* Print the (possibly multiline) prompt string. Do not write over
+ * the value string if it's a long one.
+ */
+ offset += (nchars + 1); /* offset of prompt string */
+ if (offset < PROMPTOFFSET)
+ offset = PROMPTOFFSET;
+
+ /* Add one to the offset (for ')' in hidden parameters) and display
+ * the prompt. Continuation lines start at the standard prompt
+ * offset.
+ */
+ e_displayml (parmlist[keyid]->p_prompt, line, ++offset,
+ PROMPTOFFSET + 1);
+ }
+}
+
+
+/* E_INDENT_PROMPT -- Must handle multiline prompts, i.e. prompt string may
+ * have imbedded newlines. Convert newline into newline plus the number of
+ * spaces to indent.
+e_indent_prompt (p, bp, indent)
+char *p;
+char *bp;
+int indent;
+{
+ register int i;
+ register char c;
+
+ while ((*bp++ = c = *p++) != '\0')
+ if (c == '\n')
+ for (i=0; i < indent; i++)
+ *bp++ = ' ';
+}
+ */
+
+
+/* E_ENCODE_VSTRING -- Get the value as a string for editing. If it's an array,
+ * get several of the values. If it is an array, make sure the undefined values
+ * get a '***', without calling spparval (which would bomb).
+ */
+int
+e_encode_vstring (struct param *pp, char *outbuf)
+{
+ char valuebuf[G_MAXSTRING];
+ char colbuf[16];
+
+ *outbuf = '\0';
+
+ if (pp->p_type & PT_ARRAY) {
+ int first, i, nn, numonrow;
+ struct operand o;
+ short len; /* the length of the first dim */
+
+ len = pp->p_val.v_a->a_len;
+ first = firstelement[keyid];
+
+ nn = len - ((first-1) % len);
+ numonrow = (nn > MAX_ON_ROW) ? MAX_ON_ROW : nn;
+
+ for (i=first; i < first+numonrow; i++) {
+ /* First determine if the value is undefined or not.
+ */
+ poffset (i-1);
+ paramget (pp, FN_VALUE);
+ o = popop();
+
+ if (opundef (&o))
+ sprintf (colbuf," ***");
+ else {
+ if ((pp->p_type & OT_BASIC) == OT_REAL) {
+ /* For real numbers, do not use spparval since we may
+ * lose exponents in the formatting. Limit output but
+ * use the %g format directly.
+ */
+ sprintf (colbuf, "%10g ", o.o_val.v_r);
+ if (index (colbuf, '.') == NULL)
+ strcat (colbuf, ".");
+ } else {
+ poffset (i-1);
+ spparval (valuebuf, pp);
+ sprintf (colbuf, "%10.10s ", valuebuf);
+ }
+ }
+
+ strcat (outbuf, colbuf);
+ }
+
+ } else {
+ /* Do not use a high level routine such as paramget() to fetch
+ * the parameter value, as we do not want to deal with parameter
+ * indirection here. Just print the immediate value of the
+ * parameter as a string.
+ */
+ if (opundef (&pp->p_valo))
+ *outbuf = EOS;
+ else
+ sprop (outbuf, &pp->p_valo);
+ }
+}
+
+
+/* E_CHECK_VALS -- Perform range checking and reset the default if the string
+ * contains a partial array (yea, even a whole array). Parse each element of
+ * the array and check it. Also check whether there are enough elements in the
+ * array. In any case, if gquery returns an error, report that to the user.
+ */
+int
+e_check_vals (char *string)
+{
+ char *gquery(); /* declare gquery as returning a pointer */
+ char *errstr; /* pointer to the error string (or 0) */
+ char message[SZ_LINE+1];/* error message string */
+ int badnews; /* a flag if an array element is in error */
+ int isarray; /* a flag to indicate if this is an array */
+ int numonrow; /* the number of elements on a row */
+
+ isarray = parmlist[keyid]->p_type & PT_ARRAY;
+ badnews = 0;
+
+ if (cldebug) {
+ sprintf (dbg, "string = |%s| ", string);
+ E_DEBUG (dbg);
+ }
+
+ if (isarray) {
+ char outstring[G_MAXSTRING];
+ char *in, *out, *e_getfield();
+ int first, nelem, flen;
+
+ /* Get the length of the first dimension, and the starting point.
+ */
+ flen = parmlist[keyid]->p_val.v_a->a_len;
+ first = firstelement[keyid];
+
+ /* Determine how many elements SHOULD be on the row.
+ */
+ nelem = flen - (first-1) % flen;
+ numonrow = (nelem > MAX_ON_ROW) ? MAX_ON_ROW : nelem;
+
+ in = string;
+ badnews = 0;
+ nelem = 0;
+
+ /* Parse each element of the string.
+ */
+ while (!badnews) {
+ in = e_getfield (in, outstring, G_MAXSTRING);
+ if (outstring[0] == '\0')
+ break;
+ else
+ nelem++;
+
+ if (e_undef (outstring))
+ errstr = "OK";
+ else {
+ poffset (first+nelem-2); /* push absolute index */
+ errstr = gquery (parmlist[keyid], outstring);
+ }
+
+ if (strcmp (errstr, "OK") != 0) {
+ sprintf (message, "%s [%s]?", errstr, outstring);
+ badnews++;
+ }
+ }
+
+ if ((nelem != numonrow) && !(badnews)) {
+ sprintf (message, "Expected %d elements on this line",numonrow);
+ badnews++;
+ }
+
+ } else {
+ /* Not an array.
+ */
+ errstr = gquery (parmlist[keyid], string);
+ if (strcmp (errstr, "OK") != 0) {
+ strcpy (message, errstr);
+ badnews++;
+ }
+ }
+
+ /* Report any errors. */
+ if (badnews)
+ e_rpterror (message);
+
+ /* Reprint the line. */
+ e_drawkey();
+ e_goto (startcol, line);
+ fflush (stdout);
+}
+
+
+/* E_UNDEF -- Recognize the undefined string of 3 asterisks.
+ */
+int
+e_undef (register char *s)
+{
+ register int n = 0;
+
+ for (; (*s != '*') && (*s != '\0'); s++)
+ ;
+ for (; (*s == '*') && (*s != '\0'); s++)
+ n++;
+
+ return (n == 3);
+}
+
+
+static char message[SZ_LINE]; /* used by e_rpterror and e_clrerror */
+
+/* E_RPTERROR -- Report the error for the eparam user.
+ */
+int
+e_rpterror (char *errstr)
+{
+ char *range; /* pointer to the range error string */
+
+ if (parmlist[keyid]->p_type == OT_BOOL) {
+ sprintf (message, "%s must be `yes' or `no'", errstr);
+ } else if ((parmlist[keyid]->p_type == OT_STRING)
+ && !(parmlist[keyid]->p_flags & P_UMIN)) {
+ range = enumin (parmlist[keyid]);
+ sprintf (message, "What? %s", range);
+ } else {
+ range = minmax (parmlist[keyid]);
+ sprintf (message, "%s %s", errstr, range);
+ }
+
+ /* Display at most one line of error message to avoid having to redraw
+ * the screen.
+ */
+ message[maxcol-1] = '\0';
+ e_display (message, cmdline, 1);
+ e_putline ("\007");
+ error_displayed = 1;
+
+ /* Edit the same keyline over again.
+ */
+ nextline = line;
+ nextkey = keyid;
+ fflush (stdout);
+}
+
+
+/* E_CLRERROR -- Clear the error line, i.e. the last error message.
+ */
+int
+e_clrerror (void)
+{
+ register int i, len;
+
+ len = strlen (message);
+
+ for (i=0; i < len; i++)
+ message[i] = ' ';
+ message[len] = '\0';
+
+ e_display (message, cmdline, 1);
+ error_displayed = 0;
+
+ /* Edit the same keyline over again.
+ */
+ nextline = line;
+ nextkey = keyid;
+ e_goto (startcol, line);
+ fflush (stdout);
+}
+
+
+/* E_GETFIELD -- Extract the next newline or comma delimited token from
+ * a string. Returns as the function value a pointer to the first char
+ * after the token.
+ */
+char *
+e_getfield (
+ register char *ip, /* pointer into input string */
+ char *outstr, /* receives token */
+ int maxch /* max chars out */
+)
+{
+ register char *op, *otop;
+
+ while (*ip == ' ' || *ip == ',')
+ ip++;
+ otop = &outstr[maxch];
+ for (op=outstr; *ip != '\0' && *ip != ' ' && *ip != ','; ) {
+ *op++ = *ip++;
+ if (op >= otop)
+ break;
+ }
+ *op = '\0';
+
+ return (ip);
+}
+
+
+/* E_MOREFLAG -- Signal that there are more parameters above or below the
+ * window.
+ */
+int
+e_moreflag (register int topkey)
+{
+ if ((numkeys == botkey) && (topkey == 1))
+ return 0;
+
+ if (botkey < numkeys) {
+ e_ctrl ("so");
+ e_ctrl ("us");
+ e_display ("More", botline+1, 1);
+ } else {
+ e_ctrl ("us");
+ e_display (" ", botline+1, 1);
+ }
+
+ if (topkey != 1) {
+ e_ctrl ("so");
+ e_display ("More", topline-1, 1);
+ } else {
+ e_ctrl ("se");
+ e_ctrl ("ue");
+ e_display (" ", topline-1, 1);
+ }
+
+ e_ctrl ("se");
+ e_ctrl ("ue");
+ fflush (stdout);
+}
+
+
+/* E_SCROLLIT -- Scroll the window if possible.
+ */
+int
+e_scrollit (void)
+{
+ register int i;
+
+ if (nextline == cmdline) {
+ ;
+
+ } else if (nextline > botline) {
+ topkey = nextkey;
+ nextline = topline;
+ if (parmlist[topkey]->p_type & PT_ARRAY)
+ nextline += keylines[topkey] - 1;
+ e_repaint();
+
+ } else if (nextline < topline) {
+ for (i=0; topkeys[i] <= nextkey && topkeys[i] > 0; i++)
+ ;
+ topkey = topkeys[i-1];
+ e_repaint();
+ nextline = botkeyline; /* set in e_repaint */
+
+ } else if (nextline != topline) {
+ for (i=0; i <= maxpage; i++) {
+ if (topkeys[i] == nextkey && nextkey != topkey) {
+ topkey = nextkey;
+ nextline = topline;
+ if (parmlist[topkey]->p_type & PT_ARRAY)
+ nextline += keylines[topkey] - 1;
+ e_repaint();
+ }
+ }
+ }
+}
+
+
+/* EDIT_HISTORY_DIRECTIVE -- Main entry point of EHIST, an interactive history
+ * editor.
+ *
+ * EHIST is similar to the IRAF history commands to fetch a previous command,
+ * except that it allows the user to edit it interactively. The command is
+ * highlighted (optionally) and the user's line editor is invoked.
+ *
+ * This command is invoked by:
+ *
+ * ehist (== ^) edit the previous command
+ * ehist 3 (== ^3) edit command number 3
+ * ehist a* (== ^a*) edit the previous command beginning with 'a'
+ *
+ * A 'return' or EXIT_UPDATE will execute the edited command.
+ * An EXIT_NOUPDATE will not execute the edited command.
+ */
+int
+edit_history_directive (
+ char *args, /* ehistory argument list */
+ char *new_cmd /* the command to be executed after editing */
+)
+{
+ static char *firstchr[MAX_COMMANDS]; /*array of character pointers */
+ static char string[G_MAXSTRING];
+ char arglist[SZ_LINE+1];
+ int execute, nchars, ochars, i;
+ int ice; /* flag for interactive command editor */
+ int record; /* record number of the history record */
+ int numchar; /* number of characters in the new command */
+ char *lc, *sc;
+
+ /* Convert the ehist command into the form "^histcmd", fetch the
+ * command from the history, and start EHIST up.
+ */
+ arglist[0] = '^';
+ strcpy (&arglist[1], args);
+ execute = process_history_directive (arglist, new_cmd);
+
+ standout = eh_standout; /* set standout value */
+ e_ttyinit(); /* initialize the terminal */
+ edtinit(); /* and initialize the editor */
+ ice = YES;
+
+ while (ice) {
+ /* Count the number of keylines and setup the first character
+ * pointers.
+ */
+ firstchr[1] = new_cmd;
+ for (numkeys=1, sc=new_cmd; *sc != '\0'; sc++)
+ if (*sc == '\n') {
+ numkeys++;
+ firstchr[numkeys] = sc + 1;
+ keylines[numkeys] = 1;
+ }
+
+ numkeys--;
+ firstchr[numkeys+1] = sc;
+
+ topline = cmdline - numkeys;
+ botline = cmdline - 1;
+ startcol = 1;
+
+ numchar = strlen(new_cmd) - 1;
+ line = topline;
+ if (eh_bol)
+ nextcol = startcol;
+ else
+ nextcol = startcol + numchar;
+
+ e_ctrl ("so");
+ e_display (new_cmd, cmdline, 1);
+ e_ctrl ("se");
+ fflush (stdout);
+
+ *(new_cmd+numchar) = '\0'; /* get rid of the newline at the end. */
+ nextkey = 1;
+
+ /* Main EHIST loop.
+ */
+ while (nextkey > 0) {
+ /* Copy the next command.
+ */
+ sc = string, lc = firstchr[nextkey];
+ while ((*lc != '\n') && (*lc != '\0')) {
+ /* KLUDGE fix for tabs for the moment. */
+ if ((*sc = *lc) == '\t')
+ *sc = ' ';
+ lc++, sc++;
+ }
+ *sc = '\0';
+
+ keyid = nextkey;
+ /* line = topline + keyid - 1; 24Feb87 */
+ line = topline + keyid;
+ col = nextcol;
+
+ e_goto (col, line);
+ fflush (stdout);
+ ochars = strlen (string);
+ nchars = editstring (string, NO);
+
+ /* Shift commands to the right of this one.
+ */
+ if (nchars > ochars) {
+ lc = firstchr[numkeys+1] + nchars - ochars;
+ while (lc >= firstchr[keyid+1] - 1) {
+ *lc = *(lc - nchars + ochars);
+ --lc;
+ }
+ }
+
+ /* Insert the revised string inplace.
+ */
+ for (sc=string, lc=firstchr[keyid]; *sc != '\0'; sc++, lc++)
+ *lc = *sc;
+ *lc = '\n';
+
+ /* Move the following commands if necessary.
+ */
+ if (nchars < ochars)
+ for (lc=firstchr[keyid+1]; *lc !='\0'; lc++)
+ *(lc+nchars-ochars) = *lc;
+
+ /* Revise the firstchr pointers.
+ */
+ for (i = keyid+1; i <= numkeys; i++)
+ firstchr[i] = firstchr[i] + nchars-ochars;
+
+ numchar += nchars - ochars;
+ keyid += nextline - line;
+
+ } /* end of while (nextkey) */
+
+ *(new_cmd+numchar) = '\n';
+ *(new_cmd+numchar+1) = '\0';
+
+ execute = (nextkey < 0) ? 0 : 1;
+
+ if (nextline < topline) {
+ record = what_record() + 1;
+ if (get_history (record, new_cmd, SZ_CMDBLK) == ERR)
+ ice = NO;
+ } else if (nextline > botline) {
+ record = what_record() - 1;
+ if (get_history (record, new_cmd, SZ_CMDBLK) == ERR)
+ ice = NO;
+ } else
+ ice = NO;
+
+ } /* end of ice loop */
+
+ edtexit();
+ e_ttyexit();
+ printf ("\n");
+ fflush (stdout);
+
+ return (execute);
+}
+
+
+/* EDITSTRING -- A very limited string editor for interactive input. The number
+ * of characters in the edited string is returned as the function value.
+ */
+int
+editstring (
+ char *string,
+ int eparam /* flag to indicate eparam or ehis */
+)
+{
+ char oldchar; /* save old character after delete */
+ char oldword[G_MAXSTRING]; /* save the deleted word */
+ char oldline[G_MAXSTRING]; /* save the deleted line */
+ char tempstr[G_MAXSTRING];
+ char *chn;
+ char *cp; /* pointer to char within string */
+ char *lc; /* pointer to last char */
+ int oldnum = 0; /* for DEL_WORD and UNDEL_WORD */
+ int numchar; /* number of characters in string */
+ int cmd; /* the command identifier */
+ int direction; /* the cursor direction */
+ int gotstring, i, numdel, ch;
+
+ gotstring = NO; /* dont have anything yet */
+
+ if (eparam) {
+ /* Start out with an empty string, saving the old value of
+ * the parameter in "oldline".
+ */
+ strcpy (oldline, string);
+ numchar = 0;
+ cp = string;
+ *cp = '\0';
+ } else {
+ /* Edit history. Start at either EOL or BOL depending upon
+ * value of switch set by user.
+ */
+ numchar = strlen (string);
+ if (eh_bol)
+ cp = string;
+ else
+ cp = string + numchar;
+ }
+
+ direction = FWD;
+ col = startcol + (cp - string);
+
+ while (!gotstring) {
+
+ /* Fetch the next keystroke.
+ */
+ ch = fgetc (stdin);
+ if (error_displayed)
+ e_clrerror();
+
+ /* Map to lower case if ucasein switch is set. The ^ shift escape
+ * sequence is not currently supported.
+ */
+ if (e_ucasein && isupper(ch))
+ ch = tolower (ch);
+
+ if (ch == EOF) {
+ /* EOF returned; should not happen, so return.
+ */
+ gotstring = YES;
+ nextline = cmdline;
+ continue;
+
+ } else if (eparam && ch == ':' && col == startcol) {
+ /* Colon escape.
+ */
+ if (e_colon() == EP_EOF) {
+ gotstring = YES;
+ nextline = cmdline;
+ } else {
+ e_goto (col, line);
+ fflush (stdout);
+ }
+ continue;
+
+ } else if (ch == ' ' || ch == '\t' || isprint(ch)) {
+ /* Normal character.
+ */
+
+ /* KLUDGE fix for tabs for the moment. */
+ ch = (ch == '\t') ? ' ' : ch;
+
+ /* Copy what's to the right. */
+ for (lc = string + numchar +1; lc > cp; --lc)
+ *lc = *(lc-1);
+ *cp = ch; /* substitute the new char */
+
+ if (cp >= (string + G_MAXSTRING))
+ continue;
+ lc = cp; numchar++; col++; cp++;
+ e_ctrl ("so");
+ e_putline (lc);
+ e_ctrl ("se");
+ e_goto (col, line);
+ fflush (stdout);
+ continue;
+
+ } else if (ch == '\r') {
+ /* Carriage return.
+ */
+ if (eparam)
+ gotstring = e_movedown (eparam);
+ else {
+ nextkey = 0;
+ nextline = botline;
+ gotstring = YES;
+ }
+ continue;
+
+ } else {
+ /* Find out if it is a legitimate edit command.
+ */
+ cmd = what_cmd (ch);
+ }
+
+ /* Perform the editing function.
+ */
+ switch (cmd) {
+
+ case MOVE_UP:
+ gotstring = e_moveup (eparam);
+ break;
+
+ case MOVE_DOWN:
+ gotstring = e_movedown (eparam);
+ break;
+
+ case MOVE_RIGHT:
+ if (cp < (string+numchar)) /* dont move beyond string */
+ if (col < maxcol) /* dont move beyond screen */
+ cp++;
+ break;
+
+ case MOVE_LEFT:
+ if (cp > string) /* dont move too far */
+ --cp;
+ break;
+
+ case NEXT_WORD:
+ if (direction != AFT) {
+ if (cp != (string+numchar))
+ cp = e_tonextword (cp);
+ else
+ gotstring = e_movedown (eparam);
+ break;
+ }
+ /* fall through to the PREV_WORD case (no break) */
+
+ case PREV_WORD:
+ if (cp != string)
+ cp = e_toprevword (cp, string);
+ else
+ gotstring = e_moveup (eparam);
+ break;
+
+ case MOVE_EOL:
+ /* Move to the end of the current line.
+ */
+ if (cp < (string+numchar)) {
+ cp = string + numchar;
+ break;
+ }
+
+ if (direction == AFT)
+ gotstring = e_moveup (eparam);
+ else
+ gotstring = e_movedown (eparam);
+ break;
+
+ case MOVE_BOL:
+ /* Move to the beginning of the current line.
+ */
+ cp = string;
+ break;
+
+ case NEXT_LINE:
+ if (direction == AFT)
+ gotstring = e_moveup (eparam);
+ else
+ gotstring = e_movedown (eparam);
+ break;
+
+ case NEXT_PAGE:
+ if (eparam) {
+ if (botkey != numkeys) {
+ nextline = botline + 1;
+ nextkey = botkey + 1;
+ } else {
+ nextline = botkeyline;
+ nextkey = botkey;
+ }
+ gotstring = YES;
+ }
+ break;
+
+ case PREV_PAGE:
+ if (eparam) {
+ if (topkey != 1) {
+ nextline = topline - 1;
+ nextkey = topkey - 1;
+ } else {
+ nextline = topline;
+ nextkey = topkey;
+ }
+ gotstring = YES;
+ }
+ break;
+
+ case MOVE_START:
+ if (eparam) {
+ if (topkey == 1) {
+ nextline = topline;
+ nextkey = topkey;
+ } else {
+ nextline = botline + 1;
+ nextkey = 1;
+ }
+ gotstring = YES;
+ }
+ break;
+
+ case MOVE_END:
+ if (eparam) {
+ if (botkey == numkeys) {
+ nextline = botkeyline;
+ nextkey = botkey;
+ } else {
+ nextline = topline - 1;
+ nextkey = numkeys;
+ }
+ gotstring = YES;
+ }
+ break;
+
+ case SET_FWD:
+ direction = FWD;
+ break;
+
+ case SET_AFT:
+ direction = AFT;
+ break;
+
+ case TOGGLE_DIR:
+ if (direction == AFT)
+ direction = FWD;
+ else
+ direction = AFT;
+ break;
+
+ case DEL_LEFT:
+ chn = cp - 1;
+ if (numchar > 0) {
+ oldchar = *chn;
+ strcpy (chn, chn+1);
+ if (cp > string)
+ --cp;
+ --numchar;
+
+ e_display (string, line, startcol);
+
+ e_goto (startcol + numchar, line);
+ e_putline (" ");
+ fflush (stdout);
+ }
+ break;
+
+ case DEL_CHAR:
+ /* Delete the character under the cursor.
+ */
+ chn = cp;
+ if ((numchar > 0) && (cp < (string+numchar))) {
+ oldchar = *chn;
+ strcpy (chn, chn+1);
+ --numchar;
+
+ e_display (string, line, startcol);
+
+ e_goto (startcol + numchar, line);
+ e_putline (" ");
+ fflush (stdout);
+ }
+ break;
+
+ case UNDEL_CHAR:
+ /* Undelete the last character deleted.
+ */
+ for (lc=string+numchar+1; lc >= cp; --lc)
+ *lc = *(lc-1);
+ *cp = oldchar;
+ numchar++;
+ e_display (string, line, startcol);
+ break;
+
+ case DEL_WORD:
+ if (cp >= (string + numchar)) /* end of line */
+ break;
+
+ chn = e_tonextword (cp);
+
+ if ((numchar > 0) && (chn != cp)) {
+ numdel = chn - cp;
+ strncpy (oldword, cp, numdel);
+ oldnum = numdel;
+ strcpy (cp, chn);
+ numchar -= numdel;
+
+ e_display (string, line, startcol);
+
+ e_goto (startcol + numchar, line);
+ for (i=0; i < numdel; i++)
+ e_putline (" ");
+ fflush (stdout);
+ }
+ break;
+
+ case UNDEL_WORD:
+ if (oldnum > 0) {
+ strcpy (tempstr, cp); /* save the end */
+ strncpy (cp, oldword, oldnum);
+ strcpy (cp+oldnum, tempstr);
+ numchar = numchar + oldnum;
+ e_display (string, line, startcol);
+ }
+ break;
+
+ case DEL_LINE:
+ strcpy (oldline, cp);
+ *cp= '\0';
+ chn = string + numchar;
+ numdel = chn - cp;
+ numchar = cp - string;
+
+ e_display (string, line, startcol);
+
+ e_goto (startcol + numchar, line);
+ for (i=0; i < numdel; i++)
+ e_putline (" ");
+ fflush (stdout);
+ break;
+
+ case UNDEL_LINE:
+ /* Erase current value totally; don't want extraneous
+ * characters floating around.
+ */
+ e_goto (startcol, line);
+ numchar = PROMPTOFFSET - startcol;
+ for (i=0; i < numchar; i++)
+ e_putline (" ");
+
+ /* Now, get the old line and display it.
+ */
+ strcpy (cp, oldline);
+ numchar = strlen (string);
+ cp = string + numchar;
+ e_display (string, line, startcol);
+ break;
+
+ case GET_HELP:
+ show_editorhelp();
+
+ /* fall through */
+
+ case REPAINT:
+ if (eparam) {
+ nextkey = keyid;
+ e_repaint();
+ keyid = nextkey;
+ }
+ e_ctrl ("so");
+ e_display (string, line, startcol);
+ e_ctrl ("se");
+ break;
+
+ case EXIT_NOUPDATE:
+ if (eparam) {
+ nextline = cmdline;
+ ep_status = ERR;
+ } else {
+ nextkey = -1;
+ nextline= botline;
+ }
+ gotstring = YES;
+ break;
+
+ case EXIT_UPDATE:
+ if (eparam) {
+ nextline = cmdline;
+ if (numchar > 0)
+ e_check_vals (string);
+ } else
+ nextline = botline;
+
+ nextkey = 0;
+ gotstring = YES;
+ break;
+
+ default:
+ e_putline ("\007");
+ break;
+ }
+
+ col = startcol + cp - string;
+ e_goto (col, line);
+ fflush (stdout);
+ }
+
+ return (numchar);
+}
+
+
+/* E_TTYINIT -- Initialize the terminal, i.e., set raw mode and standout mode
+ * (if enabled). Get dimensions of terminal screen.
+ */
+int
+e_ttyinit (void)
+{
+ /* Open the tty (termcap) descriptor for the terminal.
+ */
+ if ((tty = c_ttyodes ("terminal")) == ERR)
+ c_erract (EA_ERROR);
+
+ /* Set raw mode on the standard input.
+ */
+ c_fseti (fileno(stdin), F_RAW, YES);
+
+ /* The following is to support monocase (upper case only) terminals,
+ * or normal dualcase terminals in shift lock mode. Normally the
+ * terminal driver handles this, but since this is a raw mode
+ * interface case mapping is disabled. Determine if ucasein and
+ * ucaseout have been selected, e.g., with `stty ucasein ucaseout'.
+ */
+ e_ucasein = c_ttstati ((XINT)STDIN, TT_UCASEIN);
+ e_ucaseout = c_ttstati ((XINT)STDOUT, TT_UCASEOUT);
+
+ /* Get the dimensions of the terminal screen from the environment.
+ * These need not agree with the physical screen dimensions given
+ * in the termcap descriptor.
+ */
+ c_xttysize (&maxcol, &cmdline);
+ startcol = G_STARTCOL;
+ topline = G_TOPLINE;
+ botline = cmdline - (G_CMDLINE - G_BOTLINE);
+
+ tty_fd = fileno(stdout);
+}
+
+
+/* E_COLON -- Process a colon escape. Prompt with a : on the status line,
+ * get the command from the user, and either execute the command or return
+ * the command to the procedure which called eparam. As far as possible,
+ * all error checking should be performed before exiting, so that eparam
+ * does not exit when an invalid colon escape is entered. EP_EOF is returned
+ * as the function value if eparam is to exit.
+ */
+int
+e_colon (void)
+{
+ register char *ip, *op;
+ register int ch;
+ char buf[SZ_LINE+1], *pset;
+ struct param *pp;
+ int ucasein_set;
+ int force, n;
+
+ ucasein_set = c_ttstati ((XINT)STDIN, TT_UCASEIN);
+
+ /* Go to the command line, clear it and read the string value.
+ * The read is performed in raw mode to avoid a line feed and scroll
+ * when the CR is typed.
+ */
+again_:
+ c_ttygoto (tty_fd, tty, 1, cmdline);
+ c_ttyclearln (tty_fd, tty);
+ c_ttyctrl (tty_fd, tty, "se", 1);
+ c_ttyputline (tty_fd, tty, "\r:", NO);
+ c_flush (tty_fd);
+
+ for (op=buf; (ch = fgetc (stdin)) != EOF; ) {
+ if (ch == '\177' || ch == '\010') { /* delete */
+ if (op > buf) {
+ *--op = EOS;
+ c_ttyclearln (tty_fd, tty);
+ c_ttyputline (tty_fd, tty, "\r:", NO);
+ c_ttyputline (tty_fd, tty, buf, NO);
+ c_flush (tty_fd);
+ } else {
+ /* A delete at bol gets us out of colon mode. */
+ break;
+ }
+ } else if (ch == '\003' || ch == '\025') { /* ^C, ^U */
+ c_ttyclearln (tty_fd, tty);
+ goto again_;
+ } else if (ch == '\n' || ch == '\r' || (op - buf) >= SZ_LINE) {
+ break;
+ } else {
+ fputc (ch, stdout);
+ c_flush (tty_fd);
+ if (ucasein_set && isupper (ch))
+ *op++ = tolower (ch);
+ else
+ *op++ = ch;
+ }
+ }
+ *op = EOS;
+
+ /* Parse the colon directive.
+ */
+ for (ip=buf; isspace (*ip); ip++)
+ ;
+ if (*ip == EOS) {
+ c_ttyclearln (tty_fd, tty);
+ return (OK); /* null command */
+ }
+
+ ch = *ip++;
+ if (ch == 'g' && *ip == 'o')
+ ip++;
+ if (force = (*ip == '!'))
+ ip++;
+ for (; isspace (*ip); ip++)
+ ;
+ pset = ip;
+
+ /* Process the colon directive.
+ */
+ switch (ch) {
+ case 'q':
+ /* Exit. The pfile is automatically updated unless :q! is used.
+ */
+ if (force)
+ ep_update = NO;
+ return (EP_EOF);
+
+ case 'w':
+ /* Update the pfile currently being edited if no arg, else
+ * write the named pfile.
+ */
+ if (*pset == EOS)
+ n = pfilewrite (pfilep, pfilep->pf_pfilename);
+ else if (strcmp (pset, "q") == 0) /* ":wq" */
+ return (EP_EOF);
+ else {
+ if (force || c_access (pset, 0,0) == NO)
+ n = pfilewrite (pfilep, pset);
+ else {
+ sprintf (buf,
+ "File exists - use `w! %s' to overwrite", pset);
+ e_puterr (buf);
+ return (ERR);
+ }
+ }
+
+ sprintf (buf, " - %d parameters written to %s", n,
+ (*pset == EOS) ? pfilep->pf_pfilename : pset);
+ e_putline (buf);
+ fflush (stdout);
+ return (OK);
+
+ case 'r':
+ /* Load a new set of parameter values into the parameter set
+ * currently being edited. If no argument is given the main
+ * task pset is reloaded.
+ */
+ if (*pset == EOS) {
+ if (force) {
+ strcpy (e_nextpset, e_cx->e_pset);
+ ep_nextcmd = EP_EDIT;
+ ep_update = NO;
+ return (EP_EOF);
+ } else {
+ e_puterr ("Use `r!' to reload current pset");
+ return (ERR);
+ }
+ } else {
+ if (e_psetok (pset)) {
+ pfilemerge (e_cx->e_cpfp, pset);
+
+ /* If we're forcing the new parameters, update
+ * the pfile on disk so we can execute it immediately.
+ */
+ if (force)
+ n = pfilewrite (pfilep, pfilep->pf_pfilename);
+
+ e_repaint();
+ return (OK);
+ } else
+ return (ERR);
+ }
+
+ case 'e':
+ /* Edit the pset whose name is given by the string value of the
+ * current parameter.
+ */
+ if (*pset != EOS) {
+ /* Edit a new pset, discarding current context.
+ */
+ if (e_psetok (pset)) {
+ strcpy (e_nextpset, pset);
+ ep_nextcmd = EP_EDIT;
+ return (EP_EOF);
+ } else
+ return (ERR);
+
+ } else {
+ /* Edit the pset pointed to by the pset parameter currently
+ * under the cursor (only works for pset parameters).
+ */
+ pp = parmlist[keyid];
+ if (!(pp->p_type & PT_PSET)) {
+ sprintf (buf, "parameter `%s' is not a pset parameter",
+ pp->p_name);
+ e_puterr (buf);
+ return (ERR);
+ }
+
+ /* Get the pset name. This is the string value of the pset
+ * parameter, else the name of the parameter itself.
+ */
+ e_encode_vstring (pp, buf);
+ if (*buf == EOS)
+ pset = pp->p_name;
+ else
+ pset = buf;
+
+ if (e_psetok (pset)) {
+ strcpy (e_nextpset, pset);
+ ep_nextcmd = EP_DESCEND;
+ return (EP_EOF);
+ } else
+ return (ERR);
+ }
+
+ case 'g':
+ /* Exit and run the task.
+ */
+ if (force)
+ ep_update = NO;
+ if (*pset == EOS)
+ pset = e_cx->e_pset;
+
+ if (is_pfilename (pset)) {
+ e_puterr ("cannot execute a pfile");
+ return (ERR);
+ } else {
+ strcpy (e_nextpset, pset);
+ ep_nextcmd = EP_RUN;
+ return (EP_EOF);
+ }
+
+ default:
+ e_puterr ("Invalid colon escape directive");
+ return (ERR);
+ }
+}
+
+
+/* E_PSETOK -- Verify that the named pfile exists and can be read. Report
+ * any problems to the user.
+ */
+int
+e_psetok (char *pset)
+{
+ register struct pfile *pfp;
+ char errmsg[SZ_LINE+1], *errfmt, *errarg;
+ XINT save_topd;
+
+ save_topd = topd;
+ errarg = pset;
+ pfp = NULL;
+
+ if (is_pfilename (pset)) {
+ /* Verify valid file pset.
+ */
+ if (c_access (pset, 0,0) == NO) {
+ errfmt = "pfile `%s' does not exist";
+ goto error_;
+ } else if ((pfp = pfileread (NULL, pset, 0)) == NULL) {
+ errfmt = e_badpfile;
+ goto error_;
+ }
+
+ } else {
+ /* Verify valid ltask pset.
+ */
+ char *x1, *pk, *lt, *x2;
+ struct package *pkp;
+ struct ltask *ltp;
+
+ breakout (pset, &x1, &pk, &lt, &x2);
+ ltp = _ltasksrch (pk, lt, &pkp);
+
+ if (pkp == NULL) {
+ errfmt = e_pcknonexist;
+ errarg = pk;
+ goto error_;
+ } else if ((XINT)pkp == ERR) {
+ errfmt = e_pckambig;
+ errarg = pk;
+ goto error_;
+ } else if (ltp == NULL) {
+ errfmt = e_tnonexist;
+ errarg = lt;
+ goto error_;
+ } else if ((XINT)ltp == ERR) {
+ errfmt = e_tambig;
+ errarg = lt;
+ goto error_;
+ }
+
+ if (!(ltp->lt_flags & LT_PFILE)) {
+ errfmt = e_nopfile;
+ goto error_;
+ } else if ((pfp = pfileload (ltp)) == NULL) {
+ errfmt = e_badpfile;
+ goto error_;
+ }
+ }
+
+ /* If we get here we presumably have a valid pset. Return memory
+ * and return YES to the caller, indicating that the pset is valid.
+ */
+ if (pfp)
+ pfileunlink (pfp);
+ topd = save_topd;
+ return (YES);
+
+error_:
+ sprintf (errmsg, errfmt, errarg);
+ e_puterr (errmsg);
+ return (NO);
+}
+
+
+/* E_PUTERR -- Put an error message on the command line.
+ */
+int
+e_puterr (char *errmsg)
+{
+ c_ttygoto (tty_fd, tty, 1, cmdline);
+ c_ttyclearln (tty_fd, tty);
+ e_putline (errmsg);
+}
+
+
+/* E_TTYEXIT -- Turn off raw mode and standout mode and close the termcap
+ * descriptor, leaving everything as we found it.
+ */
+int
+e_ttyexit (void)
+{
+ c_fseti (fileno(stdin), F_RAW, NO); /* unset raw mode */
+
+ c_ttygoto (tty_fd, tty, 1, cmdline);
+ c_ttyctrl (tty_fd, tty, "se", 1);
+ c_ttycdes (tty);
+
+ fflush (stdout);
+}
+
+
+/* E_MOVEUP -- Move the cursor up one line.
+ */
+int
+e_moveup (int eparam)
+{
+ if (keyid != 1) {
+ /* Can go up further.
+ */
+ nextkey = keyid - 1;
+ if (line == topline) /* over the top */
+ nextline = topline - 1;
+ else {
+ nextline = line - keylines[nextkey];
+ if (eparam) {
+ if ((parmlist[nextkey]->p_type & PT_ARRAY))
+ if (firstelement[nextkey] == 1)
+ nextline = line - 1;
+
+ if ((parmlist[keyid]->p_type & PT_ARRAY))
+ if (firstelement[keyid] == 1)
+ nextline = nextline - keylines[keyid] + 1;
+ }
+ if (nextline < topline)
+ nextline = topline - 1;
+ }
+
+ } else if (!eparam) {
+ nextline = topline - 1;
+ nextkey = -1;
+ }
+
+ return (YES);
+}
+
+
+/* E_MOVEDOWN -- Move the cursor down one line.
+ */
+int
+e_movedown (int eparam)
+{
+ if (keyid != numkeys) {
+ /* get downnnnn!!
+ */
+ nextkey = keyid+1;
+ if (line == botline)
+ nextline = botline+1;
+ else {
+ nextline = line + keylines[keyid];
+ if (eparam) {
+ if ((parmlist[keyid]->p_type & PT_ARRAY))
+ if (firstelement[keyid] == 1)
+ nextline = line + 1;
+
+ /* Make room for prompt */
+ if ((parmlist[nextkey]->p_type & PT_ARRAY))
+ if (firstelement[nextkey] == 1)
+ nextline = nextline + keylines[nextkey] - 1;
+ }
+ if (nextline > botline)
+ nextline = botline + 1;
+ }
+
+ } else if (!eparam) {
+ nextline = botline+1;
+ nextkey = -1;
+ }
+
+ if (cldebug) {
+ sprintf (dbg, "nextline=%d, nextkey=%d line=%d keys=%d",
+ nextline, nextkey, line, keylines[nextkey]);
+ E_DEBUG(dbg);
+ }
+
+ return (YES);
+}
+
+
+/* E_TONEXTWORD -- Skip forward to the beginning of the next word.
+ */
+char *
+e_tonextword (register char *ip)
+{
+ ip++;
+
+ /* Pass over leading characters. */
+ while (*ip && !isspace (*ip))
+ ip++;
+
+ /* Find the next character. */
+ while (*ip && isspace(*ip))
+ ip++;
+
+ return (ip);
+}
+
+
+/* E_TOPREVWORD -- Find the beginning of the previous word.
+ */
+char *
+e_toprevword (char *ip, char *string)
+{
+ --ip;
+
+ /* Pass over leading blanks. */
+ if (*ip == ' ')
+ for (; (*ip == ' ') && (ip != string); --ip)
+ ;
+
+ /* Find the preceding blank. */
+ for (; (*ip != ' ') && (ip != string); --ip)
+ ;
+ if ((*ip != ' ') && (ip == string))
+ ;
+ else
+ ip++;
+
+ return (ip);
+}
+
+
+/* E_CTRL -- Send a control sequence to the terminal.
+ */
+int
+e_ctrl (char *cap)
+{
+ /* Check for start standout or start underline mode.
+ */
+ if (strcmp(cap,"so") == 0 || strcmp(cap,"us") == 0)
+ if (standout == NO)
+ return 0;
+
+ c_ttyctrl (tty_fd, tty, cap, 1);
+}
+
+
+/* E_GOTO -- High level edcap version of ttygoto (cursor addressing).
+ */
+int
+e_goto (int col, int line)
+{
+ c_ttygoto (tty_fd, tty, col, line);
+}
+
+
+/* E_PUTLINE -- Put a line of text to the terminal. Do not map any embedded
+ * control codes (bell will get lost).
+ */
+int
+e_putline (char *stwing)
+{
+ register char *ip, *op;
+ register int ch, n;
+ char obuf[512];
+ int map_cc=0;
+
+ /* Map output to upper case if `stty ucaseout' mode is set (we have
+ * to do this here because of the raw i/o).
+ */
+ if (e_ucaseout) {
+ for (ip=stwing, op=obuf, n=512; --n >= 0 && (ch = *ip++) != EOS; )
+ *op++ = islower(ch) ? toupper(ch) : ch;
+ *op = EOS;
+ ip = obuf;
+ } else
+ ip = stwing;
+
+ /* The flush calls are required to avoid mixing text and control
+ * sequences when doing raw i/o to monocase terminals.
+ */
+ if (e_ucaseout)
+ c_flush (tty_fd);
+ c_ttyputline (tty_fd, tty, ip, map_cc);
+ if (e_ucaseout)
+ c_flush (tty_fd);
+}
+
+
+/* E_CLEAR -- Clear the screen (disables standout mode as a side effect).
+ */
+int
+e_clear (void)
+{
+ c_ttyctrl (tty_fd, tty, "se", 1);
+ c_ttyctrl (tty_fd, tty, "ue", 1);
+ c_ttyclear (tty_fd, tty);
+}
+
+
+/* E_CLRLINE -- Clear the current line.
+ */
+int
+e_clrline (void)
+{
+ c_ttyclearln (tty_fd, tty);
+}
+
+
+/* E_DISPLAY -- Output a possibly multiline string at the given screen
+ * coordinates. Each line is written starting at the same column on the
+ * screen.
+ */
+int
+e_display (
+ char *string, /* string to be printed */
+ int sline,
+ int scol /* starting line and column */
+)
+{
+ e_displayml (string, sline, scol, scol);
+}
+
+
+/* E_DISPLAYML -- Display a possibly multiline prompt, with the first line
+ * starting a different column than the continuation lines. If a continuation
+ * line begins with \r (CR) it will be displayed starting at column 1, rather
+ * than starting at column scol.
+ */
+int
+e_displayml (
+ char *string, /* string to be printed */
+ int sline,
+ int scol, /* starting line and column */
+ int ccol /* start col of continuation lines */
+)
+{
+ register char *ip, *op;
+ char lbuf[512], *line;
+ int ocol;
+
+ /* Display a series of newline delimited lines.
+ */
+ for (ip=string, op=lbuf; *ip != EOS; )
+ for (op=lbuf; (*op = *ip) != EOS; op++, ip++)
+ if (*op == '\n') {
+ *op = EOS;
+ /* Truncate line at right margin. If first char is \r,
+ * starting column is column 1 rather than scol.
+ */
+ ocol = scol; line = lbuf;
+ while (*line == '\r') {
+ ocol = 1;
+ line++;
+ }
+ line[maxcol-ocol+1] = EOS;
+
+ /* Display the line. */
+ e_goto (ocol, sline++);
+ e_ctrl ("ce");
+ e_putline (line);
+ op = lbuf - 1;
+ scol = ccol;
+ }
+
+ /* Display any remaining, nonnewline-delimited line segment.
+ */
+ if (op > lbuf) {
+ *op = EOS;
+ ocol = scol; line = lbuf;
+ while (*line == '\r') {
+ ocol = 1;
+ line++;
+ }
+ line[maxcol-ocol+1] = EOS;
+ e_goto (ocol, sline++);
+ e_putline (line);
+ }
+}