
/* "VIEW", a data viewing program,
   Copyright (C) 1987, 1990 California Institute of Technology.
   Original authors: Dave Gillespie, port by Rick Koshi
   Unix Port Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425/ CU Boulder/Boulder CO 91125. 


This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (Version 1, Feb 1989).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

/* Output from p2c, the Pascal-to-C translator */
/* From input file "viewctrl.text" */


/* The View program
   by Dave Gillespie
 */



/*caged_date='I{ Last edit by $U on $X $]'*/
/* Last edit by dave on Feb 15, 1988 3:09 pm */
/* Last edit by dave on Jan 26, 1988 3:15 am */
/* Last edit by dave on Nov 27, 1987 6:15 pm */
/* Last edit by dave on Nov 27, 1987 5:32 pm */
/* Last edit by dave on Nov 27, 1987 3:32 pm */
/* Last edit by dave on Nov 26, 1987 6:23 pm */
/* Last edit by dave on Nov 26, 1987 6:20 pm */
/* Last edit by dave on Nov 26, 1987 5:35 pm */
/* Last edit by dave on Nov 26, 1987 5:33 pm */
/* Last edit by dave on Nov 24, 1987 3:45 pm */
/* Last edit by dave on Nov 24, 1987 3:39 pm */
/* Last edit by dave on Nov 24, 1987 3:35 pm */
/* Last edit by dave on Nov 11, 1987 3:15 am */
/* Last edit by dave on Nov 9, 1987 11:00 pm */











#include "global.h"


#define VIEWCTRL_G
#include "viewctrl.h"




#ifndef NUMEX_H
#include <p2c/numex.h>
#endif

#ifndef REGEX_H
#include <p2c/regex.h>
#endif

#ifndef NEWASM_H
#include <p2c/newasm.h>
#endif

#ifndef NEWKBD_H
#include <p2c/newkbd.h>
#endif

#ifndef SYSGLOBALS_H
#include <p2c/sysglobals.h>
#endif

#ifndef MISC_H
#include <p2c/misc.h>
#endif

#ifndef SYSDEVS_H
#include <p2c/sysdevs.h>
#endif

#ifndef FILEPACK_H
#include <p2c/filepack.h>
#endif

#ifndef MYLIB_H
#include <p2c/mylib.h>
#endif

#ifndef NEWCRT_H
#include <p2c/newcrt.h>
#endif

#ifndef NEWCI_H
#include <p2c/newci.h>
#endif

#ifndef VIEWMOD_H
#include "viewmod.h"
#endif

#ifndef VIEWCONF_H
#include "viewconf.h"
#endif


/*$if v_hasdebug$
   $debug$
$end$*/



typedef struct forrec {
  Char *name;
  long index;
  double incr, min, max;
} forrec;

typedef struct wfilerec {
  long tag;
  Char *name;
} wfilerec;


#define wfiletag        12345

#ifndef strdup
extern char *strdup();
#endif

Static Anyptr whilecmd, repeatcmd, forcmd, switchcmd, trycmd;
Static wfilerec *outfilehandle;
Static FILE *outfile;
Static _PROCEDURE savecloseproc;






/* Support for output file */

Static Void close_outfile()
{
  if (outfilehandle != NULL) {
    TRY(try1);
      if (outfile != NULL)
	fclose(outfile);
      outfile = NULL;
    RECOVER(try1);
      if (P_escapecode == -20)
	_Escape(P_escapecode);
    ENDTRY(try1);
  }
  outfilehandle = NULL;
}


Static Void outfilecloseproc()
{
  close_outfile();
  if (savecloseproc.link != NULL)
    (*(Void(*) PP((Anyptr _link)))savecloseproc.proc)(savecloseproc.link);
  else
    (*(Void(*) PV())savecloseproc.proc)();
}


Static Void selectoutfile(wf)
wfilerec **wf;
{
  if ((long)(*wf) >= 0 || (*wf)->tag != wfiletag)
    v_failmsg("Bad output file hook");
  if (outfilehandle == *wf)
    return;
  close_outfile();
  if (outfile != NULL)
    outfile = freopen((*wf)->name, "a", outfile);
  else
    outfile = fopen((*wf)->name, "a");
  if (outfile == NULL)
    _EscIO(FileNotFound);
  outfilehandle = *wf;
}






/* Miscellaneous control commands */


Static Void dobuiltin(buf)
Char *buf;
{
  v_failmsg("Internal error - in dobuiltin");
}


Static Void dosource(buf_)
Char *buf_;
{
  Char buf[256], wrd[256];
  Char STR1[256];

  strcpy(buf, buf_);
  v_strword(buf, wrd);
  v_checktoomany(buf);
  if (!v_pushinput_file(wrd, true)) {
    sprintf(STR1, "Error reading file %s", wrd);
    v_failmsg(STR1);
  }
}



Static Void dodokbd(buf)
Char *buf;
{
  v_pushinput_stdin();
  v_doinputsession(v_viewprompt);
}


Static Void dohistory(buf)
Char *buf;
{
  long i, n, num;
  na_strlist *l1;

  if (*buf == '\0')
    n = 20;
  else {
    if (!v_parseinteger(buf, &n))
      v_fail();
  }
  l1 = v_history;
  num = 0;
  while (l1 != NULL) {
    num++;
    l1 = l1->next;
  }
  if (n < 0)
    n = 0;
  else if (n > num)
    n = num;
  l1 = v_history;
  for (i = n + 1; i <= num; i++)
    l1 = l1->next;
  i = n;
  while (l1 != NULL) {
    n--;
    printf("%4ld  %s\n", num - n, l1->s);
    l1 = l1->next;
  }
}



Static Void dotypeahead(buf_)
Char *buf_;
{
  Char buf[256];
  long i, j;
  Char STR1[256];
  Char STR2[256];

  strcpy(buf, buf_);
  strcpy(STR1, strltrim(strrtrim(strcpy(STR2, buf))));
  strcpy(buf, STR1);
  i = 1;
  while (i <= strlen(buf)) {
    if (buf[i - 1] != '\\') {
      i++;
      continue;
    }
    strcpy(buf + i - 1, buf + i);
    if (i <= strlen(buf)) {
      switch (buf[i - 1]) {

      case 'n':
      case 'N':
	buf[i - 1] = '\015';
	break;

      case 'e':
      case 'E':
	buf[i - 1] = '\033';
	break;

      default:
	if (isdigit(buf[i - 1])) {
	  j = buf[i - 1] - 48;
	  while (i < strlen(buf) && isdigit(buf[i]) && j < 26) {
	    j = j * 10 + buf[i] - 48;
	    strcpy(buf + i, buf + i + 1);
	  }
	  buf[i - 1] = (Char)j;
	}
	break;
      }
    }
    i++;
  }
  nk_ungetstr(buf);
}



Static Void douse(buf_)
Char *buf_;
{
  Char buf[256], fn[256], tn[256], suf[256];
  Char STR1[256];

  strcpy(buf, buf_);
  v_strword(buf, fn);
  if (*fn == '\0')
    v_failmsg("File name required");
  v_strword(buf, tn);
  if (*tn == '\0')
    sprintf(suf, "tool file %s", fn);
  else
    sprintf(suf, "tool %s", tn);
  v_checktoomany(buf);
  switch (v_use(fn, tn)) {

  case 1:
    sprintf(STR1, "Installed %s", suf);
    v_logwriteln(STR1);
    break;

  case 0:
    v_writeerror();
    sprintf(STR1, "Could not install %s", suf);
    v_logwriteln(STR1);
    v_fail();
    break;
  }
}



Static Void doset(buf_)
Char *buf_;
{
  Char buf[256], wrd[256];
  v_paramrec *pp;
  Char STR2[256];
  Char STR3[256];

  strcpy(buf, buf_);
  if (*buf == '\0') {
    pp = v_parambase;
    while (pp != NULL) {
      sprintf(STR3, "%s = %s", pp->name, v_getstrparam(STR2, pp));
      v_logwriteln(STR3);
      pp = pp->next;
    }
    return;
  }
  v_strword(buf, wrd);
  pp = v_findparam(wrd);
  v_needsep(buf, '=');
  v_setstrparam(pp, buf);
}




