home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / mm / mm-ccmd-0.91-20031009.tar.gz / mm-ccmd-0.91-20031009.tar / work / ccmd / cmpara.c < prev    next >
C/C++ Source or Header  |  2002-02-20  |  39KB  |  1,438 lines

  1. /*
  2.  Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  the City of New York.  Permission is granted to any individual or
  4.  institution to use, copy, or redistribute this software so long as it
  5.  is not sold for profit, provided this copyright notice is retained.
  6.  
  7.  Author: Howie Kaye
  8. */
  9.  
  10. /*
  11.  * cmpara
  12.  * parse 'chunks' of text, with some nice actions defined.
  13.  *
  14.  * texti style data input.
  15.  */
  16.  
  17. /*
  18.  * This file contains the code to parse chunks of text, simlilarly to the 
  19.  * way MM parses a message on the DEC-20
  20.  *
  21.  * Accepts a char *, which is:
  22.  *  a buffer of initialized text -- so that the function can be 
  23.  *    interrupted, and then continued.
  24.  *  and a list of action characters.  These are only in place when inside 
  25.  *  the actual paragraph parse.  When an action char is typed.
  26.  * 
  27.  * This is pretty hairy.  What it does, is to change the action routines
  28.  * being used, to allow the default/user defined actions to work.  It also
  29.  * has to manage it's own set of cmd buffers and work buffers, so that
  30.  * calls to ccmd insertion routines (cmsti) do not overflow the buffer
  31.  * space which ccmd has been given (cmbufs call).  The routines here are
  32.  * meant to be called after a confirm has been given, and no reparses into
  33.  * previous data will be necessary.  It can be used to parse large chunks
  34.  * of text, in a manner similar to the TEXTI jsys under TOPS-20.
  35.  *
  36.  * In order to make ccmd appear to be in a normal state whenever we leave
  37.  * the paragraph environment, we have to remember the old environment, and
  38.  * 'context switch' the old environment in (and out again) whenever an
  39.  * action character is typed (the action routine may make asumptions about
  40.  * the ccmd environment, and try to parse something).  To do this, all
  41.  * action character force a call to the break_hndlr() routine.  This then
  42.  * saves the environment, calls the real handler, and then restores the
  43.  * environment.  It also fixes the cmd internal buffers to reflect the new
  44.  * state.   
  45.  * 
  46.  * When a user supplied (or default) action routine is called, it is
  47.  * passed the text it is acting on (This buffer is malloc'ed to the correct
  48.  * size, and should not be written to if the write will go past the bounds
  49.  * of the current buffer).  The routine is also passed two flags.  If the
  50.  * buffer is modified, then the modified flag should be set.  If the
  51.  * parse should end (eof,abort,etc), then the ret flags should be set.  In
  52.  * all cases, a pointer to the new text should be returned.
  53.  */
  54.  
  55.                     /* allocate cmd stuff here */
  56. #define PARAERR
  57.  
  58.                     /* system structures/defines */
  59. #include "ccmdlib.h"
  60. #include "cmfncs.h"
  61.                     /* incremental buffer size */
  62. #if HAVE_UNISTD
  63. # include <unistd.h>            /* For mktemp */
  64. #else
  65.   extern char *mktemp();
  66. #endif
  67.  
  68. #define BSIZ 1000
  69.                     /* minimum space left before buffer */
  70.                     /* expansion */
  71. #define MINSIZE 133
  72.  
  73. #define beep() cmputc(BELL,cmcsb._cmoj)
  74.  
  75. /* forward declarations */
  76. PASSEDSTATIC int paraparse(), paracomplete(), parahelp();
  77.  
  78. static char *parse_cmdline(char *p);
  79. static char *parse_cmdline1(void);
  80. static char **get_path(void);
  81. static int lastlinelen(char *str);
  82. static int tablen(char *str);
  83.  
  84. /* 
  85.  * paragraph break mask
  86.  */
  87. static brktab parabrk = {
  88.   {                    /* all print characters */
  89.                     /* except tab and space */
  90.     0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
  91.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  92.   },
  93.   {
  94.     0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
  95.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  96.   }
  97. };
  98.     
  99. static brktab pipeparabrk = {
  100.   {                    /* just newline is a brk char */
  101.                     /* except tab and space */
  102.     0x00, 0x24, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
  103.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  104.   },
  105.   {
  106.     0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
  107.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  108.   }
  109. };
  110.  
  111. /*
  112.  * The behavior of this parser is different from the standard
  113.  * ccmd interface, so we must set up our own action table.
  114.  */
  115.  
  116. /*
  117.  * forward declare our action routines
  118.  */
  119. static char
  120.      *redispact(), *eofact(), *begact(), *fixact(), *quoact(), *delact(),
  121.      *wrdact(),*editact(),*dispact(),*insact(),*abortact(), *eolact(),
  122.      *autowrapact(), *autowraptab(), *autowrapspace(), *autowrapnl(),
  123.      *filteract(), *executeact();
  124.  
  125. /* 
  126.  * default paragraph actions
  127.  */
  128. para_actions def_actions[] = {
  129.   { '\002', insact },            /* ^B insert file */
  130.   { '\004', eofact },            /* ^D end of file */
  131.   { '\005', editact },            /* ^E invoke editor on this buffer */
  132.   { '\006', filteract },        /* ^F run buffer through filter */
  133.   { '\b', delact },            /* back space */
  134.   { '\t', autowraptab },        /* autowrap on tab */
  135.   { '\n', autowrapnl },            /* \n end of line wrap */
  136.   { '\r', autowrapnl },            /* CR or LF. */
  137.   { '\013', dispact },            /* ^K display whole buffer */
  138.   { '\f', redispact },            /* ^L redisplay screen */
  139.   { '\016', abortact },            /* ^N abort this insertion */
  140.   { '\020', executeact },        /* ^P execute command and insert */
  141.   { '\022', fixact },            /* ^R redisplay line */
  142.   { '\025', begact },            /* ^U delete line */
  143.   { '\026', quoact },            /* ^V quota character */
  144.   { '\027', wrdact },            /* ^W delete backwards word */
  145.   { ' ', autowrapspace },        /* SPC autowrap on space */
  146.   { '\177', delact },            /* DEL delete previous char */
  147.   {      0, NULL },            /* end the table */
  148. };
  149.  
  150. static int (**oldact)();        /* old action table */
  151.  
  152.                     /* clean paragraph action table */
  153. static int (*(paraact[128]))() = {
  154.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  155.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  156.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  157.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  158.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  159.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  160.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  161.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  162.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  163.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  164.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  165.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  166.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  167.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  168.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  169.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL
  170. };
  171.  
  172.                     /* clean user defined action table */
  173. static char * (*(paraact1[128]))() = {
  174.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  175.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  176.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  177.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  178.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  179.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  180.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  181.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,
  182.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  183.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  184.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  185.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  186.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  187.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  188.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  189.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL
  190. };
  191.  
  192. /*
  193.  * global state variables
  194.  */
  195.  
  196. static int eof=FALSE;
  197. static int abortf = FALSE;
  198. static csb savecsb;
  199. static int *cmdbuf=NULL;
  200. static int set=FALSE;            /* first call to parse, or an */
  201. static jmp_buf ojmp;
  202.  
  203.                     /* handler structure */
  204. ftspec ft_para = { paraparse, parahelp, paracomplete, 0, ¶brk };
  205.  
  206. static int (*oerrh)();
  207.  
  208. parareset(code) int code; {
  209.   bcopy(ojmp, cmerjb, sizeof (jmp_buf)); /* put back old error handler */
  210.   null_actions();            /* restore action block */
  211.   cmact(oldact);            /* put back the original action table*/
  212.   set = FALSE;                /* uninitialized...for next time */
  213.   if (cmcsb._cmwbp)
  214.       free(cmcsb._cmwbp);
  215.   if (cmcsb._cmbfp)
  216.       free(cmcsb._cmwbp);
  217.   cmcsb = savecsb;
  218.   cmcsb._cmerh = oerrh;
  219.   return((*cmcsb._cmerh)(code));
  220. }
  221.  
  222. /*
  223.  * parse routine.
  224.  * parse until eof or abort get's set.
  225.  * returns buffer which has been typed, or NULL on abort
  226.  */
  227. PASSEDSTATIC int
  228. paraparse(text,textlen,fdbp,parselen,value)
  229. char *text;
  230. int textlen;
  231. fdb *fdbp;
  232. int *parselen;
  233. pval *value;
  234. {
  235.   int len,i;
  236.   brktab *btab;                /* break table to use */
  237.                     /* action call? */
  238.   static int flg;
  239.   static char *buf;
  240.  
  241.   if (cmcsb._cmflg2 & CM_EOF) {
  242.       cmcsb._cmflg2 &= ~CM_EOF;
  243.       eof = TRUE;
  244.   }
  245.  
  246.   if (!set) {                /* first time through, set things up */
  247.     bcopy(cmerjb, ojmp, sizeof (jmp_buf));
  248.     
  249.     savecsb = cmcsb;            /* save stae for later */
  250.     oerrh = cmcsb._cmerh;
  251.     if (cmdbuf != NULL)            /* get rid of old buffer */
  252.       free(cmdbuf);
  253.     if ((cmdbuf = (int *)calloc(1,BSIZ*sizeof(*cmdbuf))) == NULL)
  254.       return(PARAxNM);
  255.     if ((cmcsb._cmwbp = 
  256.      (char *)calloc(1,BSIZ*sizeof(*cmcsb._cmwbp))) == NULL) {
  257.       free(cmdbuf);
  258.       cmdbuf = NULL;
  259.       return(PARAxNM);
  260.     }
  261.     cmcsb._cmwbc = BSIZ;        /* set up. */
  262.     cmcsb._cmcnt = BSIZ;
  263.     cmcsb._cmptr = cmdbuf;
  264.     cmcsb._cmbfp = cmdbuf;
  265.     cmcsb._cmcur = cmdbuf;
  266.     cmcsb._cminc = 0;
  267.     cmcsb._cmflg &= ~CM_NAC;
  268.     cmcsb._cmerh = parareset;
  269.  
  270.     if (fdbp->_cmdat != NULL) {        /* insert specified starting text */
  271.       para_data *dat = (para_data *) fdbp->_cmdat;
  272.       if (dat->buf != NULL) {
  273.     int len = strlen(dat->buf);
  274.     if (len >= BSIZ) {        /* do we have enough space? */
  275.                     /* no!  get more */
  276.       if ((cmdbuf=(int *)cmrealloc(cmdbuf,(len+BSIZ)*sizeof(int)))==NULL){
  277.         return(PARAxNM);
  278.       }
  279.       cmcsb._cmcur = cmcsb._cmptr = cmdbuf + (cmcsb._cmptr - cmcsb._cmbfp);
  280.       cmcsb._cmbfp = cmdbuf;
  281.       cmcsb._cmcnt = len + BSIZ;
  282.  
  283.       if ((cmcsb._cmwbp = 
  284.            (char *)cmrealloc(cmcsb._cmwbp, 
  285.                  sizeof(*cmcsb._cmwbp)*(len+BSIZ))) == NULL){
  286.         return(PARAxNM);
  287.       }
  288.       cmcsb._cmwbc = len + BSIZ;
  289.     }
  290.     cmsti(dat->buf,CC_NEC|CC_HID|CC_QUO); /* insert text, no echoing */
  291.     for (i = 0; i < cmcsb._cminc; i++) { /* turn off the flags */
  292.       cmcsb._cmptr[i] &= ~(CC_HID|CC_NEC|CC_QUO);
  293.     }
  294.       }
  295.       null_actions();            /* zero out the action table */
  296.       if (cmcsb._cmflg & CM_ITTY) {
  297.     if (dat->actions != NULL) {    /* install user/default actions */
  298.       if (fdbp->_cmffl & PARA_DEF)
  299.         install_actions(def_actions);
  300.       install_actions(dat->actions);
  301.     }
  302.     else {
  303.       install_actions(def_actions);
  304.     }
  305.       }
  306.       else {
  307.     install_nl_action();
  308.       }
  309.     }
  310.     oldact = cmcsb._cmact;        /* save old action table */
  311.     cmact(paraact);            /* now use our own action characters */
  312.     eof = FALSE;            /* not done yet */
  313.     abortf = FALSE;            /* not aborting */
  314.     set = TRUE;                /* but we are initialized */
  315.   }
  316.  
  317.   if (cmcsb._cmcnt < MINSIZE) {        /* running out of buffer space? */
  318.                     /* then get more space */
  319.     if ((cmdbuf=(int *)cmrealloc(cmdbuf,(cmcsb._cmwbc + BSIZ)
  320.                  *sizeof(int)))==NULL){
  321.       return(PARAxNM);
  322.     }
  323.     cmcsb._cmptr = cmdbuf + (cmcsb._cmptr - cmcsb._cmbfp);
  324.     cmcsb._cmcur = cmdbuf + (cmcsb._cmcur - cmcsb._cmbfp);
  325.     cmcsb._cmbfp = cmdbuf;        /* and install it into the CSB */
  326.     
  327.     cmcsb._cmcnt += BSIZ;        /* count it */
  328.     
  329.     if ((cmcsb._cmwbp = (char *)cmrealloc(cmcsb._cmwbp,cmcsb._cmwbc+BSIZ))
  330.     == NULL) {
  331.       return(PARAxNM);
  332.     }
  333.     cmcsb._cmwbc += BSIZ;
  334.   }
  335.  
  336.   if (eof) {                /* done! */
  337.     if (buf != NULL)            /* free previous buffer */
  338.       free(buf);
  339.     
  340.     if ((buf = (char *)malloc(textlen+1)) == NULL) { /* get space */
  341.       return(PARAxNM);
  342.     }
  343.     strncpy(buf,text,textlen);        /* copy text into buffer */
  344.     buf[textlen] = '\0';        /* NULL terminate it */
  345.     for (i = 0; i < textlen; i++)
  346.       buf[i] &= 0x7f;            /* strip those quota characters out. */
  347.     value->_pvpara = buf;        /* point return value at it */
  348.     *parselen = textlen;        /* set the length properly */
  349.     null_actions();            /* restore action block */
  350.     bcopy(cmerjb, ojmp, sizeof (jmp_buf)); /* put back old error handler */
  351.     cmact(oldact);            /* put back the original action table*/
  352.     set = FALSE;            /* initialized...for next time */
  353.     if (cmcsb._cmcol != 0)
  354.     cmxnl();
  355.     free(cmcsb._cmwbp);
  356.     free(cmcsb._cmbfp);
  357.     cmdbuf = NULL;            /* cmdbuf = cmcsb._cmbfp */
  358.     cmcsb = savecsb;            /* restore ccmd's buffers */
  359.     return(CMxOK);            /* return done */
  360.   }
  361.   else
  362.     if (abortf) {
  363.       bcopy(ojmp, cmerjb, sizeof (jmp_buf)); /* put back old error handler */
  364.       null_actions();            /* restore action block */
  365.       cmact(oldact);            /* put back the original action table*/
  366.       set = FALSE;            /* uninitialized...for next time */
  367.       value->_pvpara = NULL;
  368.       *parselen = textlen;
  369.       if (cmcsb._cmcol != 0)
  370.       cmxnl();
  371.       free(cmcsb._cmwbp);        /* restore ccmd's buffers */
  372.       cmcsb = savecsb;
  373.       return(CMxOK);
  374.     }
  375.   return(CMxINC);            /* nothing here...return incomplete */
  376. }
  377.  
  378. int break_hndlr();            /* forward declaration */
  379.  
  380. /*
  381.  * scan through para_action table, and install actions in 
  382.  * the real actions tables.
  383.  * terminates in NULL function.
  384.  */
  385. install_actions(actions) para_actions *actions; {
  386.   if (!cmcsb._cmflg & CM_TTY)
  387.     return;
  388.   for(; !(actions->actionfunc==NULL && actions->actionchar==0);actions++) {
  389.     paraact[actions->actionchar] = break_hndlr;
  390.     paraact1[actions->actionchar] = actions->actionfunc;
  391.   }
  392. }
  393.  
  394. /*
  395.  * zero out the action tables
  396.  */
  397. null_actions() {
  398.     bzero(paraact, sizeof(paraact));
  399.     bzero(paraact1, sizeof(paraact));
  400. }
  401.  
  402. /*
  403.  * parse completion.
  404.  * does nothing.
  405.  */
  406. PASSEDSTATIC int
  407. paracomplete(text,textlen,fdbp,full,cplt,cpltlen)
  408. char *text,**cplt;
  409. int textlen,full,*cpltlen;
  410. fdb *fdbp;
  411. {
  412.   *cplt = NULL;
  413.   return(CMP_BEL);        /* beep at them */
  414. }
  415.  
  416. /*
  417.  * helpless
  418.  */
  419.  
  420. PASSEDSTATIC int
  421. parahelp(text,textlen,fdbp,cust,lines)
  422. char *text;
  423. int textlen,cust;
  424. fdb *fdbp;
  425. int lines;
  426. {
  427.   return(lines);
  428. }
  429.  
  430. /*
  431.  * Action routines
  432.  */
  433.  
  434. /*
  435.  * eof action.
  436.  */
  437. static char *
  438. eofact(text,modified,ret) char *text; int *modified,*ret; {
  439.   *ret = TRUE;
  440.   *modified = FALSE;
  441.   return(text);
  442. }
  443.  
  444.  
  445. /*
  446.  * redisplay the last screenful of text
  447.  */
  448.  
  449. static char *
  450. redispact(text,modified,ret) char *text; int *modified, *ret;{
  451.   int i, li, co, cols, ov=FALSE;
  452.   char c;
  453.  
  454.   *ret = FALSE;
  455.   *modified = FALSE;
  456.   cmcls();
  457.   li = cmcsb._cmrmx;            /* get number of lines */
  458.   co = cmcsb._cmcmx;            /* and number of columns */
  459.  
  460.   for (i = strlen(text)-1, cols = 0; i >= 0; i--) { /* figure out what */
  461.     c = text[i] & 0x7f;            /*   we can display */
  462.     if (c == '\t')
  463.     cols = ((cols + 8) / 8) * 8;
  464.     else 
  465.     cols++;                /* incr column count */
  466.     if (iscntrl(c) && !isspace(c))    /* control char takes two chars */
  467.       cols++;                /*   to display, count the ^ */
  468.     if (cols > co) {        
  469.       --li;                /* we overflowed the line */
  470.       cols = 0;                /* reset column count */
  471.       ov = TRUE;            /* remember */
  472.     }
  473.     if (c == '\n') {            /* another line */
  474.       cols = 0;                /* reset the column count */
  475.       li--;
  476.       ov = FALSE;
  477.     }
  478.     if (li == 0)            /* can't display any more lines */
  479.       break;
  480.   }
  481.   if (ov && li == 0) {            /* top line doesn't fit on display */
  482.     int p;
  483.     p = i;
  484.     while ((c = text[p] & 0x7f) != '\n' &&  p > 0) /* find beginning of line */
  485.       p--;
  486.     p += ((i - p)/co + 1) * co;
  487.     i = p-1;                /* skip over the \n */
  488.   }
  489.     
  490.   cmcsb._cmcol = 0;
  491.   for(i++; i < cmcsb._cminc; i++) {    /* display the screenful */
  492.     c = text[i] & 0x7f;
  493.     if (iscntrl(c) && !isspace(c)) {
  494.       cmxputc('^');            /* display control chars as */
  495.       cmxputc(c | 0100);        /*   caret and uppercased */
  496.     }
  497.     else cmechx(c);
  498.   }
  499.   return(text);
  500. }
  501.  
  502. /* 
  503.  * insact
  504.  * insert a file at the end of the buffer
  505.  */
  506. static char *
  507. insact(text, modified, ret) char *text; int *modified, *ret; {
  508.                     /* filename fdb */
  509.   static fdb filfdb = { _CMFIL ,FIL_TYPE|FIL_NODIR, NULL, NULL, NULL, NULL,
  510.                 NULL };
  511.                     /* confirm fdb */
  512.   static fdb filfdb1 = { _CMCFM, CM_SDH, &filfdb, NULL, "Confirm to cancel",
  513.              NULL, NULL };
  514.   static fdb cfmfdb = { _CMCFM, 0, NULL, NULL, NULL, NULL, NULL };
  515.   char c;
  516.   char *fname= NULL;
  517.   pval parseval;
  518.   fdb *used;
  519.   int fd;
  520.   struct stat buf;
  521.   char *ntext = NULL;
  522.   int len;
  523.   static int cmdbuf[200];
  524.   static char atmbuf[200],wrkbuf[200];
  525.  
  526.   cmbufs(cmdbuf,200,atmbuf,200,wrkbuf,200);
  527.   cmseter();                /* errors come back to here */
  528.   prompt("Insert file: ");        /* prmpt for a filename */
  529.   cmsetrp();                /* reparses come back here. */
  530.   parse(&filfdb1, &parseval, &used);    /* parse the filename */
  531.   if (used == &filfdb1) {
  532.     cmxputs("...No file inserted\n"); 
  533.     *modified = FALSE;
  534.     return(text);
  535.   }
  536.   if (fname != NULL)            /* free up old filename if */
  537.     free(fname);            /* necessary */
  538.   if ((fname = (char *)malloc(strlen(parseval._pvfil[0])+1)) == NULL) {
  539.     cmxputs("?Out of memory\n");
  540.     return(text);
  541.   }
  542.   strcpy(fname,parseval._pvfil[0]);    /* copy the data */
  543.   parse(&cfmfdb,&parseval,&used);    /* get confirmation */
  544.  
  545.   fd = open(fname,O_RDONLY,0);        /* open up the file */
  546.   if (fd == -1) {            /* couldn't open it... */
  547.     cmxputs("?permission denied\n");    /* complain */
  548.     *modified = FALSE;            /* no modification done */
  549.     return(text);
  550.   }
  551.   stat(fname,&buf);            /* get length of file */
  552.   len = strlen(text) + buf.st_size;
  553.   if ((ntext = (char *)malloc(len+1)) == NULL) { /* make space */
  554.     cmxputs("?Out of memory\n"); 
  555.     return(text);
  556.   }
  557.   strcpy(ntext,text);            /* copy old text */
  558.                     /* and add in the file */  
  559.   len = strlen(text) + read(fd,&ntext[strlen(text)],buf.st_size);
  560.   close(fd);                /* close the file */
  561.   cmxputs("[OK]\n"); 
  562.   ntext[len] = '\0';            /* null terminate */
  563.   *modified = TRUE;            /* we changed things */
  564.   *ret = FALSE;
  565.   return(ntext);            /* return new text */
  566. }
  567.  
  568. /*
  569.  * display the whole buffer
  570.  */
  571. static char *
  572. dispact(text, modified, ret) char *text; int *modified, *ret; {
  573.   if (cmcsb._cmcol != 0)
  574.     cmxnl();
  575.   cmxputs(text); 
  576.   return(text);
  577. }
  578.  
  579. /*
  580.  * invoke the editor on the buffer
  581.  */
  582. static char *
  583. editact(text, modified, ret) char *text; int *modified, *ret; {
  584.   char fname[40];
  585.   char *e,*getenv();
  586.   int fd;
  587.   char buf[100];
  588.   static char *ntext=NULL;
  589.   struct stat sbuf;
  590.   int len,i;
  591.  
  592.   cmxputs("Invoking editor...\n");    /* announce our intentions */
  593.   e = getenv("EDITOR");            /* check editor variable */
  594.   if (e == NULL || *e == '\0')        /* no editor variable? */
  595.     e = DEF_EDITOR;            /* use default editor */
  596.   
  597. #if CCMD_OS_UNIX
  598.     strcpy(fname,"/tmp/cmdXXXXXX");    /* get a file name */
  599.     mktemp(fname);
  600. #else
  601.   strcpy(fname,mktemp(getenv("TMP"),"cmd")); /* get a file name */  
  602. #endif
  603.   fd = open(fname,O_WRONLY|O_CREAT,0700); /* open the tmp file */
  604.   if (fd < 0) {
  605.     cmxputs("?Could not create temporary file.\n"); 
  606.     perror(fname);
  607.     return(text);
  608.   }
  609.   if (write(fd,text,strlen(text)) != strlen(text)) {
  610.     cmxputs("?Could not write temporary file.\n"); 
  611.     perror(fname);
  612.     close(fd);
  613.     unlink(fname);
  614.     return(text);
  615.   }
  616.   close(fd);
  617.   strcpy(buf,e);
  618. #if !CCMD_OS_MSDOS
  619.   strcat(buf," +1000000");
  620. #endif
  621.   strcat(buf," ");
  622.   strcat(buf,fname);
  623.   cmtend();                /* put the tty back */
  624.   if (system(buf) != 0) {        /* execute it */
  625.     cmtset();
  626.     cmxputs("?Edit failed.\n");        /* failure? */
  627.     perror(fname);
  628.     unlink(fname);            /* throw up hands in disgust */
  629.     return(text);
  630.   }
  631.   cmtset();
  632.   if (stat(fname,&sbuf) == -1) {    /* get length of file */
  633.     cmxputs("?Temporary file disappeared\n"); 
  634.     return(text);
  635.   }
  636.   len = sbuf.st_size;
  637.   fd = open(fname,O_RDONLY,0);        /* open the file again */
  638.   if (fd < 0) {
  639.     cmxputs("?Could not open temporary file for read.\n"); 
  640.     perror(fname);
  641.     unlink(fname);
  642.     return(text);
  643.   }
  644.   if (ntext != NULL)            /* free up last buffer */
  645.     free(ntext);
  646.   if ((ntext = (char *)malloc(len+1)) == NULL) { /* make space */
  647.     cmxputs("?Out of memory\n"); 
  648.     return(text);
  649.   }
  650. #if CCMD_OS_MSDOS
  651.   if ((i = read(fd,ntext,len)) < 0)  /* read in the file */
  652. #else
  653.   if ((i = read(fd,ntext,len)) != len) /* read in the file */
  654. #endif
  655.   {
  656.     cmxputs("?Could not read temporary file.\n"); 
  657.     perror(fname);
  658.     unlink(fname);
  659.     return(text);
  660.   }
  661.   close(fd);                /* close the file */
  662.   cmcls();
  663.   ntext[len] = '\0';            /* null terminate */
  664.   *modified = TRUE;
  665.   unlink(fname);
  666.   cmxputs("...Back again\n"); 
  667.   return(ntext);
  668. }
  669.  
  670. /*
  671.  * abort the current buffer
  672.  */
  673. static char *
  674. abortact(text, modified, ret) char *text; int *modified, *ret; {
  675.   static fdb cfmfdb = { _CMCFM, CM_SDH, NULL, NULL, "Carriage Return to abort",
  676.             NULL, NULL };
  677.   char cmdbuf[200],atmbuf[200],wrkbuf[200];
  678.   pval parseval;
  679.   fdb *used;
  680.  
  681.   cmcsb._cmerr = CMxOK;
  682.   cmbufs(cmdbuf,200,atmbuf,200,wrkbuf,200);
  683.   cmseter();                /* errors come back to here */
  684.   if (cmcsb._cmerr == CFMxNOC) {
  685.     cmcsb._cmflg &= ~CM_ACT;        /* no pending actions now */
  686.     return(text);
  687.   }
  688.   prompt("[Confirm to Abort]");        /* prompt for a confirm */
  689.   cmsetrp();                /* reparses come back here. */
  690.   parse(&cfmfdb, &parseval, &used);    /* parse the confirm */
  691.   abortf = TRUE;
  692.   return(text);
  693. }
  694.  
  695. /*
  696.  * just make us wake up on eol, to check on buffer space...
  697.  */
  698.  
  699. static char *
  700. eolact(text, modified, ret) char *text; int *modified, *ret; {
  701.   static char *ntext=NULL;
  702.   
  703.   cmechx('\n');                /* do it again */
  704.   *modified = TRUE;            /* we modified it */
  705.   *ret = FALSE;                /* don't return yet */
  706.   strcat(text,"\n");
  707.   return(ntext);
  708. }  
  709.  
  710.  
  711. static char *
  712. executeact(text, modified, ret) 
  713. char *text; 
  714. int *modified, *ret; 
  715. {
  716.   char fname[40];
  717.   char *getenv();
  718.   char *output;
  719.   char *cmd, *parse_cmdline();
  720.   struct stat sbuf;
  721.   int fd;
  722.   int len;
  723.   int total;
  724.  
  725.   if ((cmd = parse_cmdline("Command: ")) == NULL) {
  726.     *modified = FALSE;
  727.     return (text);
  728.   }
  729.  
  730. #if CCMD_OS_UNIX
  731.   strcpy(fname,"/tmp/cmdXXXXXX");    /* get a file name */
  732.   mktemp(fname);
  733. #else
  734.   strcpy(fname,mktemp(getenv("TMP"),"cmd")); /* get a file name */  
  735. #endif
  736.  
  737.   cmd = (char *) cmrealloc (cmd, strlen(cmd)+strlen(fname)+strlen(" > ")+1);
  738.   strcat (cmd, " > ");
  739.   strcat (cmd, fname);
  740.   
  741.   cmsystem (cmd);
  742.   free (cmd);
  743.  
  744.   if (stat(fname, &sbuf) == -1) {
  745.     cmxputs ("?Temporary file missing\n");
  746.     return (text);
  747.   }
  748.   len = sbuf.st_size;
  749.   total = strlen(text)+len;
  750.   if ((output = (char *) malloc (total+1)) == NULL) {
  751.     cmxputs ("?Out of memory\n");
  752.     *modified = FALSE;
  753.     return (text);
  754.   }
  755.   strcpy (output, text);
  756.   if ((fd = open(fname, O_RDONLY,0)) < 0) {
  757.     cmxputs("?Could not open temporary file for read.\n"); 
  758.     perror(fname);
  759.     unlink(fname);
  760.     free (output);
  761.     return(text);
  762.   }
  763. #if CCMD_OS_MSDOS
  764.   if (read(fd,output+strlen(text),len) < 0)
  765. #else
  766.   if (read(fd,output+strlen(text),len) != len)
  767. #endif
  768.   {
  769.     cmxputs("?Could not read temporary file.\n"); 
  770.     perror(fname);
  771.     unlink(fname);
  772.     free (output);
  773.     return(text);
  774.   }
  775.   close(fd);                /* close the file */
  776.   output[total] = '\0';
  777.   unlink (fname);
  778.   *modified = TRUE;
  779.   *ret = FALSE;
  780.   cmxputs("[Done]\n");
  781.   return (output);
  782. }
  783.  
  784.  
  785. static brktab fieldbrk = {
  786.   {                    /* print chars except ?, space, tab */
  787.     0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01,
  788.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
  789.   },
  790.   {                    /* print chars except ?, space, tab */
  791.     0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x01,
  792.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
  793.   }
  794. };
  795. static filblk efilblk = { NULL, NULL, NULL };
  796. static fdb efilefdb = { _CMFIL, FIL_OLD|FIL_EXEC|CM_SDH, NULL, 
  797.               (pdat) &efilblk, NULL, NULL, NULL };
  798. static fdb filefdb = { _CMFIL, CM_SDH, NULL, 
  799.              (pdat) NULL, NULL, NULL, NULL };
  800. static fdb fieldfdb = { _CMFLD, CM_SDH, NULL, NULL, NULL, NULL, &fieldbrk };
  801. static fdb conffdb = { _CMCFM, CM_SDH, NULL, NULL, 
  802.              "command line", NULL, NULL };
  803. static char **path = NULL;
  804.  
  805. static char *
  806. parse_cmdline (char *p)
  807. {
  808.   char *cmd;
  809.   char *cmdend;
  810.   pval parseval;
  811.   fdb *used;
  812.   static int cmdbuf[200];
  813.   static char atmbuf[200],wrkbuf[200];
  814.  
  815.   cmbufs(cmdbuf,200,atmbuf,200,wrkbuf,200);
  816.  
  817.   path = get_path();
  818.   efilblk.pathv = path;
  819.  
  820.   cmseter();
  821.   prompt (p);
  822.   cmsetrp();
  823.   parse (fdbchn(&conffdb, &efilefdb, &filefdb, &fieldfdb, NULL), 
  824.      &parseval, &used);
  825.  
  826.   if (used == &conffdb) {
  827.     cmxputs ("Aborting\n");
  828.     return (NULL);
  829.   }
  830.  
  831.   if (used == &efilefdb || used == &filefdb) {
  832.     cmd = (char *) malloc (strlen (parseval._pvfil[0]) + 1);
  833.     strcpy (cmd, parseval._pvfil[0]);
  834.   }
  835.   else if (used == &fieldfdb) {
  836.     cmd = (char *) malloc (strlen (parseval._pvstr) + 1);
  837.     strcpy (cmd, parseval._pvstr);
  838.   }
  839.   
  840.   if (cmdend = parse_cmdline1()) {
  841.       cmd = (char *) realloc (cmd, strlen (cmd)+strlen(cmdend)+2);
  842.       strcat (cmd, " ");
  843.       strcat (cmd, cmdend);
  844.       free (cmdend);
  845.   }
  846.   return (cmd);
  847. }
  848.  
  849. static char *
  850. parse_cmdline1 (void)
  851. {
  852.   char *cmd;
  853.   char *cmdend;
  854.   pval parseval;
  855.   fdb *used;
  856.   
  857.   parse (fdbchn(&conffdb, &filefdb, &fieldfdb, NULL), 
  858.      &parseval, &used);
  859.  
  860.   if (used == &conffdb)
  861.     return (NULL);
  862.  
  863.   if (used == &filefdb) {
  864.     cmd = (char *) malloc (strlen (parseval._pvfil[0]) + 1);
  865.     strcpy (cmd, parseval._pvfil[0]);
  866.   }
  867.   else if (used == &fieldfdb) {
  868.     cmd = (char *) malloc (strlen (parseval._pvstr) + 1);
  869.     strcpy (cmd, parseval._pvstr);
  870.   }
  871.   
  872.   if (cmdend = parse_cmdline1()) {
  873.       cmd = (char *) realloc (cmd, strlen (cmd)+strlen(cmdend)+2);
  874.       strcat (cmd, " ");
  875.       strcat (cmd, cmdend);
  876.       free (cmdend);
  877.   }
  878.   return (cmd);
  879. }
  880.  
  881.  
  882. static char **
  883. get_path(void)
  884. {
  885.   char **path = NULL;
  886.   int num = 0;
  887.   char *PATH, *cp, *getenv();
  888.   char *p, *index();
  889.  
  890.   if ((PATH = getenv ("PATH")) == NULL)
  891.     return (NULL);
  892.   else {
  893.     cp = (char *) malloc (strlen(PATH)+1); /* space for private copy */
  894.     strcpy (cp, PATH);
  895.   }
  896.  
  897.   while ((p = index (cp, ':')) != NULL) { /* while we have dirs */
  898.     *p = '\0';                /* tie of with a NULL */
  899.     if (strlen(cp) != 0) {
  900.       if (num == 0)             /* first path */
  901.     path = (char **) malloc (sizeof (char *)); /* space for 1 */
  902.       else                /* need more space */
  903.     path = (char **) realloc (path, (num+1)*sizeof(char *));
  904.       path[num] = (char *) malloc (strlen(cp)+1); /* space for path */
  905.       strcpy (path[num], cp);        /* copy path into array */
  906.       num++;                /* increment count */
  907.     }
  908.     cp = ++p;                /* move on */
  909.   }
  910.   /* the last path element */
  911.   path = (char **) realloc (path, (num+2)*sizeof(char *));
  912.   path[num] = (char *) malloc (strlen(cp)+1);
  913.   strcpy (path[num], cp);
  914.   num++;
  915.   path[num] = NULL;            /* tie off with null path */
  916.   return (path);
  917. }
  918.  
  919. static char *
  920. autowrapspace (text, modified, ret)
  921. char *text;
  922. int *modified, *ret;
  923. {
  924.   return (autowrapact (text, modified, ret, ' '));
  925. }
  926.  
  927. static char *
  928. autowrapnl (text, modified, ret)
  929. char *text;
  930. int *modified, *ret;
  931. {
  932.   return (autowrapact (text, modified, ret, '\n'));
  933. }
  934.  
  935.  
  936. static char *
  937. autowraptab (text, modified, ret)
  938. char *text;
  939. int *modified, *ret;
  940. {
  941.   return (autowrapact (text, modified, ret, '\t'));
  942. }
  943.  
  944. static char *
  945. autowrapact(text, modified, ret, c)
  946. char *text;
  947. int *modified, *ret;
  948. char c;
  949. {
  950.     int i,j;
  951.     extern csb cmcsb;
  952.     int wordbeg, spacebeg;
  953.     int maxcol;
  954.  
  955.     maxcol = cmcsb._cmwrp >= 0 ? cmcsb._cmwrp : cmcsb._cmcmx + cmcsb._cmwrp;
  956.     if (cmcsb._cmwrp != 0 && lastlinelen(text) >= maxcol) {
  957.     for(i = strlen(text)-1; i >= 0; i--) {
  958.         if (text[i] == ' ' || text[i] == '\t') {
  959.         wordbeg = i+1;
  960.         i--;
  961. #ifdef undef
  962.         while((text[i] == ' ' || text[i] == '\t') && i >= 0) i--;
  963. #endif
  964.         spacebeg = i+1;
  965.         break;
  966.         }
  967.         else {
  968.         if (text[i] == '\n' || i == 0 ||
  969.             strlen(text) - i >= maxcol) {
  970.             strcat(text,"\n");
  971.             cmechx('\n');
  972.             *ret = FALSE;
  973.             *modified = TRUE;
  974.             return(text);
  975.         }
  976.         }
  977.     }
  978.     if (cmcsb._cmcol != strlen(text) - wordbeg) {
  979.         delcurrent(strlen(text) - wordbeg);
  980.         cmechx('\n');
  981.         cmxputs(&text[wordbeg]);
  982.     }
  983.     cmechx(c);
  984.     text[spacebeg] = '\n';
  985.     text[strlen(text)+1] = '\0';
  986.     text[strlen(text)] = c;
  987.     *ret = FALSE;
  988.     *modified = TRUE;
  989.     return(text);
  990.     }
  991.     text[strlen(text)+1] = '\0';
  992.     text[strlen(text)] = c;
  993.     cmechx(c);
  994.     *ret = FALSE;
  995.     *modified = TRUE;
  996.     return(text);
  997. }
  998.  
  999. static int
  1000. lastlinelen(char *str)
  1001. {
  1002.     register int i,j=strlen(str);
  1003.     for(i = j - 1; i >= 0; i--)
  1004.     if (str[i] == '\n')
  1005.         return(tablen(str + i + 1));
  1006.     return(tablen(str));
  1007. }
  1008.  
  1009. /* 
  1010.  * calculate length of a line, even if there are tabs in it.
  1011.  */
  1012.  
  1013. static int
  1014. tablen(char *str)
  1015. {
  1016.     register char *cp = str;
  1017.     register int len=0;
  1018.     while(*cp) {
  1019.     if (*cp == '\t') {
  1020.         len = ((len + 8) / 8) * 8;
  1021.     }
  1022.     else
  1023.         len++;
  1024.     cp++;
  1025.     }
  1026.     return(len);
  1027. }
  1028.         
  1029.  
  1030. static char *
  1031. filteract (text, modified, ret) 
  1032. char *text; 
  1033. int *modified, *ret; 
  1034. {
  1035.   char fname1[40];
  1036.   char fname2[40];
  1037.   char *getenv();
  1038.   char *output;
  1039.   char *cmd;
  1040.   struct stat sbuf;
  1041.   int fd;
  1042.   int len;
  1043.   int total;
  1044.   FILE *pp;
  1045.  
  1046.   if ((cmd = parse_cmdline("Filter: ")) == NULL) {
  1047.     *modified = FALSE;
  1048.     return (text);
  1049.   }
  1050.  
  1051. #if CCMD_OS_UNIX
  1052.   strcpy(fname1,"/tmp/cmd1XXXXXX");    /* get a file name */
  1053.   mktemp(fname1);
  1054.   strcpy(fname2,"/tmp/cmd2XXXXXX");    /* get a file name */
  1055.   mktemp(fname2);
  1056. #else
  1057.   strcpy(fname1,mktemp(getenv("TMP"),"cmd1")); /* get a file name */  
  1058.   strcpy(fname2,mktemp(getenv("TMP"),"cmd2")); /* get a file name */  
  1059. #endif
  1060.  
  1061.   cmd = (char *) realloc (cmd, strlen(cmd)+strlen(fname1)+strlen(" < ")+
  1062.               strlen(" > ") + strlen(fname2) +1);
  1063.   strcat (cmd, " < ");
  1064.   strcat (cmd, fname1);
  1065.   strcat (cmd, " > ");
  1066.   strcat (cmd, fname2);
  1067.   if ((pp = fopen (fname1, "w")) == NULL) {
  1068.     cmxputs ("Could not open temp file to execute command\n");
  1069.     *modified = FALSE;
  1070.     free (cmd);
  1071.     return (text);
  1072.   }
  1073.   fprintf (pp, "%s", text);
  1074.   fclose (pp);
  1075.   system(cmd);
  1076.   free (cmd);
  1077.   unlink(fname1);
  1078.  
  1079.   if (stat(fname2, &sbuf) == -1) {
  1080.     cmxputs ("?Temporary file missing\n");
  1081.     return (text);
  1082.   }
  1083.   len = sbuf.st_size;
  1084.   if ((output = (char *) malloc (len+1)) == NULL) {
  1085.     cmxputs ("?Out of memory\n");
  1086.     *modified = FALSE;
  1087.     unlink(fname2);
  1088.     return (text);
  1089.   }
  1090.   if ((fd = open(fname2, O_RDONLY,0)) < 0) {
  1091.     cmxputs("?Could not open temporary file for read.\n"); 
  1092.     perror(fname2);
  1093.     unlink(fname2);
  1094.     free (output);
  1095.     return(text);
  1096.   }
  1097. #if CCMD_OS_MSDOS
  1098.   if (read(fd,output,len) < 0)
  1099. #else
  1100.   if (read(fd,output,len) != len)
  1101. #endif
  1102.   {
  1103.     cmxputs("?Could not read temporary file.\n"); 
  1104.     perror(fname2);
  1105.     unlink(fname2);
  1106.     free (output);
  1107.     return(text);
  1108.   }
  1109.   close(fd);                /* close the file */
  1110.   output[len] = '\0';
  1111.   unlink (fname2);
  1112.   *modified = TRUE;
  1113.   *ret = FALSE;
  1114.   cmxputs("[Done]\n");
  1115.   return (output);
  1116. }
  1117.  
  1118.  
  1119.    
  1120. #if CCMD_OS_MSDOS
  1121. static char *
  1122. mktemp(dir,prefix) char *dir, *prefix; {
  1123.   static int inited=FALSE;
  1124.   int x;
  1125.   char name[100];
  1126.   struct stat sbuf;
  1127.   if (!inited++)
  1128.     srand(1);
  1129.   x = rand();
  1130.   if (dir == NULL)
  1131.     dir = "./";
  1132.   strcpy(name,dir);
  1133.   strcat(name,"\\");
  1134.   strcat(name,prefix);
  1135.   strcat(name,atoi(x));
  1136.   if (stat(name,&sbuf) == 0)
  1137.     return(mktemp(dir,prefix));
  1138.   return(name);
  1139. }
  1140. #endif /* CCMD_OS_MSDOS */
  1141.  
  1142. cm_para_abort() {
  1143.   abortf = TRUE;
  1144. }
  1145.  
  1146. cm_para_eof() {
  1147.   eof = TRUE;
  1148. }
  1149.  
  1150.  
  1151. /*
  1152.  * delete to beginning of line.   mostly taken from begact() in stdact.c
  1153.  */
  1154. static char *
  1155. begact(text,modified,ret) char *text; int *modified, *ret; {
  1156.   char *cp;                /* pointer to deletion site */
  1157.   int cc;                /* character under examination */
  1158.   char c;
  1159.   int eralen;                /* # of chars erased */
  1160.  
  1161.   *modified = FALSE;
  1162.   *ret = FALSE;
  1163.   if (strlen(text) == 0) return(text);
  1164.   cp = text + strlen(text) - 1;     /* point to end of buffer */
  1165.   while (cp-- != text) {        /* search for nonhidden newline */
  1166.     if (*cp == NEWLINE)            /* newline? */
  1167.       break;                /* yup, stop looking */
  1168.   }
  1169.   cp++;                    /* point to char after break */
  1170.   eralen = (text - cp) + strlen(text); /* get # of chars erased */
  1171.   if (eralen <= 0) return(text);
  1172.   if (cmcsb._cmflg2 & CM_CRT)
  1173.     delcurrent(eralen);            /* erase the characters */
  1174.   else {
  1175.     cmxputs("^U");            /* signal line kill on hardcopy */
  1176.     cmxnl();                /* move to a new line */
  1177.   }
  1178.   *modified = TRUE;
  1179.   text[strlen(text)-eralen] = '\0';
  1180.   return(text);
  1181. }
  1182.  
  1183. /*
  1184.  * wrdact:
  1185.  * delete backwards one word.  If at the beginning of a line, 
  1186.  * and previous line is empty, just deletes to beginning of
  1187.  * previous line.
  1188.  */
  1189. static char *
  1190. wrdact(text,modified,ret) char *text; int *modified, *ret; {
  1191.   char *cp;                /* pointer to deletion site */
  1192.   int cc;                /* character under examination */
  1193.   char c;
  1194.   int eralen;                /* # of chars erased */
  1195.  
  1196.   *modified = FALSE;
  1197.   *ret = FALSE;
  1198.   if (strlen(text) == 0) {
  1199.     beep();
  1200.     return(text);
  1201.   }
  1202.   cp = text + strlen(text) - 1;     /* point to end of buffer */
  1203.   while (cp-- != text) {        /* search for a character which is */
  1204.     c = *cp;
  1205.     if ((c < '0') ||            /* not a letter or digit? */
  1206.      ((c > '9') && (c < 'A')) ||
  1207.      ((c > 'Z') && (c < 'a')) ||
  1208.      (c > 'z')
  1209.     )
  1210.       break;                /* yup, stop looking */
  1211.   }
  1212.   cp++;                    /* point to char after break */
  1213.   eralen = (text - cp) + cmcsb._cminc; /* get # of chars erased */
  1214.   if (eralen <= 0) return(text);
  1215.   if (cmcsb._cmflg2 & CM_CRT)
  1216.     delcurrent(eralen);            /* erase the characters */
  1217.   else {
  1218.     cmxputs("^W");            /* signal line kill on hardcopy */
  1219.   }
  1220.   *modified = TRUE;
  1221.   text[strlen(text)-eralen] = '\0';    /* modify in place */
  1222.   return(text);
  1223. }
  1224.  
  1225. /* fixact
  1226. **
  1227. ** Purpose:
  1228. **   Refresh the display of the current line of text, back to the
  1229. **   last unhidden newline character.  If the last character in the
  1230. **   buffer is a newline, the previous line is refreshed.
  1231. **/
  1232.  
  1233. static char *
  1234. fixact(text,modified,ret) char *text; int *modified, *ret; {
  1235.   char *cp;                /* pointer into buffer */
  1236.   int cc;                /* character under examination */
  1237.   char c;
  1238.   int reflen;                /* # of chars refreshed */
  1239.  
  1240.   *ret = FALSE;
  1241.   *modified = FALSE;
  1242.   if (strlen(text) == 0) return(text);
  1243.   cp = text + strlen(text) -1;        /* point to end of buffer */
  1244.  
  1245.   while (cp-- != text) {        /* search for nonhidden newline */
  1246.     if (*cp == NEWLINE)            /* newline? */
  1247.       break;                /* yup, stop looking */
  1248.   }
  1249.   cp++;                    /* point to char after break */
  1250.  
  1251.   reflen = (text - cp) + strlen(text); /* get # of chars to refresh */
  1252.  
  1253.   if (cmcsb._cmflg2 & CM_CRT)
  1254.     delcurrent(reflen);            /* erase the characters from screen */
  1255.   else {
  1256.     cmxputs("^R");            /* signal line kill on hardcopy */
  1257.     cmxnl();                /* move to a new line */
  1258.   }
  1259.   while (reflen-- > 0) {        /* retype buffer contents */
  1260.     c = (cc = *cp++) & CC_CHR;        /* get next char */
  1261.     cmechx(c);                /* do it again */
  1262.   }
  1263.   return(text);
  1264. }
  1265.  
  1266. /* quoact
  1267. **
  1268. ** Purpose:
  1269. **   Enter the next character into the buffer with its quote flag
  1270. **   turned on, so it will be treated as a normal character regardless
  1271. **   of any handling it would normally receive.
  1272. **/
  1273. static char *
  1274. quoact(text,modified,ret) char *text; int *modified, *ret; {
  1275.   int c;                /* quoted character */
  1276.   
  1277.   cmgetc(&c,cmcsb._cmij);        /* get another character */
  1278.   cmechx(c);                /* do it again */
  1279.   *modified = TRUE;            /* we modified it */
  1280.   *ret = FALSE;                /* don't return yet */
  1281.   text[strlen(text)+1] = '\0';  
  1282.   text[strlen(text)] = c;   /* | CC_QUO; */
  1283.   return(text);
  1284. }
  1285.  
  1286.  
  1287. /* delact
  1288. **
  1289. ** Purpose:
  1290. **   Erase back to and including the last non-hidden character in the
  1291. **   command buffer.
  1292. **/
  1293. static char *
  1294. delact(text,modified,ret) char *text; int *modified, *ret; {
  1295.   char *cp;                /* pointer to deletion site */
  1296.   int cc;                /* character under examination */
  1297.   char c;
  1298.   int eralen;                /* # of chars erased */
  1299.  
  1300.   *modified = FALSE;
  1301.   *ret = FALSE;
  1302.   if (strlen(text) == 0) {
  1303.     beep();
  1304.     return(text);
  1305.   }
  1306.   eralen = 1;
  1307.   if (cmcsb._cmflg2 & CM_CRT)
  1308.     delcurrent(eralen);            /* erase the characters */
  1309.   else {
  1310.     cmxputs("\\");            /* signal line kill on hardcopy */
  1311.   }
  1312.   *modified = TRUE;
  1313.   text[strlen(text)-eralen] = '\0';    /* modify in place */
  1314.   return(text);
  1315. }
  1316.  
  1317.  
  1318.  
  1319. /*
  1320.  * paragraph action char handler.
  1321.  * calls user defined handlers, fixes up text, and returns
  1322.  * CMxGO
  1323.  * Must perform context switch on ccmd's buffers, and maintain enough
  1324.  * buffer space for the current buffer
  1325.  */
  1326. break_hndlr(fdblist,brk,deferred) 
  1327. fdb *fdblist;
  1328. char brk;
  1329. int deferred;
  1330. {
  1331.   csb savecsb;
  1332.   jmp_buf rpbuf, erbuf;
  1333.   int col;
  1334.   int len, ret, modified;
  1335.   char *text, *ntext;
  1336.   int i;
  1337.  
  1338.   if (paraact[brk] == NULL) {
  1339.     cmsti1(brk,0);
  1340.     return(CMxGO);
  1341.   }
  1342.  
  1343.   if ((text = (char *)malloc(cmcsb._cminc+3)) == NULL) { /* space for buffer */
  1344.     return(PARAxNM);            /* and a few added chars */
  1345.   }
  1346.  
  1347.   for (i = 0; i < cmcsb._cminc; i++) {
  1348.     text[i] = cmcsb._cmptr[i] & 0x7f;
  1349.     if (text[i] == '\0') text[i] |= 0x80;
  1350.   }
  1351.   text[cmcsb._cminc] = '\0';
  1352.  
  1353.   savecsb = cmcsb;            /* save old state */
  1354.   cmcsb._cmrty = "";            /* no prompt here. */
  1355.   cmact(oldact);
  1356.   bcopy(cmrpjb,rpbuf,sizeof(jmp_buf));
  1357.   bcopy(cmerjb,erbuf,sizeof(jmp_buf));
  1358.  
  1359.   modified = ret = FALSE;        /* default values */
  1360.  
  1361.   if (paraact1[brk] != NULL) {        /* call handler with text */
  1362.     ntext = (*paraact1[brk])(text,&modified,&ret);
  1363.   }
  1364.   else
  1365.       ntext = NULL;
  1366.   col = cmcsb._cmcol;            /* need to remember where we were on */
  1367.                     /* the screen.   this is independent */
  1368.                     /* of the rest of the csb state. */
  1369.  
  1370.   cmcsb = savecsb;            /* restore old state */
  1371.   cmcsb._cmcol = col;
  1372.   bcopy(rpbuf,cmrpjb,sizeof(jmp_buf));
  1373.   bcopy(erbuf,cmerjb,sizeof(jmp_buf));
  1374.   cmact(paraact);
  1375.  
  1376.   if (text != ntext) {            /* new buffer. */
  1377.     free(text);                /* get rid of old one */
  1378.     text = NULL;
  1379.   }
  1380.  
  1381.   if (modified) {
  1382.     if (strlen(ntext) >= 
  1383.     cmcsb._cmcnt + cmcsb._cminc) { /* out of space? */
  1384.                     /* then get some more space */
  1385.       cmcsb._cmcnt = strlen(ntext);
  1386.       cmcsb._cminc = 0;
  1387.       if ((cmdbuf = 
  1388.     (int *)cmrealloc(cmdbuf, (cmcsb._cmcnt + BSIZ) * sizeof(int)))==NULL) {
  1389.     return(PARAxNM);
  1390.       }
  1391.       cmcsb._cmcnt += BSIZ;        /* count it */
  1392.       if ((cmcsb._cmwbp = 
  1393.        (char *)cmrealloc(cmcsb._cmwbp,
  1394.                  sizeof(*cmcsb._cmwbp)*cmcsb._cmcnt))==NULL){
  1395.     return(PARAxNM);
  1396.       }
  1397.       cmcsb._cmwbc = cmcsb._cmcnt;    /* and install it into the CSB */
  1398.       cmcsb._cmptr = cmdbuf;
  1399.       cmcsb._cmbfp = cmdbuf;
  1400.       cmcsb._cmcur = cmdbuf;
  1401.     }
  1402.     else {
  1403.       cmcsb._cmptr = cmcsb._cmcur = cmcsb._cmbfp;
  1404.       cmcsb._cmcnt += cmcsb._cminc;
  1405.       cmcsb._cminc = 0;
  1406.       cmcsb._cmwbc = cmcsb._cmcnt;
  1407.     }
  1408.     len = strlen(ntext);
  1409.     for (i = 0; i < len; i++)        /* unquote everything */
  1410.       ntext[i] &= 0x7f;
  1411.     cmsti(ntext,CC_NEC|CC_HID|CC_QUO);        /* insert text into buffer */
  1412.     for (i = 0; i < cmcsb._cminc; i++)
  1413.       cmcsb._cmptr[i] &= ~(CC_HID|CC_NEC); /* mark it unhidden */
  1414.   }
  1415.   eof = ret;
  1416.   if (ntext)
  1417.     free(ntext);
  1418.   return(CMxGO);
  1419. }
  1420.  
  1421. char *
  1422. self_ins_nl(text, modified, ret)
  1423. char *text;
  1424. int *modified, *ret;
  1425. {
  1426.   strcat(text,"\n");
  1427.   cmechx('\n');
  1428.   *modified = TRUE;
  1429.   return(text);
  1430. }
  1431.  
  1432. install_nl_action()
  1433. {
  1434.   paraact['\n'] = break_hndlr;
  1435.   paraact1['\n'] = self_ins_nl;
  1436. }
  1437.  
  1438.