diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /pkg/ecl/eparam.c | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'pkg/ecl/eparam.c')
-rw-r--r-- | pkg/ecl/eparam.c | 2156 |
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, <, &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); + } +} |