Static Char *formatreal(Result, r, fmt1, fmt2)
Char *Result;
double r;
long fmt1, fmt2;
{
  Char wrd[256];
  long i, j, maxlen, expon;
  boolean carry, minus;
  Char *STR1, STR2[256], STR3[256];

  *wrd = '\0';
  if (fmt2 < 0) {
    if (fmt1 < 0) {
      sprintf(STR2, "%g", r);
      strlower(wrd, STR2);
      return strcpy(Result, wrd);
    }
    minus = (r < 0);
    if (minus) {
      r = -r;
      fmt1--;
    }
    if (r < 1e-2 || r >= 1e9) {
      sprintf(wrd, "%50.43E", r);
      i = strlen(wrd) + 1;
      i = strposc(wrd, 'E', 1L);
      if (i == 0)
	expon = 0;
      else {
	expon = strtol(wrd + i, &STR1, 10);
	j = STR1 - wrd + 1;
	wrd[i - 1] = '\0';
/* p2c: viewctrl.text, line 309:
 * Note: Modification of string length may translate incorrectly [146] */
	if (expon < 0)
	  fmt1--;
	if (labs((double)(expon)) >= 10) {
	  if (labs((double)(expon)) >= 100)
	    fmt1 -= 4;
	  else
	    fmt1 -= 3;
	} else
	  fmt1 -= 2;
      }
    } else {
      sprintf(wrd, "%50.18f", r);
      i = strlen(wrd) + 1;
      expon = 0;
    }
    if (strends(wrd, " "))
      strcpy(wrd, strrtrim(strcpy(STR2, wrd)));
    if (*wrd == ' ') {
      strcpy(STR2, strltrim(wrd));
      strcpy(wrd, STR2);
    }
    if (strlen(wrd) > fmt1) {
      i = strposc(wrd, '.', 1L);
      maxlen = P_imax2(fmt1, i);
      carry = (wrd[maxlen] >= '5');
      wrd[maxlen] = '\0';
/* p2c: viewctrl.text, line 335:
 * Note: Modification of string length may translate incorrectly [146] */
      while (carry && maxlen >= 1) {
	if (wrd[maxlen - 1] == '.') {
	  maxlen--;
	  continue;
	}
	wrd[maxlen - 1]++;
	carry = (wrd[maxlen - 1] > '9');
	if (!carry)
	  break;
	wrd[maxlen - 1] = '0';
	maxlen--;
      }
      if (carry)
	sprintf(wrd, "1%s", strcpy(STR2, wrd));
    }
    while (wrd[strlen(wrd) - 1] == '0')
      wrd[strlen(wrd) - 1] = '\0';
    if (wrd[strlen(wrd) - 1] == '.')
      wrd[strlen(wrd) - 1] = '\0';
    if (minus) {
      sprintf(wrd, "-%s", strcpy(STR2, wrd));
      fmt1++;
    }
    if (strlen(wrd) < fmt1) {
      sprintf(STR3, "%*s%s", (int)(fmt1 - strlen(wrd)), "", wrd);
      strcpy(wrd, STR3);
    }
    if (expon != 0) {
      strcat(wrd, "e");
      sprintf(wrd + strlen(wrd), "%ld", expon);
    }
    return strcpy(Result, wrd);
  }
  if (fmt1 >= 0) {
    sprintf(wrd, "%*.*f", (int)fmt1, (int)fmt2, r);
    i = strlen(wrd) + 1;
    return strcpy(Result, wrd);
  }
  sprintf(wrd, "%40.*f", (int)fmt2, r);
  i = strlen(wrd) + 1;
  if (fmt2 == 0)
    strcat(wrd, ".");
  strcpy(STR2, strltrim(wrd));
  strcpy(wrd, STR2);
  return strcpy(Result, wrd);
}


/* Local variables for doprint: */
struct LOC_doprint {
  Char lbuf[256], strname[256];
  wfilerec *wf;
  boolean moreflag;
} ;

Local Void writebuf(LINK)
struct LOC_doprint *LINK;
{
  v_curverec *cp;
  Char STR1[256];

  if (*LINK->strname != '\0') {
    if (LINK->moreflag) {
      cp = v_findcurve(LINK->strname);
      if (cp != NULL && cp->sval != NULL)
	sprintf(LINK->lbuf, "%s%s", cp->sval, strcpy(STR1, LINK->lbuf));
    }
    v_assigncurvestr(LINK->lbuf, LINK->strname);
    return;
  }
  if (LINK->wf != NULL) {
    selectoutfile(&LINK->wf);
    fputs(LINK->lbuf, outfile);
    if (!LINK->moreflag)
      putc('\n', outfile);
    return;
  }
  if (LINK->moreflag)
    fputs(LINK->lbuf, stdout);
  else
    v_logwriteln(LINK->lbuf);
}


Static Void doprint(buf_)
Char *buf_;
{
  struct LOC_doprint V;
  Char buf[256], wrd[256];
  na_long handle;
  ne_nexrec *nex, nexr;
  long i, fmt1, fmt2;
  boolean wasnum;
  Char STR1[256];

  strcpy(buf, buf_);
  V.moreflag = false;
  V.wf = NULL;
  *V.strname = '\0';
  while (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, wrd);
    if (strcicmp(wrd, "MORE") == 0)
      V.moreflag = true;
    else if (strcicmp(wrd, "FILE") == 0) {
      v_needsep(buf, '=');
      v_strword(buf, wrd);
      if (!v_parseinteger(wrd, (long*)(&handle)))
	v_fail();
      V.wf = (wfilerec *)handle;
      if ((long)handle >= 0 || V.wf->tag != wfiletag)
	v_failmsg("Bad output file handle");
    } else if (strcicmp(wrd, "STR") == 0) {
      v_needsep(buf, '=');
      v_strword(buf, V.strname);
    } else
      v_unrecognizedoption();
    v_needsep(buf, ']');
  }
  *V.lbuf = '\0';
  wasnum = false;
  do {
    v_exstrword(buf, wrd);
    if (*wrd == '\0') {
      v_checktoomany(buf);
      writebuf(&V);
      v_halt();
    }
    v_buildsymtab(0L);
    ne_compile(wrd, &nex, &v_nedesc);
    v_checkneeds(nex);
    ne_evaluate(nex, &nexr);
    ne_dispose(&nex);
    fmt1 = -1;
    fmt2 = -1;
    if (*buf == ':') {
      v_needsep(buf, ':');
      if (*buf != ':') {
	v_exstrword(buf, wrd);
	if (!v_parseinteger(wrd, &fmt1))
	  v_fail();
      }
      if (*buf == ':') {
	v_needsep(buf, ':');
	v_exstrword(buf, wrd);
	if (!v_parseinteger(wrd, &fmt2))
	  v_fail();
      }
    }
    if (nexr.op < 32 &&
	((1L << nexr.op) & ((1L << ((long)ne_ic)) | (1L << ((long)ne_rc)))) != 0) {
      if (wasnum)
	strcat(V.lbuf, " ");
      wasnum = true;
    } else
      wasnum = false;
    switch ((ne_opkind)nexr.op) {

    case ne_ic:
      strcat(V.lbuf, formatreal(STR1, (double)nexr.UU.i, fmt1, fmt2));
      break;

    case ne_rc:
      if (nexr.UU.r == v_badvalue) {
	if (fmt1 <= 0)
	  strcat(V.lbuf, "(none)");
	else
	  sprintf(V.lbuf + strlen(V.lbuf), "%*sX", (int)(fmt1 - 1), "");
      } else
	strcat(V.lbuf, formatreal(STR1, nexr.UU.r, fmt1, fmt2));
      break;

    case ne_sc:
      strcat(V.lbuf, nexr.UU.s);
      for (i = strlen(nexr.UU.s) + 1; i <= fmt1; i++)
	strcat(V.lbuf, " ");
      strdispose(&nexr.UU.s);
      break;

    case ne_error:
      if (*V.lbuf != '\0')
	writebuf(&V);
      v_failneerr((ne_errorkind)nexr.UU.err);
      break;

    default:
      strcat(V.lbuf, "<bad type>");
      break;
    }
  } while (true);
}  /*doprint*/



Static Void doecho(buf)
Char *buf;
{
  v_logwriteln(buf);
}



Static Void doquit(buf_)
Char *buf_;
{
  Char buf[256], wrd[256];
  long i, n;

  strcpy(buf, buf_);
  if (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, wrd);
    v_needsep(buf, ']');
  } else
    *wrd = '\0';
  n = 1;
  if (*buf != '\0' && !v_parseinteger(buf, &n))
    v_fail();
  for (i = 1; i <= n; i++) {
    if (*wrd == '\0')
      v_popinput();
    else if (strcicmp(wrd, "file") == 0)
      v_popinput_file();
    else if (strcicmp(wrd, "proc") == 0)
      v_popinput_proc();
    else if (strcicmp(wrd, "kbd") == 0)
      v_popinput_kbd();
    else if (strcicmp(wrd, "all") == 0)
      v_setup_stdin();
    else if (strcicmp(wrd, "view") == 0) {
      v_exitflag = true;
      v_setup_stdin();
    } else
      v_unrecognizedoption();
  }
}



Static Void doabort(buf)
Char *buf;
{
  v_setup_stdin();
}


Static Void dobye(buf)
Char *buf;
{
  v_exitflag = true;
  v_setup_stdin();
}


Static Void dohelp(buf)
Char *buf;
{
  v_givehelp(buf);
}






/* Control constructs */


Static Void skipnesting(starting, ending)
Char *starting, *ending;
{
  Char wrd[256];
  long nest;
  Char STR1[256];

  nest = 0;
  v_scanword(wrd, nest);
  while (nest > 0 || strcmp(wrd, ending)) {
    if (!strcmp(wrd, ending))
      nest--;
    else if (!strcmp(wrd, starting))
      nest++;
    else if (*wrd == '\0') {
      sprintf(STR1, "Missing %s", ending);
      v_failmsg(STR1);
    }
    v_skipln();
    v_scanword(wrd, nest);
  }
}









/* IF constructs */


Static Void eattrailer(buf, tr)
Char *buf;
Char *tr;
{
  long i;
  Char STR1[256];

  if (!strciends(buf, tr))
    return;
  i = strlen(buf) - strlen(tr);
  if (i != 0 && isalnum(tr[0]) && buf[i - 1] != '"' && buf[i - 1] != '\'' &&
      buf[i - 1] != ']' && buf[i - 1] != ')' && buf[i - 1] != ' ')
    return;
  buf[i] = '\0';
/* p2c: viewctrl.text, line 645:
 * Note: Modification of string length may translate incorrectly [146] */
  if (strends(buf, " "))
    strcpy(buf, strrtrim(strcpy(STR1, buf)));
}


Static Void handleiffail()
{
  Char buf[256], wrd[256];
  boolean done;
  long nest;

  nest = 0;
  do {
    v_scanword(wrd, nest);
    while (nest > 0 || (strcmp(wrd, "ENDIF") && strcmp(wrd, "ELSE") &&
			strcmp(wrd, "ELSEIF"))) {
      if (!strcmp(wrd, "ENDIF"))
	nest--;
      else if (!strcmp(wrd, "IF"))
	nest++;
      else if (*wrd == '\0')
	v_failmsg("Missing ENDIF");
      v_skipln();
      v_scanword(wrd, nest);
    }
    done = true;
    if (!strcmp(wrd, "ELSEIF")) {
      v_readln("", buf);
      v_doexpansions(buf, 0L);
      strword(buf, wrd);
      eattrailer(buf, "then");
      if (!v_parsecondition(buf, &done))
	v_fail();
    } else
      v_skipln();
  } while (!done);
}


Static Void doif(buf_)
Char *buf_;
{
  Char buf[256];
  boolean flag;

  strcpy(buf, buf_);
  eattrailer(buf, "then");
  if (!v_parsecondition(buf, &flag))
    v_fail();
  if (!flag)
    handleiffail();
}


Static Void doelse(buf)
Char *buf;
{
  skipnesting("IF", "ENDIF");
  v_skipln();
}


Static Void doendif(buf)
Char *buf;
{
  /* nothing to do */
}






/* SWITCH construct */


Static Void switchbreakhook(cp)
v_controlrec *cp;
{
  skipnesting("SWITCH", "ENDSWITCH");
  v_skipln();
  v_popcontrol();
}


Static Void doswitch(buf_)
Char *buf_;
{
  Char buf[256], sval[256], sval2[256], ibuf[256], rex[256];
  long nest;
  boolean found, caseins;
  v_controlrec *cp;

  strcpy(buf, buf_);
  eattrailer(buf, "of");
  caseins = false;
  while (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, sval);
    if (strcicmp(sval, "CI") == 0)
      caseins = true;
    else
      v_unrecognizedoption();
    v_needsep(buf, ']');
  }
  if (!v_parsestr(buf, sval))
    v_fail();
  nest = 0;
  v_pushcontrol(&cp);
  cp->kind = switchcmd;
  cp->breakhook.proc = (Anyptr)switchbreakhook;
  cp->breakhook.link = (Anyptr)NULL;
  cp->canbreak = true;
  found = false;
  do {
    v_scanword(ibuf, nest);
    if (*ibuf == '\0')
      v_failmsg("Missing ENDSWITCH");
    else if (!strcmp(ibuf, "SWITCH"))
      nest++;
    else if (!strcmp(ibuf, "ENDSWITCH"))
      nest--;
    else if (nest > 0)
      v_skipln();
    else {
      if (!strcmp(ibuf, "CASE")) {
	v_readln("", ibuf);
	v_doexpansions(buf, 0L);
	eattrailer(ibuf, ":");
	strword(ibuf, sval2);
	if (v_parsestr(ibuf, sval2)) {
	  if (!strcmp(sval, sval2) || caseins && strcicmp(sval, sval2) == 0)
	    found = true;
	}
      } else if (!strcmp(ibuf, "PCASE")) {
	v_readln("", ibuf);
	v_doexpansions(buf, 0L);
	eattrailer(ibuf, ":");
	strword(ibuf, sval2);
	v_strword(ibuf, sval2);
	if (caseins)
	  re_cicompile(sval2, rex, re_shellchars);
	else
	  re_compile(sval2, rex, re_shellchars);
	if (re_compare(sval, rex))
	  found = true;
      } else if (!strcmp(ibuf, "RCASE")) {
	v_readln("", ibuf);
	v_doexpansions(buf, 0L);
	eattrailer(ibuf, ":");
	strword(ibuf, sval2);
	v_strword(ibuf, sval2);
	if (caseins)
	  re_cicompile(sval2, rex, "");
	else
	  re_compile(sval2, rex, "");
	if (re_compare(sval, rex))
	  found = true;
      } else if (!strcmp(ibuf, "OTHERWISE")) {
	v_skipln();
	found = true;
      } else
	v_skipln();
    }
  } while (!(found || nest < 0));
}


Static Void docase(buf)
Char *buf;
{
  /* nothing to do */
}


Static Void doendswitch(buf)
Char *buf;
{
  if (v_topcontrolkind() != switchcmd)
    v_misplacedcmd();
  v_popcontrol();
}







/* WHILE loops */


Static Void handlewhilefail()
{
  skipnesting("WHILE", "ENDWHILE");
  v_skipln();
}


Static Void whilepophook(cp)
v_controlrec *cp;
{
  strdispose((Char **)((Char **)(&cp->info.U99.l1)));
}


Static Void whilebreakhook(cp)
v_controlrec *cp;
{
  handlewhilefail();
  v_popcontrol();
}


Static Void whilecontinuehook(cp)
v_controlrec *cp;
{
  v_gotoinput(cp->mark);
}


Static Void dowhile(buf_)
Char *buf_;
{
  Char buf[256];
  v_controlrec *cp;
  boolean flag;

  strcpy(buf, buf_);
  eattrailer(buf, "do");
  if (*buf == '\0')
    flag = true;
  else if (!v_parsecondition(buf, &flag))
    v_fail();
  if (!flag) {
    handlewhilefail();
    return;
  }
  v_pushcontrol(&cp);
  cp->kind = whilecmd;
  if (*buf != '\0')
    *(Char **)((Char **)(&cp->info.U99.l1)) = strdup(buf);
  cp->pophook.proc = (Anyptr)whilepophook;
  cp->pophook.link = (Anyptr)NULL;
  cp->breakhook.proc = (Anyptr)whilebreakhook;
  cp->breakhook.link = (Anyptr)NULL;
  cp->canbreak = true;
  cp->continuehook.proc = (Anyptr)whilecontinuehook;
  cp->continuehook.link = (Anyptr)NULL;
  cp->cancontinue = true;
}


Static Void doendwhile(buf)
Char *buf;
{
  boolean flag;

  if (v_topcontrolkind() != whilecmd)
    v_misplacedcmd();
  if (v_ctrlstack->info.U1.i1 == 0)
    flag = true;
  else if (!v_parsecondition((Char *)v_ctrlstack->info.U99.l1, &flag))
    v_fail();
  if (flag) {
    v_gotoinput(v_ctrlstack->mark);
    v_skipln();
  } else
    v_popcontrol();
}






/* REPEAT loops */


Static Void repeatbreakhook(cp)
v_controlrec *cp;
{
  skipnesting("REPEAT", "UNTIL");
  v_skipln();
  v_popcontrol();
}


Static Void repeatcontinuehook(cp)
v_controlrec *cp;
{
  skipnesting("REPEAT", "UNTIL");
}


Static Void dorepeat(buf)
Char *buf;
{
  v_controlrec *cp;

  v_pushcontrol(&cp);
  cp->kind = repeatcmd;
  cp->breakhook.proc = (Anyptr)repeatbreakhook;
  cp->breakhook.link = (Anyptr)NULL;
  cp->canbreak = true;
  cp->continuehook.proc = (Anyptr)repeatcontinuehook;
  cp->continuehook.link = (Anyptr)NULL;
  cp->cancontinue = true;
}


Static Void dountil(buf_)
Char *buf_;
{
  Char buf[256];
  boolean flag;

  strcpy(buf, buf_);
  eattrailer(buf, ";");
  if (v_topcontrolkind() != repeatcmd)
    v_misplacedcmd();
  if (*buf == '\0')
    flag = false;
  else if (!v_parsecondition(buf, &flag))
    v_fail();
  if (!flag) {
    v_gotoinput(v_ctrlstack->mark);
    v_skipln();
  } else
    v_popcontrol();
}






/* FOR loops */


Static Void forbreakhook(cp)
v_controlrec *cp;
{
  skipnesting("FOR", "ENDFOR");
  v_skipln();
  v_popcontrol();
}


Static Void forcontinuehook(cp)
v_controlrec *cp;
{
  skipnesting("FOR", "ENDFOR");
}


Static Void forpophook(cp)
v_controlrec *cp;
{
  forrec *forp;

  forp = (forrec *)cp->info.U99.l1;
  strdispose(&forp->name);
  Free(forp);
}


Static Void dofor(buf_)
Char *buf_;
{
  Char buf[256];
  v_controlrec *cp;
  forrec forr, *forp;
  Char name[256], units[256], wrd[256];

  strcpy(buf, buf_);
  eattrailer(buf, "do");
  v_strword(buf, name);
  v_needsep(buf, '=');
  v_exstrword(buf, wrd);
  if (!v_parseureal(wrd, &forr.min, units))
    v_fail();
  v_needsep(buf, ':');
  v_exstrword(buf, wrd);
  if (!v_parsereal(wrd, &forr.max))
    v_fail();
  if (*buf == ':') {
    v_needsep(buf, ':');
    v_exstrword(buf, wrd);
    if (!v_parsereal(wrd, &forr.incr))
      v_fail();
    if (forr.incr == 0.0)
      v_failmsg("Increment must be nonzero");
  } else
    forr.incr = 1.0;
  v_checktoomany(buf);
  forr.index = 0;
  if ((forr.incr <= 0 || forr.min > forr.max) &&
      (forr.incr >= 0 || forr.min < forr.max)) {
    skipnesting("FOR", "ENDFOR");
    v_skipln();
    return;
  }
  v_addcurveconst(forr.min, units, name);
  forr.name = strdup(name);
  forp = (forrec *)Malloc(sizeof(forrec));
  *forp = forr;
  v_pushcontrol(&cp);
  cp->kind = forcmd;
  cp->info.U99.l1 = (Anyptr)forp;
  cp->pophook.proc = (Anyptr)forpophook;
  cp->pophook.link = (Anyptr)NULL;
  cp->breakhook.proc = (Anyptr)forbreakhook;
  cp->breakhook.link = (Anyptr)NULL;
  cp->canbreak = true;
  cp->continuehook.proc = (Anyptr)forcontinuehook;
  cp->continuehook.link = (Anyptr)NULL;
  cp->cancontinue = true;
}


Static Void doendfor(buf)
Char *buf;
{
  forrec *forp;
  double value;

  if (v_topcontrolkind() != forcmd)
    v_misplacedcmd();
  forp = (forrec *)v_ctrlstack->info.U99.l1;
  forp->index++;
  value = forp->min + forp->index * forp->incr;
  if ((forp->incr <= 0 || value > forp->max) &&
      (forp->incr >= 0 || value < forp->max)) {
    v_popcontrol();
    return;
  }
  v_assigncurveconst(value, forp->name);
  v_gotoinput(v_ctrlstack->mark);
  v_skipln();
}







/* TRY mechanism */


Static Void tryrecoverhook(cp)
v_controlrec *cp;
{
  Char wrd[256];
  long nest;

  v_gotoinput(cp->mark);
  v_popcontrol();
  v_skipln();
  v_setstrparam(v_p_errormsg, v_lasterrormsg);
  v_setstrparam(v_p_errorstr, v_lasterrorstr);
  v_clearerror();
  nest = 0;
  v_scanword(wrd, nest);
  while (nest > 0 || strcmp(wrd, "RECOVER")) {
    if (!strcmp(wrd, "TRY"))
      nest++;
    else if (!strcmp(wrd, "ENDTRY")) {
      nest--;
      if (nest < 0)
	v_failmsg("Missing RECOVER");
    } else if (*wrd == '\0')
      v_failmsg("Missing ENDTRY");
    v_skipln();
    v_scanword(wrd, nest);
  }
  v_skipln();
}


Static Void dotry(buf)
Char *buf;
{
  v_controlrec *cp;

  v_pushcontrol(&cp);
  cp->kind = trycmd;
  cp->recoverhook.proc = (Anyptr)tryrecoverhook;
  cp->recoverhook.link = (Anyptr)NULL;
  cp->canrecover = true;
}


Static Void dorecover(buf)
Char *buf;
{
  if (v_topcontrolkind() != trycmd)
    v_misplacedcmd();
  v_popcontrol();
  skipnesting("TRY", "ENDTRY");
  v_skipln();
}


Static Void doendtry(buf)
Char *buf;
{
  /* nothing to do */
}







/* BREAK and CONTINUE commands */


Static Void dobreak(buf_)
Char *buf_;
{
  Char buf[256];
  v_controlrec *cp;
  long n, n1;

  strcpy(buf, buf_);
  if (*buf == '\0')
    n = 1;
  else if (!v_parseinteger(buf, &n))
    v_fail();
  cp = v_ctrlstack;
  n1 = n;
  while (cp != NULL && n1 > 0) {
    if (cp->canbreak)
      n1--;
    if (n1 > 0)
      cp = cp->next;
  }
  if (cp == NULL)
    v_misplacedcmd();
  while (v_ctrlstack != cp && v_ctrlstack != NULL)
    v_popcontrol();
  if (n > 1) {  /*make it easier for skipnesting*/
    v_gotoinput(cp->mark);
    v_skipln();
  } else
    v_gotoinputfile(cp->mark);
  if (cp->breakhook.link != NULL)
    (*(Void(*) PP((v_controlrec *cp, Anyptr _link)))cp->breakhook.proc)(cp,
      cp->breakhook.link);
  else
    (*(Void(*) PP((v_controlrec *cp)))cp->breakhook.proc)(cp);
}



Static Void docontinue(buf_)
Char *buf_;
{
  Char buf[256];
  v_controlrec *cp;
  long n, n1;

  strcpy(buf, buf_);
  if (*buf == '\0')
    n = 1;
  else if (!v_parseinteger(buf, &n))
    v_fail();
  cp = v_ctrlstack;
  n1 = n;
  while (cp != NULL && n1 > 0) {
    if (cp->cancontinue)
      n1--;
    if (n1 > 0)
      cp = cp->next;
  }
  if (cp == NULL)
    v_misplacedcmd();
  while (v_ctrlstack != cp && v_ctrlstack != NULL)
    v_popcontrol();
  if (n > 1) {
    v_gotoinput(cp->mark);
    v_skipln();
  } else
    v_gotoinputfile(cp->mark);
  if (cp->continuehook.link != NULL)
    (*(Void(*) PP((v_controlrec *cp, Anyptr _link)))cp->continuehook.proc)(cp,
      cp->continuehook.link);
  else
    (*(Void(*) PP((v_controlrec *cp)))cp->continuehook.proc)(cp);
}






/* DEFINE mechanism */


Static Void dodefine(buf_)
Char *buf_;
{
  Char buf[256], name[256], endcmd[256];
  na_strlist *body;
  boolean isbefore, isafter;

  strcpy(buf, buf_);
  isbefore = false;
  isafter = false;
  *endcmd = '\0';
  while (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, name);
    if (strcicmp(name, "BEFORE") == 0)
      isbefore = true;
    else if (strcicmp(name, "AFTER") == 0)
      isafter = true;
    else if (strcicmp(name, "BLOCK") == 0) {
      if (*buf == ':') {
	v_needsep(buf, ':');
	v_strword(buf, endcmd);
      } else
	strcpy(endcmd, "*");
    } else
      v_unrecognizedoption();
    v_needsep(buf, ']');
  }
  v_strword(buf, name);
  if (*name == '\0')
    v_failmsg("Missing name for ~~");
  if (!strcmp(endcmd, "*"))
    sprintf(endcmd, "end%s", name);
  v_scanbody(&body, "DEFINE", "ENDDEF");
  if (!isbefore && !isafter)
    v_undefine(name);
  if (isbefore)
    v_definebefore(name, buf, body);
  else
    v_defineafter(name, buf, body);
  if (*endcmd != '\0') {
    v_isctrl();
    v_isblockcmd(endcmd);
  }
}



Static Void doenddef(buf)
Char *buf;
{
  v_misplacedcmd();
}



Static Void doreturn(buf)
Char *buf;
{
  v_popinput_proc();
}



Static Void dolocal(buf_)
Char *buf_;
{
  Char buf[256], wrd[256];

  strcpy(buf, buf_);
  do {
    v_strword(buf, wrd);
    if (*wrd != '\0') {
      v_addlocalcurve(wrd);
      if (*buf == '=') {
	v_assignment(wrd, buf);
	v_halt();
      }
    }
  } while (*wrd != '\0');
  v_checktoomany(buf);
}


Static Void dolocaldef(buf_)
Char *buf_;
{
  Char buf[256], wrd[256], wrd2[256];

  strcpy(buf, buf_);
  do {
    v_strword(buf, wrd);
    if (*wrd != '\0') {
      v_addlocaldef(wrd);
      if (*buf == '=') {
	v_needsep(buf, '=');
	v_strword(buf, wrd2);
	v_addalias(wrd, wrd2);
	v_halt();
      }
    }
  } while (*wrd != '\0');
  v_checktoomany(buf);
}


Static Void dolocalparam(buf_)
Char *buf_;
{
  Char buf[256], wrd[256];

  strcpy(buf, buf_);
  do {
    v_strword(buf, wrd);
    if (*wrd != '\0') {
      v_addlocalparam(wrd);
      if (*buf == '=') {
	v_needsep(buf, '=');
	v_setstrparam(v_findparam(wrd), buf);
	v_halt();
      }
    }
  } while (*wrd != '\0');
  v_checktoomany(buf);
}



Static Void doaddhelp(buf_)
Char *buf_;
{
  Char buf[256];

  strcpy(buf, buf_);
  if (*buf == '>')
    strcpy(buf, buf + 1);
  v_addhelp(buf);
}



Static Void doundefine(buf_)
Char *buf_;
{
  Char buf[256], wrd[256];

  strcpy(buf, buf_);
  v_eof();   /*optimization in case a proc undefines itself*/
  do {
    v_strword(buf, wrd);
    if (*wrd != '\0')
      v_undefine(wrd);
  } while (*wrd != '\0');
  v_checktoomany(buf);
}



Static Void doalias(buf_)
Char *buf_;
{
  Char buf[256], nname[256], oname[256];

  strcpy(buf, buf_);
  v_strword(buf, nname);
  v_needsep(buf, '=');
  v_strword(buf, oname);
  v_checktoomany(buf);
  v_addalias(nname, oname);
}



Static Void doeditdef(buf)
Char *buf;
{
  Char tempfn[256];

  sprintf(tempfn, "/tmp/vtmp_%ld.view", newci_fullseconds() % 1000);
/* p2c: viewctrl.text, line 1405:
 * Note: Using % for possibly-negative arguments [317] */
  v_savecmds(tempfn, buf);
  v_closelog();
  newci_fulleditescape(tempfn, "S", 8L, 1L);
  if (!v_sourcefile(tempfn, false)) {
    v_writeerror();
    v_failmsg("Unable to re-read editing file");
  }
        unlink(tempfn);
}







/* Error reporting */


Static Void doerror(buf)
Char *buf;
{
  v_writeerror();
  strcpy(v_lasterrormsg, buf);
  strcpy(v_lasterrorstr, buf);
  v_writeerror();
}




Static Void doferror(buf)
Char *buf;
{
  if (*buf != '\0')
    v_errormsg(buf, true);
  v_fail();
}



Static Void docerror(buf)
Char *buf;
{
  if (*buf != '\0') {
    v_writeerror();
    strcpy(v_lasterrormsg, buf);
    strcpy(v_lasterrorstr, buf);
  }
  v_fail();
}






/* Reading data */


/* Note: this stuff requires 64-bit real variables for cp^.yval! */
Static Void doresetfile(buf_)
Char *buf_;
{
  Char buf[256], vname[256], fname[256], wrd[256];
  na_long handle;
  Char STR2[256];

  strcpy(buf, buf_);
  v_strword(buf, vname);
  v_needsep(buf, '=');
  v_exstrword(buf, wrd);
  v_checktoomany(buf);
  if (!v_parsestr(wrd, fname))
    v_fail();
  handle = (na_long)v_getfile(fname, false);
  if ((na_strlistrec *)handle == NULL) {
    sprintf(STR2, "File %s not found", fname);
    v_failmsg(STR2);
  }
  v_assigncurveconst((double)((long)handle), vname);
}



Static Void readoptions(buf, optional, expand, default_, fvar)
Char *buf;
boolean *optional, *expand, *default_;
Char *fvar;
{
  Char wrd[256];

  *optional = false;
  *expand = false;
  *default_ = false;
  *fvar = '\0';
  while (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, wrd);
    if (strcicmp(wrd, "OPT") == 0)
      *optional = true;
    else if (strcicmp(wrd, "EXP") == 0)
      *expand = true;
    else if (strcicmp(wrd, "DEF") == 0)
      *default_ = true;
    else if (strcicmp(wrd, "FILE") == 0) {
      v_needsep(buf, '=');
      v_strword(buf, fvar);
    } else
      v_unrecognizedoption();
    v_needsep(buf, ']');
  }
}



Static Void doreadnum(buf_)
Char *buf_;
{
  Char buf[256], names[256], buf2[256], buf3[256], wrd[256], fvar[256];
  v_curverec *cp;
  long i, num;
  double rbuf[100];
  boolean good, optional, expand, default_;
  Char STR2[256], STR3[256];

  strcpy(buf, buf_);
  readoptions(buf, &optional, &expand, &default_, fvar);
  v_fixstdin();
  strcpy(names, buf);
  num = 0;
  *buf2 = '\0';
  do {
    v_strword(buf, wrd);
    if (*wrd != '\0') {
      if (default_) {
	if (*buf2 != '\0')
	  strcat(buf2, " ");
	cp = v_findcurve(wrd);
	if (cp == NULL || cp->base != NULL || cp->sval != NULL)
	  strcat(buf2, "0");
	else
	  sprintf(buf2 + strlen(buf2), "%g", cp->yval);
      }
      num++;
    }
  } while (*wrd != '\0');
  if (*buf == ':')
    v_needsep(buf, ':');
  else {
    v_checktoomany(buf);
    sprintf(buf, "%s?", names);
  }
  do {
    if (!default_)
      *buf2 = '\0';
    sprintf(STR2, "%s ", buf);
    if (!v_readkbddef(buf2, STR2, buf2, fvar))
      v_failmsg("Attempt to read past end of input file");
    if (expand)
      v_doexpansions(buf2, 0L);
    good = true;
    if (*buf2 != '\0' || !optional) {
      strcpy(buf3, buf2);
      i = 1;
      while (good && i <= num && *buf3 != '\0') {
	v_strword(buf3, wrd);
	good = v_parsereal(wrd, &rbuf[i - 1]);
	i++;
      }
      if (good && i > num && *buf3 == '\0') {
	strcpy(buf3, names);
	for (i = 0; i < num; i++) {
	  v_strword(buf3, wrd);
	  v_assigncurveconst(rbuf[i], wrd);
	}
      } else {
	v_writeerror();
	if (*fvar != '\0')
	  v_failmsg("Bad input format in data file");
	good = false;
	printf("Please enter ");
	if (num == 1)
	  printf("a number");
	else
	  printf("%ld numbers", num);
	printf(".\n");
      }
    }
  } while (!good);
  if (*fvar != '\0') {
    sprintf(STR3, "%s %s", buf, buf2);
    v_logwrite(STR3);
  }
}




Static Void doreadln(buf_)
Char *buf_;
{
  Char buf[256], buf2[256], name[256], fvar[256], eofmark[256];
  v_curverec *cp;
  boolean optional, expand, default_, haseof;
  Char STR1[256], STR2[256];

  strcpy(buf, buf_);
  readoptions(buf, &optional, &expand, &default_, fvar);
  v_fixstdin();
  strcpy(buf2, buf);
  v_strword(buf, name);
  if (*name == '\0')
    v_needcurvename();
  haseof = (*buf != '\0' && buf[0] != ':');
  if (haseof)
    v_strword(buf, eofmark);
  if (*buf == ':')
    v_needsep(buf, ':');
  else {
    v_checktoomany(buf);
    sprintf(buf, "%s?", buf2);
  }
  if (default_) {
    cp = v_findcurve(name);
    if (cp == NULL || cp->base != NULL || cp->sval == NULL)
      *buf2 = '\0';
    else
      strcpy(buf2, cp->sval);
  } else
    *buf2 = '\0';
  sprintf(STR1, "%s ", buf);
  if (!v_readkbddef(buf2, STR1, buf2, fvar)) {
    if (haseof)
      strcpy(buf2, eofmark);
    else
      v_failmsg("Attempt to read past end of input file");
  }
  if (expand)
    v_doexpansions(buf2, 0L);
  if (*fvar != '\0') {
    sprintf(STR2, "%s %s", buf, buf2);
    v_logwrite(STR2);
  }
  if (*buf2 != '\0' || !optional)
    v_assigncurvestr(buf2, name);
}






/* Writing data */


Static Void dorewritefile(buf_)
Char *buf_;
{
  Char buf[256];
  boolean neednew, appending;
  Char vname[256], fname[256], wrd[256];
  wfilerec *wf;
  Char STR2[256];

  strcpy(buf, buf_);
  neednew = false;
  appending = false;
  while (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, wrd);
    if (strcicmp(wrd, "NEW") == 0)
      neednew = true;
    else if (strcicmp(wrd, "APPEND") == 0)
      appending = true;
    else
      v_unrecognizedoption();
    v_needsep(buf, ']');
  }
  v_strword(buf, vname);
  v_needsep(buf, '=');
  v_exstrword(buf, wrd);
  v_checktoomany(buf);
  if (!v_parsestr(wrd, fname))
    v_fail();
  if (neednew && access(fname, F_OK) == 0) {
    sprintf(STR2, "File %s already exists", fname);
    v_failmsg(STR2);
  }
  close_outfile();
  if (appending && access(fname, F_OK) == 0) {
    if (outfile != NULL)
      outfile = freopen(fname, "a", outfile);
    else
      outfile = fopen(fname, "a");
    if (outfile == NULL)
      _EscIO(FileNotFound);
  } else {
    if (outfile != NULL)
      outfile = freopen(fname, "w", outfile);
    else
      outfile = fopen(fname, "w");
    if (outfile == NULL)
      _EscIO(FileNotFound);
  }
  wf = (wfilerec *)Malloc(sizeof(wfilerec));
  wf->tag = wfiletag;
  wf->name = strdup(fname);
  outfilehandle = wf;
  v_assigncurveconst((double)((long)wf), vname);
}



Static Void doclosefile(buf)
Char *buf;
{
  wfilerec *wf;
  na_long handle;

  if (!v_parseinteger(buf, (long*)(&handle)))
    v_fail();
  if ((long)handle == 0)
    return;
  if ((long)handle >= 0)
    v_failmsg("Bad file handle");
  wf = (wfilerec *)handle;
  if (wf->tag == wfiletag) {
    if (outfilehandle == wf)
      close_outfile();
    strdispose(&wf->name);
    Free(wf);
  }  /*nothing to do for input files*/
  v_assigncurveconst(0.0, buf);
}






/* Parameters */


Static Void wildcardchproc(pp, val)
v_paramrec *pp;
Char *val;
{
  if (strcicmp(val, "none") == 0) {
    pp->val.U1.i1 = 2;
    strcpy(v_rechars, " ");
    return;
  }
  if (strcicmp(val, "regex") == 0) {
    pp->val.U1.i1 = 1;
    strcpy(v_rechars, re_defchars);
    return;
  }
  if (*val == '\0' || strcicmp(val, "shell") == 0 ||
      strcicmp(val, "unix") == 0) {
    pp->val.U1.i1 = 0;
    strcpy(v_rechars, re_shellchars);
  } else
    v_failmsg("Wildcard must be one of None, Regex, or Shell");
}


Static Void wildcardfmtproc(pp, val)
v_paramrec *pp;
Char *val;
{
  switch (pp->val.U1.i1) {

  case 0:
    strcpy(val, "Shell");
    break;

  case 1:
    strcpy(val, "Regex");
    break;

  default:
    strcpy(val, "None");
    break;
  }
}


Static Void wildcardrestproc(pp, opp)
v_paramrec *pp, *opp;
{
  pp->val = opp->val;
  switch (pp->val.U1.i1) {

  case 0:
    strcpy(v_rechars, re_shellchars);
    break;

  case 1:
    strcpy(v_rechars, re_defchars);
    break;

  case 2:
    strcpy(v_rechars, " ");
    break;
  }
}




Static Void dodefparam(buf_)
Char *buf_;
{
  Char buf[256], wrd[256], extra[256];
  v_paramkindrec *pk;
  v_paramrec *pp;

  strcpy(buf, buf_);
  pk = v_paramstrkind;
  *extra = '\0';
  if (*buf == '[') {
    v_needsep(buf, '[');
    v_strword(buf, wrd);
    if (strcicmp(wrd, "REAL") == 0)
      pk = v_paramrealkind;
    else if (strcicmp(wrd, "INT") == 0)
      pk = v_paramintkind;
    else if (strcicmp(wrd, "BOOL") == 0)
      pk = v_paramboolkind;
    else if (strcicmp(wrd, "FN") == 0) {
      pk = v_paramfnkind;
      if (*buf == '=') {
	v_needsep(buf, '=');
	v_strword(buf, extra);
	strupper(extra, extra);
	if (*extra == '.')
	  strcpy(extra, extra + 1);
      }
    } else if (strcicmp(wrd, "STR") != 0)
      v_unrecognizedoption();
    v_needsep(buf, ']');
  }
  v_strword(buf, wrd);
  v_addparam(wrd, &pp, pk);
  if (*extra != '\0') {
    if (pk == v_paramfnkind)
      *(Char **)((na_strlistrec **)(&pp->val.U99.l2)) = strdup(extra);
  }
  if (*buf == '=') {
    v_needsep(buf, '=');
    v_setstrparam(pp, buf);
  } else
    v_checktoomany(buf);
}








/* Initialization */


Void viewctrl_viewbuiltin()
{
  v_paramkindrec *pk;
  v_paramrec *pp;
  _PROCEDURE TEMP;

  TEMP.proc = (Anyptr)dobuiltin;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("builtin", TEMP, "", "");
  v_isctrl();
  v_addhelp("builtin <command>");
  v_addhelp("  Do the built-in meaning of <command>, ignoring DEFINEs.");
  TEMP.proc = (Anyptr)dosource;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("source", TEMP, "*", "");
  v_addhelp("source <file>");
  v_addhelp("do <file>");
  v_addhelp("  Read commands from a file.");
  v_addalias("do", "source");
  TEMP.proc = (Anyptr)dodokbd;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("dokbd", TEMP, "", "");
  v_addhelp("dokbd");
  v_addhelp("  Read commands from the keyboard.  When user types QUIT");
  v_addhelp("  or hits ctrl-D, input returns to the file or procedure");
  v_addhelp("  that issued this command.");
  TEMP.proc = (Anyptr)douse;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("use", TEMP, "", "");
  v_addhelp("use <filename> [<toolname>]");
  v_addhelp("  Read the View tool stored in <filename>.code or");
  v_addhelp("  <filename>.view. See documentation on viewmod(3) for");
  v_addhelp("  more information.");
  TEMP.proc = (Anyptr)dohistory;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("history", TEMP, "", "");
  v_addhelp("history <n>");
  v_addhelp("  Display last <n> keyboard commands.  Default <n> = 20.");
  TEMP.proc = (Anyptr)dotypeahead;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("typeahead", TEMP, "*", "");
  v_addhelp("typeahead <string>");
  v_addhelp("  Push a string onto the typeahead buffer.");
  TEMP.proc = (Anyptr)doecho;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("echo", TEMP, "", "");
  v_addhelp("echo <message>");
  v_addhelp("  Print <message> on the screen.");
  TEMP.proc = (Anyptr)doprint;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("print", TEMP, "", "");
  v_addhelp("print <expr> <expr> <expr>");
  v_addhelp("  Print values of string or numeric expressions on the screen.");
  v_addhelp("  Expressions may be followed by :<n>, :<n>:<m>, or ::<m>");
  v_addhelp("  Options: [file=<filevar>] writes to specified output file");
  v_addhelp("           [str=<var>] writes to a string variable");
  v_addhelp("           [more] does a write instead of a writeln");
  TEMP.proc = (Anyptr)doset;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("set", TEMP, "*", "");
  v_addhelp("set");
  v_addhelp("set <parameter> = <value>");
  v_addhelp("  Display current parameter settings, or change a parameter.");
  TEMP.proc = (Anyptr)doquit;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("quit", TEMP, "quit", "Exit from the program");
  v_addhelp("quit  or  exit  or  control-D");
  v_addhelp("  As a keyboard command, exits from the View system.");
  v_addhelp("  Elsewhere, exits from current file or procedure.");
  v_addhelp("  quit [proc] exits from highest-level procedure.");
  v_addhelp("  quit [file] exits from highest-level command file.");
  v_addhelp("  quit [all] exits from all procedures and files.");
  v_addhelp("  quit [view] exits from the View system.");
  v_addalias("exit", "quit");
  TEMP.proc = (Anyptr)doabort;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("abort", TEMP, "", "");
  v_addhelp("abort");
  v_addhelp("  Exit to outermost keyboard input level (same as quit [all]).");
  TEMP.proc = (Anyptr)dobye;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("bye", TEMP, "", "");
  v_addhelp("bye");
  v_addhelp("  Exit from the View system (same as quit [view]).");
  TEMP.proc = (Anyptr)dohelp;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("help", TEMP, "", "");
  v_addhelp("?  or  help");
  v_addhelp("? <command> or <parameter>");
  v_addhelp("??");
  v_addhelp("?? <command>");
  v_addhelp("  The first form prints brief help for some common commands.");
  v_addhelp("  The second form prints complete help for one command, or");
  v_addhelp("  for one SET parameter.");
  v_addhelp("  The third form prints a list of all commands.");
  v_addhelp("  The fourth form prints an internal description of a command.");
  v_addalias("man", "help");

  TEMP.proc = (Anyptr)dodefparam;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("defparam", TEMP, "", "");
  v_addhelp("defparam [<type>] <parameter> = <ivalue>");
  v_addhelp("  Create a new SET parameter with name <parameter> and optional");
  v_addhelp("  initial value <ivalue>.  Default type is \"[str]\".");
  v_addhelp("  Others are \"[real]\", \"[int]\", \"[bool]\", \"[fn=suffix]\".");

  TEMP.proc = (Anyptr)doif;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("if", TEMP, "*", "");
  v_isctrl();
  v_addhelp("if <expr>");
  v_addhelp("elseif <expr>");
  v_addhelp("else");
  v_addhelp("endif");
  v_addhelp("  Evaluate IF/ELSEIF conditions until one is true (nonzero).");
  TEMP.proc = (Anyptr)doelse;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("else", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)doelse;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("elseif", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)doendif;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("endif", TEMP, "", "");
  v_isctrl();
  v_samehelp();

  TEMP.proc = (Anyptr)doswitch;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("switch", TEMP, "*", "");
  v_isctrl();
  v_addhelp("switch [<options>] <expr>");
  v_addhelp("case <expr>");
  v_addhelp("pcase <wildcard>");
  v_addhelp("rcase <regex>");
  v_addhelp("break");
  v_addhelp("otherwise");
  v_addhelp("endswitch");
  v_addhelp("  Evaluate the switch expression, and search for the first CASE");
  v_addhelp("  whose expression evaluates to the same value, or PCASE whose");
  v_addhelp("  Unix-style wildcard matches the value, or RCASE whose regular");
  v_addhelp("  expression pattern (see regex(2)) matches the value.  If none");
  v_addhelp("  of the cases match, the ELSE code, if any, is done.  You need");
  v_addhelp("  a BREAK command before each case to keep from falling through");
  v_addhelp("  as in the C language.");
  v_addhelp(
    "  The \"[ci]\" option forces case-insensitive comparisons of strings.");
  switchcmd = v_cmdid;
  TEMP.proc = (Anyptr)docase;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("case", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)docase;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("rcase", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)docase;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("pcase", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)docase;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("otherwise", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)doendswitch;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("endswitch", TEMP, "", "");
  v_isctrl();
  v_samehelp();

  TEMP.proc = (Anyptr)dowhile;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("while", TEMP, "*", "");
  v_isctrl();
  v_addhelp("while <expr>");
  v_addhelp("  <commands>");
  v_addhelp("endwhile");
  v_addhelp("  Repeat <commands> for as long as condition is true (nonzero).");
  v_addhelp("  BREAK and CONTINUE may be used to modify the loop.");
  whilecmd = v_cmdid;
  TEMP.proc = (Anyptr)doendwhile;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("endwhile", TEMP, "", "");
  v_isctrl();
  v_samehelp();

  TEMP.proc = (Anyptr)dorepeat;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("repeat", TEMP, "*", "");
  v_isctrl();
  v_addhelp("repeat");
  v_addhelp("  <commands>");
  v_addhelp("until <expr>");
  v_addhelp("  Repeat <commands> until condition is true (nonzero).");
  v_addhelp("  BREAK and CONTINUE may be used to modify the loop.");
  repeatcmd = v_cmdid;
  TEMP.proc = (Anyptr)dountil;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("until", TEMP, "", "");
  v_isctrl();
  v_samehelp();

  TEMP.proc = (Anyptr)dofor;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("for", TEMP, "*", "");
  v_isctrl();
  v_addhelp("for <var> = <min> : <max> [: <incr>]");
  v_addhelp("  <commands>");
  v_addhelp("endfor");
  v_addhelp("  Repeat <commands> for <var> equal to <min>, <min>+<incr>,");
  v_addhelp("  etc., up (or down) to <max>.  Default <incr> is 1.  Loop may");
  v_addhelp("  execute zero or more times.");
  v_addhelp("  BREAK and CONTINUE may be used to modify the loop.");
  forcmd = v_cmdid;
  TEMP.proc = (Anyptr)doendfor;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("endfor", TEMP, "", "");
  v_isctrl();
  v_samehelp();

  TEMP.proc = (Anyptr)dotry;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("try", TEMP, "*", "");
  v_isctrl();
  v_addhelp("try");
  v_addhelp("  <commands>");
  v_addhelp("recover");
  v_addhelp("  <recovery-commands>");
  v_addhelp("endtry");
  v_addhelp("  Execute <commands> as normal.  If an error occurs, jump");
  v_addhelp("  to the <recovery-commands>.  If all works well, jump past");
  v_addhelp("  the <recovery-commands>.");
  trycmd = v_cmdid;
  TEMP.proc = (Anyptr)dorecover;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("recover", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)doendtry;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("endtry", TEMP, "", "");
  v_isctrl();
  v_samehelp();

  TEMP.proc = (Anyptr)docontinue;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("continue", TEMP, "", "");
  v_addhelp("continue <n>");
  v_addhelp("  Jump back to the beginning of the n'th innermost WHILE,");
  v_addhelp("  REPEAT, or FOR loop.  Default <n> is 1.");
  TEMP.proc = (Anyptr)dobreak;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("break", TEMP, "", "");
  v_addhelp("break <n>");
  v_addhelp("  Jump out of the end of the n'th innermost WHILE, REPEAT,");
  v_addhelp("  or FOR loop, or SWITCH construct.  Default <n> is 1.");

  TEMP.proc = (Anyptr)dodefine;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("define", TEMP, "*", "");
  v_isctrl();
  v_addhelp("define [<options>] <name> <arguments>");
  v_addhelp("  <commands>");
  v_addhelp("enddef");
  v_addhelp("  Define a new command.  When <name> is entered as a command,");
  v_addhelp("  the <commands> will be executed in its place.  Argument");
  v_addhelp("  substitution occurs as described in the View documentation.");
  v_addhelp("  The default form deletes any previous commands of same name.");
  v_addhelp("  The \"[before]\" option adds before commands of same name.");
  v_addhelp("  The \"[after]\" option adds after commands of same name.");
  v_addhelp("  The \"[block]\" option defines a block-structuring command.");
  v_addhelp("  See /lib/view/examples.view for some example definitions.");
  TEMP.proc = (Anyptr)doenddef;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("enddef", TEMP, "", "");
  v_isctrl();
  v_samehelp();
  TEMP.proc = (Anyptr)doreturn;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("return", TEMP, "", "");
  v_addhelp("return");
  v_addhelp("  Return from highest-level procedure.  Equivalent to quit [proc]");
  TEMP.proc = (Anyptr)dolocal;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("local", TEMP, "", "");
  v_addhelp("local <var> <var> ...");
  v_addhelp("  Define local variables in a procedure.  (See DEFINE.)");
  TEMP.proc = (Anyptr)dolocaldef;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("localdef", TEMP, "", "");
  v_addhelp("localdef <cmd> <cmd> ...");
  v_addhelp("  Define local commands in a procedure.  (See DEFINE.)");
  TEMP.proc = (Anyptr)dolocalparam;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("localparam", TEMP, "", "");
  v_addhelp("localparam <param> <param> ...");
  v_addhelp("  Define local parameters in a procedure.  (See DEFINE, SET.)");
  TEMP.proc = (Anyptr)doaddhelp;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("addhelp", TEMP, "", "");
  v_addhelp("addhelp <message>");
  v_addhelp("  Add the line <message> to the help of the most recently");
  v_addhelp("  DEFINEd command.  Indent lines as follows:");
  v_addhelp("      addhelp  local <var> <var> ...");
  v_addhelp("      addhelp >  Define local variables in a procedure.");
  TEMP.proc = (Anyptr)doalias;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("alias", TEMP, "", "");
  v_addhelp("alias <newcmd> = <oldcmd>");
  v_addhelp("  Make an alternate name for a command.");
  TEMP.proc = (Anyptr)doeditdef;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("editdef", TEMP, "", "");
  v_addhelp("editdef <command> ...");
  v_addhelp("  Write the definitions of some commands to a temporary");
  v_addhelp("  file, run Caged on that file, then reload the definitions.");
  TEMP.proc = (Anyptr)doundefine;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("undefine", TEMP, "", "");
  v_addhelp("undefine <command> <command> ...");
  v_addhelp("  Remove any definitions for the specified command(s).");

  TEMP.proc = (Anyptr)doerror;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("error", TEMP, "", "");
  v_addhelp("error <message>");
  v_addhelp("  Print an error message related to the current command.");
  TEMP.proc = (Anyptr)doferror;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("ferror", TEMP, "", "");
  v_addhelp("ferror <message>");
  v_addhelp("  Print optional message and then exit this command with");
  v_addhelp("  a failure indication.");
  TEMP.proc = (Anyptr)docerror;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("cerror", TEMP, "", "");
  v_addhelp("cerror <message>");
  v_addhelp("  Same as FERROR, but does not append current line number");
  v_addhelp("  or file/procedure name to <message>.");

  TEMP.proc = (Anyptr)doresetfile;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("resetfile", TEMP, "", "");
  v_addhelp("resetfile <filevar> = '<filename>'");
  v_addhelp("  Open the specified file for reading, store a handle");
  v_addhelp("  in <filevar>.");
  TEMP.proc = (Anyptr)doreadnum;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("readnum", TEMP, "", "");
  v_addhelp("readnum [<options>] <var> <var> ... : <prompt>");
  v_addhelp("  Print the prompt line then wait for the user to enter");
  v_addhelp("  one or several numbers.  See READLN for list of options.");
  TEMP.proc = (Anyptr)doreadln;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("readln", TEMP, "", "");
  v_addhelp("readln [<options>] <var> <eofmark> : <prompt>");
  v_addhelp("  Print the prompt line them wait for the user to enter");
  v_addhelp("  a line of text to be stored as a string variable.");
  v_addhelp("  If <eofmark> is given, <var>='<eofmark>' on end-of-file.");
  v_addhelp("  The \"[opt]\" option lets the user enter a blank line");
  v_addhelp("  to retain the previous value of the variable.");
  v_addhelp("  The \"[exp]\" option does '$' expansions on the input.");
  v_addhelp("  The \"[file=<filevar>]\" option specifies an input file");
  v_addhelp("  hook (see RESETFILE).");

  TEMP.proc = (Anyptr)dorewritefile;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("rewritefile", TEMP, "", "");
  v_addhelp("resetfile [<options>] <filevar> = '<filename>'");
  v_addhelp("  Open the specified file for writing, store a handle");
  v_addhelp("  in <filevar>.");
  v_addhelp("  The \"[new]\" option prevents overwriting an existing file.");
  v_addhelp("  The \"[append]\" option appends to an existing file.");
  TEMP.proc = (Anyptr)doclosefile;
  TEMP.link = (Anyptr)NULL;
  v_addcmd("closefile", TEMP, "", "");
  v_addhelp("closefile <filevar>");
  v_addhelp("  Close an input or output file.");

  outfilehandle = NULL;
  savecloseproc = v_closefileshook;
  v_closefileshook.proc = (Anyptr)outfilecloseproc;
  v_closefileshook.link = (Anyptr)NULL;

  v_addparamkind(&pk, v_pk_other);
  pk->chproc.proc = (Anyptr)wildcardchproc;
  pk->chproc.link = (Anyptr)NULL;
  pk->fmtproc.proc = (Anyptr)wildcardfmtproc;
  pk->fmtproc.link = (Anyptr)NULL;
  pk->restproc.proc = (Anyptr)wildcardrestproc;
  pk->restproc.link = (Anyptr)NULL;
  pk->helpstr = strdup("Enter None, Shell, or Regex");
  v_addparam("wildcard", &pp, pk);

}






/*viewctrl*/






/* End. */
