home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 198_02 / random.c < prev    next >
C/C++ Source or Header  |  1990-01-23  |  30KB  |  1,103 lines

  1. /*
  2.  * This file contains the command processing functions for a number of random
  3.  * commands. There is no functional grouping here, for sure.
  4.  */
  5.  
  6. #include        <stdio.h>
  7. #include    "estruct.h"
  8. #include        "edef.h"
  9.  
  10. /*
  11.  * Set fill column to n.
  12.  */
  13. setfillcol(f, n)
  14. {
  15.         fillcol = n;
  16.     mlwrite("[Fill column is %d]",n);
  17.         return(TRUE);
  18. }
  19.  
  20. /*
  21.  * Display the current position of the cursor, in origin 1 X-Y coordinates,
  22.  * the character that is under the cursor (in hex), and the fraction of the
  23.  * text that is before the cursor. The displayed column is not the current
  24.  * column, but the column that would be used on an infinite width display.
  25.  * Normally this is bound to "C-X =".
  26.  */
  27. showcpos(f, n)
  28. {
  29.         register LINE   *lp;        /* current line */
  30.         register long   numchars;    /* # of chars in file */
  31.         register int    numlines;    /* # of lines in file */
  32.         register long   predchars;    /* # chars preceding point */
  33.         register int    predlines;    /* # lines preceding point */
  34.         register int    curchar;    /* character under cursor */
  35.         int ratio;
  36.         int col;
  37.     int savepos;            /* temp save for current offset */
  38.     int ecol;            /* column pos/end of current line */
  39.  
  40.     /* starting at the beginning of the buffer */
  41.         lp = lforw(curbp->b_linep);
  42.  
  43.     /* start counting chars and lines */
  44.         numchars = 0;
  45.         numlines = 0;
  46.         while (lp != curbp->b_linep) {
  47.         /* if we are on the current line, record it */
  48.         if (lp == curwp->w_dotp) {
  49.             predlines = numlines;
  50.             predchars = numchars + curwp->w_doto;
  51.             if ((curwp->w_doto) == llength(lp))
  52.                 curchar = '\n';
  53.             else
  54.                 curchar = lgetc(lp, curwp->w_doto);
  55.         }
  56.         /* on to the next line */
  57.         ++numlines;
  58.         numchars += llength(lp) + 1;
  59.         lp = lforw(lp);
  60.         }
  61.  
  62.     /* if at end of file, record it */
  63.     if (curwp->w_dotp == curbp->b_linep) {
  64.         predlines = numlines;
  65.         predchars = numchars;
  66.         curchar = '\n';
  67.     }
  68.  
  69.     /* Get real column and end-of-line column. */
  70.     col = getccol(FALSE);
  71.     savepos = curwp->w_doto;
  72.     curwp->w_doto = llength(curwp->w_dotp);
  73.     ecol = getccol(FALSE);
  74.     curwp->w_doto = savepos;
  75.  
  76.         ratio = 0;              /* Ratio before dot. */
  77.         if (numchars != 0)
  78.                 ratio = (100L*predchars) / numchars;
  79.  
  80.     /* summarize and report the info */
  81.     mlwrite("Line %d/%d Col %d/%d Char %D/%D (%d%%) char = 0x%x (%d)",
  82.         predlines+1, numlines+1, col, ecol,
  83.         predchars, numchars, ratio, curchar, curchar);
  84.         return (TRUE);
  85. }
  86.  
  87. getcline()    /* get the current line number */
  88.  
  89. {
  90.         register LINE   *lp;        /* current line */
  91.         register int    numlines;    /* # of lines before point */
  92.  
  93.     /* starting at the beginning of the buffer */
  94.         lp = lforw(curbp->b_linep);
  95.  
  96.     /* start counting lines */
  97.         numlines = 0;
  98.         while (lp != curbp->b_linep) {
  99.         /* if we are on the current line, record it */
  100.         if (lp == curwp->w_dotp)
  101.             break;
  102.         ++numlines;
  103.         lp = lforw(lp);
  104.         }
  105.  
  106.     /* and return the resulting count */
  107.     return(numlines + 1);
  108. }
  109.  
  110. /*
  111.  * Return current column.  Stop at first non-blank given TRUE argument.
  112.  */
  113. getccol(bflg)
  114. int bflg;
  115. {
  116.         register int c, i, col;
  117.         col = 0;
  118.         for (i=0; i<curwp->w_doto; ++i) {
  119.                 c = lgetc(curwp->w_dotp, i);
  120.                 if (c!=' ' && c!='\t' && bflg)
  121.                         break;
  122.                 if (c == '\t')
  123.                         col += tabsize - (col % tabsize) - 1;
  124.                 else if ((c&0x7F) < 0x20 || (c&0x7F) == 0x7F)
  125.                         ++col;
  126.                 ++col;
  127.         }
  128.         return(col);
  129. }
  130.  
  131. /*
  132.  * Set current column.
  133.  */
  134. setccol(pos)
  135.  
  136. int pos;    /* position to set cursor */
  137.  
  138. {
  139.         register int c;        /* character being scanned */
  140.     register int i;        /* index into current line */
  141.     register int col;    /* current cursor column   */
  142.     register int llen;    /* length of line in bytes */
  143.  
  144.     col = 0;
  145.     llen = llength(curwp->w_dotp);
  146.  
  147.     /* scan the line until we are at or past the target column */
  148.     for (i = 0; i < llen; ++i) {
  149.         /* upon reaching the target, drop out */
  150.         if (col >= pos)
  151.             break;
  152.  
  153.         /* advance one character */
  154.                 c = lgetc(curwp->w_dotp, i);
  155.                 if (c == '\t')
  156.                         col += tabsize - (col % tabsize) - 1;
  157.                 else if ((c&0x7F) < 0x20 || (c&0x7F) == 0x7F)
  158.                         ++col;
  159.                 ++col;
  160.         }
  161.  
  162.     /* set us at the new position */
  163.     curwp->w_doto = i;
  164.  
  165.     /* and tell weather we made it */
  166.     return(col >= pos);
  167. }
  168.  
  169. /*
  170.  * Twiddle the two characters on either side of dot. If dot is at the end of
  171.  * the line twiddle the two characters before it. Return with an error if dot
  172.  * is at the beginning of line; it seems to be a bit pointless to make this
  173.  * work. This fixes up a very common typo with a single stroke. Normally bound
  174.  * to "C-T". This always works within a line, so "WFEDIT" is good enough.
  175.  */
  176. twiddle(f, n)
  177. {
  178.         register LINE   *dotp;
  179.         register int    doto;
  180.         register int    cl;
  181.         register int    cr;
  182.  
  183.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  184.         return(rdonly());    /* we are in read only mode    */
  185.         dotp = curwp->w_dotp;
  186.         doto = curwp->w_doto;
  187.         if (doto==llength(dotp) && --doto<0)
  188.                 return (FALSE);
  189.         cr = lgetc(dotp, doto);
  190.         if (--doto < 0)
  191.                 return (FALSE);
  192.         cl = lgetc(dotp, doto);
  193.         lputc(dotp, doto+0, cr);
  194.         lputc(dotp, doto+1, cl);
  195.         lchange(WFEDIT);
  196.         return (TRUE);
  197. }
  198.  
  199. /*
  200.  * Quote the next character, and insert it into the buffer. All the characters
  201.  * are taken literally, with the exception of the newline, which always has
  202.  * its line splitting meaning. The character is always read, even if it is
  203.  * inserted 0 times, for regularity. Bound to "C-Q"
  204.  */
  205. quote(f, n)
  206. {
  207.         register int    s;
  208.         register int    c;
  209.  
  210.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  211.         return(rdonly());    /* we are in read only mode    */
  212.         c = tgetc();
  213.         if (n < 0)
  214.                 return (FALSE);
  215.         if (n == 0)
  216.                 return (TRUE);
  217.         if (c == '\n') {
  218.                 do {
  219.                         s = lnewline();
  220.                 } while (s==TRUE && --n);
  221.                 return (s);
  222.         }
  223.         return (linsert(n, c));
  224. }
  225.  
  226. /*
  227.  * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
  228.  * tab into file.  If given argument, n, of zero, change to true tabs.
  229.  * If n > 1, simulate tab stop every n-characters using spaces. This has to be
  230.  * done in this slightly funny way because the tab (in ASCII) has been turned
  231.  * into "C-I" (in 10 bit code) already. Bound to "C-I".
  232.  */
  233. tab(f, n)
  234. {
  235.         if (n < 0)
  236.                 return (FALSE);
  237.         if (n == 0 || n > 1) {
  238.                 stabsize = n;
  239.                 return(TRUE);
  240.         }
  241.         if (! stabsize)
  242.                 return(linsert(1, '\t'));
  243.         return(linsert(stabsize - (getccol(FALSE) % stabsize), ' '));
  244. }
  245.  
  246. #if    AEDIT
  247. detab(f, n)        /* change tabs to spaces */
  248.  
  249. int f,n;    /* default flag and numeric repeat count */
  250.  
  251. {
  252.     register int inc;    /* increment to next line [sgn(n)] */
  253.  
  254.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  255.         return(rdonly());    /* we are in read only mode    */
  256.  
  257.     if (f == FALSE)
  258.         n = 1;
  259.  
  260.     /* loop thru detabbing n lines */
  261.     inc = ((n > 0) ? 1 : -1);
  262.     while (n) {
  263.         curwp->w_doto = 0;    /* start at the beginning */
  264.  
  265.         /* detab the entire current line */
  266.         while (curwp->w_doto < llength(curwp->w_dotp)) {
  267.             /* if we have a tab */
  268.             if (lgetc(curwp->w_dotp, curwp->w_doto) == '\t') {
  269.                 ldelete(1L, FALSE);
  270.                 insspace(TRUE,
  271.                     tabsize - (curwp->w_doto % tabsize));
  272.             }
  273.             forwchar(FALSE, 1);
  274.         }
  275.  
  276.         /* advance/or back to the next line */
  277.         forwline(TRUE, inc);
  278.         n -= inc;
  279.     }
  280.     curwp->w_doto = 0;    /* to the begining of the line */
  281.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  282.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  283.     return(TRUE);
  284. }
  285.  
  286. entab(f, n)        /* change spaces to tabs where posible */
  287.  
  288. int f,n;    /* default flag and numeric repeat count */
  289.  
  290. {
  291.     register int inc;    /* increment to next line [sgn(n)] */
  292.     register int fspace;    /* pointer to first space if in a run */
  293.     register int ccol;    /* current cursor column */
  294.     register char cchar;    /* current character */
  295.  
  296.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  297.         return(rdonly());    /* we are in read only mode    */
  298.  
  299.     if (f == FALSE)
  300.         n = 1;
  301.  
  302.     /* loop thru entabbing n lines */
  303.     inc = ((n > 0) ? 1 : -1);
  304.     while (n) {
  305.         curwp->w_doto = 0;    /* start at the beginning */
  306.  
  307.         /* entab the entire current line */
  308.         fspace = -1;
  309.         ccol = 0;
  310.         while (curwp->w_doto < llength(curwp->w_dotp)) {
  311.             /* see if it is time to compress */
  312.             if ((fspace >= 0) && (nextab(fspace) <= ccol))
  313.                 if (ccol - fspace < 2)
  314.                     fspace = -1;
  315.                 else {
  316.         /* there is a bug here dealing with mixed space/tabed
  317.            lines.......it will get fixed        */
  318.         /* WB 4/21/88 - casted ldelete arg to long */
  319.                     backchar(TRUE, ccol - fspace);
  320.                     ldelete( (long) (ccol-fspace), FALSE);
  321.                     linsert(1, '\t');    
  322.                     fspace = -1;
  323.                 }
  324.  
  325.             /* get the current character */
  326.             cchar = lgetc(curwp->w_dotp, curwp->w_doto);
  327.  
  328.             switch (cchar) {
  329.                 case '\t': /* a tab...count em up */
  330.                     ccol = nextab(ccol);
  331.                     break;
  332.  
  333.                 case ' ':  /* a space...compress? */
  334.                     if (fspace == -1)
  335.                         fspace = ccol;
  336.                     ccol++;
  337.                     break;
  338.  
  339.                 default:   /* any other char...just count */
  340.                     ccol++;
  341.                     fspace = -1;
  342.                     break;
  343.             }
  344.             forwchar(FALSE, 1);
  345.         }
  346.  
  347.         /* advance/or back to the next line */
  348.         forwline(TRUE, inc);
  349.         n -= inc;
  350.     }
  351.     curwp->w_doto = 0;    /* to the begining of the line */
  352.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  353.     lchange(WFEDIT);    /* yes, we have made at least an edit */
  354.     return(TRUE);
  355. }
  356.  
  357. trim(f, n)    /* trim trailing whitespace from the point to eol */
  358.  
  359. int f,n;    /* default flag and numeric repeat count */
  360.  
  361. {
  362.     register LINE *lp;    /* current line pointer */
  363.     register int offset;    /* original line offset position */
  364.     register int length;    /* current length */
  365.     register int inc;    /* increment to next line [sgn(n)] */
  366.  
  367.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  368.         return(rdonly());    /* we are in read only mode    */
  369.  
  370.     if (f == FALSE)
  371.         n = 1;
  372.  
  373.     /* loop thru trimming n lines */
  374.     inc = ((n > 0) ? 1 : -1);
  375.     while (n) {
  376.         lp = curwp->w_dotp;        /* find current line text */
  377.         offset = curwp->w_doto;        /* save original offset */
  378.         length = lp->l_used;        /* find current length */
  379.  
  380.         /* trim the current line */
  381.         while (length > offset) {
  382.             if (lgetc(lp, length-1) != ' ' &&
  383.                 lgetc(lp, length-1) != '\t')
  384.                     break;
  385.             length--;
  386.         }
  387.         lp->l_used = length;
  388.  
  389.         /* advance/or back to the next line */
  390.         forwline(TRUE, inc);
  391.         n -= inc;
  392.     }
  393.     lchange(WFEDIT);
  394.     thisflag &= ~CFCPCN;    /* flag that this resets the goal column */
  395.     return(TRUE);
  396. }
  397. #endif
  398.  
  399. /*
  400.  * Open up some blank space. The basic plan is to insert a bunch of newlines,
  401.  * and then back up over them. Everything is done by the subcommand
  402.  * procerssors. They even handle the looping. Normally this is bound to "C-O".
  403.  */
  404. openline(f, n)
  405. {
  406.         register int    i;
  407.         register int    s;
  408.  
  409.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  410.         return(rdonly());    /* we are in read only mode    */
  411.         if (n < 0)
  412.                 return (FALSE);
  413.         if (n == 0)
  414.                 return (TRUE);
  415.         i = n;                                  /* Insert newlines.     */
  416.         do {
  417.                 s = lnewline();
  418.         } while (s==TRUE && --i);
  419.         if (s == TRUE)                          /* Then back up overtop */
  420.                 s = backchar(f, n);             /* of them all.         */
  421.         return (s);
  422. }
  423.  
  424. /*
  425.  * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
  426.  * indentation as specified.
  427.  */
  428. newline(f, n)
  429. {
  430.     register int    s;
  431.  
  432.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  433.         return(rdonly());    /* we are in read only mode    */
  434.     if (n < 0)
  435.         return (FALSE);
  436.  
  437.     /* if we are in C mode and this is a default <NL> */
  438.     if (n == 1 && (curbp->b_mode & MDCMOD) &&
  439.         curwp->w_dotp != curbp->b_linep)
  440.         return(cinsert());
  441.  
  442.         /*
  443.          * If a newline was typed, fill column is defined, the argument is non-
  444.          * negative, wrap mode is enabled, and we are now past fill column,
  445.      * and we are not read-only, perform word wrap.
  446.          */
  447.         if ((curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 &&
  448.         getccol(FALSE) > fillcol &&
  449.         (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
  450.         execute(FUNC|'W', HOOK, 1);
  451.  
  452.     /* insert some lines */
  453.     while (n--) {
  454.         if ((s=lnewline()) != TRUE)
  455.             return (s);
  456.     }
  457.     return (TRUE);
  458. }
  459.  
  460. cinsert()    /* insert a newline and indentation for C */
  461.  
  462. {
  463.     register char *cptr;    /* string pointer into text to copy */
  464.     register int tptr;    /* index to scan into line */
  465.     register int bracef;    /* was there a brace at the end of line? */
  466.     register int i;
  467.     char ichar[NSTRING];    /* buffer to hold indent of last line */
  468.  
  469.     /* grab a pointer to text to copy indentation from */
  470.     cptr = &curwp->w_dotp->l_text[0];
  471.  
  472.     /* check for a brace */
  473.     tptr = curwp->w_doto - 1;
  474.     bracef = (cptr[tptr] == '{');
  475.  
  476.     /* save the indent of the previous line */
  477.     i = 0;
  478.     while ((i < tptr) && (cptr[i] == ' ' || cptr[i] == '\t')
  479.         && (i < NSTRING - 1)) {
  480.         ichar[i] = cptr[i];
  481.         ++i;
  482.     }
  483.     ichar[i] = 0;        /* terminate it */
  484.  
  485.     /* put in the newline */
  486.     if (lnewline() == FALSE)
  487.         return(FALSE);
  488.  
  489.     /* and the saved indentation */
  490.     i = 0;
  491.     while (ichar[i])
  492.         linsert(1, ichar[i++]);
  493.  
  494.     /* and one more tab for a brace */
  495.     if (bracef)
  496.         tab(FALSE, 1);
  497.  
  498.     return(TRUE);
  499. }
  500.  
  501. insbrace(n, c)    /* insert a brace into the text here...we are in CMODE */
  502.  
  503. int n;    /* repeat count */
  504. int c;    /* brace to insert (always { for now) */
  505.  
  506. {
  507.     register int ch;    /* last character before input */
  508.     register int i;
  509.     register int target;    /* column brace should go after */
  510.  
  511.     /* if we are at the beginning of the line, no go */
  512.     if (curwp->w_doto == 0)
  513.         return(linsert(n,c));
  514.  
  515.     /* scan to see if all space before this is white space */
  516.     for (i = curwp->w_doto - 1; i >= 0; --i) {
  517.         ch = lgetc(curwp->w_dotp, i);
  518.         if (ch != ' ' && ch != '\t')
  519.             return(linsert(n, c));
  520.     }
  521.  
  522.     /* delete back first */
  523.     target = getccol(FALSE);    /* calc where we will delete to */
  524.     target -= 1;
  525.     target -= target % (stabsize == 0 ? tabsize : stabsize);
  526.     while (getccol(FALSE) > target)
  527.         backdel(FALSE, 1);
  528.  
  529.     /* and insert the required brace(s) */
  530.     return(linsert(n, c));
  531. }
  532.  
  533. inspound()    /* insert a # into the text here...we are in CMODE */
  534.  
  535. {
  536.     register int ch;    /* last character before input */
  537.     register int i;
  538.  
  539.     /* if we are at the beginning of the line, no go */
  540.     if (curwp->w_doto == 0)
  541.         return(linsert(1,'#'));
  542.  
  543.     /* scan to see if all space before this is white space */
  544.     for (i = curwp->w_doto - 1; i >= 0; --i) {
  545.         ch = lgetc(curwp->w_dotp, i);
  546.         if (ch != ' ' && ch != '\t')
  547.             return(linsert(1, '#'));
  548.     }
  549.  
  550.     /* delete back first */
  551.     while (getccol(FALSE) >= 1)
  552.         backdel(FALSE, 1);
  553.  
  554.     /* and insert the required pound */
  555.     return(linsert(1, '#'));
  556. }
  557.  
  558. /*
  559.  * Delete blank lines around dot. What this command does depends if dot is
  560.  * sitting on a blank line. If dot is sitting on a blank line, this command
  561.  * deletes all the blank lines above and below the current line. If it is
  562.  * sitting on a non blank line then it deletes all of the blank lines after
  563.  * the line. Normally this command is bound to "C-X C-O". Any argument is
  564.  * ignored.
  565.  */
  566. deblank(f, n)
  567. {
  568.         register LINE   *lp1;
  569.         register LINE   *lp2;
  570.         long nld;
  571.  
  572.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  573.         return(rdonly());    /* we are in read only mode    */
  574.         lp1 = curwp->w_dotp;
  575.         while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
  576.                 lp1 = lp2;
  577.         lp2 = lp1;
  578.         nld = 0;
  579.         while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
  580.                 ++nld;
  581.         if (nld == 0)
  582.                 return (TRUE);
  583.         curwp->w_dotp = lforw(lp1);
  584.         curwp->w_doto = 0;
  585.         return (ldelete(nld, FALSE));
  586. }
  587.  
  588. /*
  589.  * Insert a newline, then enough tabs and spaces to duplicate the indentation
  590.  * of the previous line. Assumes tabs are every eight characters. Quite simple.
  591.  * Figure out the indentation of the current line. Insert a newline by calling
  592.  * the standard routine. Insert the indentation by inserting the right number
  593.  * of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
  594.  * subcomands failed. Normally bound to "C-J".
  595.  */
  596. indent(f, n)
  597. {
  598.         register int    nicol;
  599.         register int    c;
  600.         register int    i;
  601.  
  602.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  603.         return(rdonly());    /* we are in read only mode    */
  604.         if (n < 0)
  605.                 return (FALSE);
  606.         while (n--) {
  607.                 nicol = 0;
  608.                 for (i=0; i<llength(curwp->w_dotp); ++i) {
  609.                         c = lgetc(curwp->w_dotp, i);
  610.                         if (c!=' ' && c!='\t')
  611.                                 break;
  612.                         if (c == '\t')
  613.                                 nicol += tabsize - (nicol % tabsize) - 1;
  614.                         ++nicol;
  615.                 }
  616.                 if (lnewline() == FALSE
  617.                 || ((i=nicol/tabsize)!=0 && linsert(i, '\t')==FALSE)
  618.                 || ((i=nicol%tabsize)!=0 && linsert(i,  ' ')==FALSE))
  619.                         return (FALSE);
  620.         }
  621.         return (TRUE);
  622. }
  623.  
  624. /*
  625.  * Delete forward. This is real easy, because the basic delete routine does
  626.  * all of the work. Watches for negative arguments, and does the right thing.
  627.  * If any argument is present, it kills rather than deletes, to prevent loss
  628.  * of text if typed with a big argument. Normally bound to "C-D".
  629.  */
  630. forwdel(f, n)
  631. {
  632.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  633.         return(rdonly());    /* we are in read only mode    */
  634.         if (n < 0)
  635.                 return (backdel(f, -n));
  636.         if (f != FALSE) {                       /* Really a kill.       */
  637.                 if ((lastflag&CFKILL) == 0)
  638.                         kdelete();
  639.                 thisflag |= CFKILL;
  640.         }
  641.         else ykchar = ((curwp->w_doto == curwp->w_dotp->l_used)? '\n':
  642.             lgetc(curwp->w_dotp, curwp->w_doto));
  643.         return (ldelete((long)n, f));
  644. }
  645.  
  646. /*
  647.  * Delete backwards. This is quite easy too, because it's all done with other
  648.  * functions. Just move the cursor back, and delete forwards. Like delete
  649.  * forward, this actually does a kill if presented with an argument. Bound to
  650.  * both "RUBOUT" and "C-H".
  651.  */
  652. backdel(f, n)
  653. {
  654.         register int    s;
  655.  
  656.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  657.         return(rdonly());    /* we are in read only mode    */
  658.         if (n < 0)
  659.                 return (forwdel(f, -n));
  660.         if (f != FALSE) {                       /* Really a kill.       */
  661.                 if ((lastflag&CFKILL) == 0)
  662.                         kdelete();
  663.                 thisflag |= CFKILL;
  664.         }
  665.         else ykchar = ((curwp->w_doto == 0)? '\n':
  666.             lgetc(curwp->w_dotp, (curwp->w_doto-1)));
  667.         if ((s=backchar(f, n)) == TRUE)
  668.                 s = ldelete((long)n, f);
  669.         return (s);
  670. }
  671.  
  672. /*
  673.  * Kill text. If called without an argument, it kills from dot to the end of
  674.  * the line, unless it is at the end of the line, when it kills the newline.
  675.  * If called with an argument of 0, it kills from the start of the line to dot.
  676.  * If called with a positive argument, it kills from dot forward over that
  677.  * number of newlines. If called with a negative argument it kills backwards
  678.  * that number of newlines. Normally bound to "C-K".
  679.  */
  680.  
  681. killtext(f, n)
  682. {
  683.     return( killtxt(f, n, FALSE) );
  684. }
  685.  
  686. #if DECEDT
  687. delfline(f, n)
  688. {
  689.     return( killtxt(f, n, TRUE) );
  690. }
  691. #endif
  692.  
  693. killtxt(f, n, delflag)
  694. {
  695.         register LINE   *nextp;
  696.         long chunk;
  697.  
  698.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  699.         return(rdonly());    /* we are in read only mode    */
  700.         if ((lastflag&CFKILL) == 0)             /* Clear kill buffer if */
  701.                 kdelete();                      /* last wasn't a kill.  */
  702.         thisflag |= CFKILL;
  703.         if (f == FALSE) {
  704.                 chunk = llength(curwp->w_dotp)-curwp->w_doto;
  705.                 if ((delflag == TRUE) || (chunk == 0))
  706.                         ++chunk;
  707.         } else if (n == 0) {
  708.                 chunk = curwp->w_doto;
  709.                 curwp->w_doto = 0;
  710.         } else if (n > 0) {
  711.                 chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
  712.                 nextp = lforw(curwp->w_dotp);
  713.                 while (--n) {
  714.                         if (nextp == curbp->b_linep)
  715.                                 return (FALSE);
  716.                         chunk += llength(nextp)+1;
  717.                         nextp = lforw(nextp);
  718.                 }
  719.         } else {
  720.                 mlwrite("neg kill");
  721.                 return (FALSE);
  722.         }
  723.         return(ldelete(chunk, TRUE));
  724. }
  725.  
  726. setmode(f, n)    /* prompt and set an editor mode */
  727.  
  728. int f, n;    /* default and argument */
  729.  
  730. {
  731.     adjustmode(TRUE, FALSE);
  732. }
  733.  
  734. delmode(f, n)    /* prompt and delete an editor mode */
  735.  
  736. int f, n;    /* default and argument */
  737.  
  738. {
  739.     adjustmode(FALSE, FALSE);
  740. }
  741.  
  742. setgmode(f, n)    /* prompt and set a global editor mode */
  743.  
  744. int f, n;    /* default and argument */
  745.  
  746. {
  747.     adjustmode(TRUE, TRUE);
  748. }
  749.  
  750. delgmode(f, n)    /* prompt and delete a global editor mode */
  751.  
  752. int f, n;    /* default and argument */
  753.  
  754. {
  755.     adjustmode(FALSE, TRUE);
  756. }
  757.  
  758. adjustmode(kind, global)    /* change the editor mode status */
  759.  
  760. int kind;    /* true = set,        false = delete */
  761. int global;    /* true = global flag,    false = current buffer flag */
  762. {
  763.     register char *scan;        /* scanning pointer to convert prompt */
  764.     register int i;            /* loop index */
  765.     register status;        /* error return on input */
  766. #if    COLOR
  767.     register int uflag;        /* was modename uppercase?    */
  768. #if    TERMCAP | VMSVT
  769.     extern int usedcolor, isansi;
  770. #endif
  771. #endif
  772.     char prompt[50];    /* string to prompt user with */
  773.     char cbuf[NPAT];        /* buffer to recieve mode name into */
  774.  
  775.     /* build the proper prompt string */
  776.     if (global)
  777.         strcpy(prompt,"Global mode to ");
  778.     else
  779.         strcpy(prompt,"Mode to ");
  780.  
  781.     if (kind == TRUE)
  782.         strcat(prompt, "add: ");
  783.     else
  784.         strcat(prompt, "delete: ");
  785.  
  786.     /* prompt the user and get an answer */
  787.  
  788.     status = mlreply(prompt, cbuf, NPAT - 1);
  789.     if (status != TRUE)
  790.         return(status);
  791.  
  792.     /* make it uppercase */
  793.  
  794.     scan = cbuf;
  795. #if    COLOR
  796.     uflag = (*scan >= 'A' && *scan <= 'Z');
  797. #endif
  798.     while (*scan != 0) {
  799.         if (*scan >= 'a' && *scan <= 'z')
  800.             *scan = *scan - 32;
  801.         scan++;
  802.     }
  803.  
  804.     /* test it first against the colors we know */
  805.     for (i=0; i<NCOLORS; i++) {
  806.         if (strcmp(cbuf, cname[i]) == 0) {
  807.             /* finding the match, we set the color */
  808. #if    COLOR
  809. #if    TERMCAP | VMSVT
  810.             if (isansi) {
  811.                 usedcolor = TRUE;
  812.                 eolexist = FALSE;
  813.             }
  814. #endif
  815.             if (uflag)
  816.                 if (global)
  817.                     gfcolor = i;
  818.                 else
  819.                     curwp->w_fcolor = i;
  820.             else
  821.                 if (global)
  822.                     gbcolor = i;
  823.                 else
  824.                     curwp->w_bcolor = i;
  825.  
  826.             curwp->w_flag |= WFCOLR;
  827. #endif
  828.             mlerase();
  829.             return(TRUE);
  830.         }
  831.     }
  832.  
  833.     /* test it against the modes we know */
  834.  
  835.     for (i=0; i < NUMMODES; i++) {
  836.         if (strcmp(cbuf, modename[i]) == 0) {
  837.             /* finding a match, we process it */
  838.             if (kind == TRUE)
  839.                 if (global)
  840.                     gmode |= (1 << i);
  841.                 else
  842.                     curbp->b_mode |= (1 << i);
  843.             else
  844.                 if (global)
  845.                     gmode &= ~(1 << i);
  846.                 else
  847.                     curbp->b_mode &= ~(1 << i);
  848.             /* display new mode line */
  849.             if (global == 0)
  850.                 upmode();
  851.             mlerase();    /* erase the junk */
  852.             return(TRUE);
  853.         }
  854.     }
  855.  
  856.     mlwrite("No such mode!");
  857.     return(FALSE);
  858. }
  859.  
  860. /*    This function simply clears the message line,
  861.         mainly for macro usage            */
  862.  
  863. clrmes(f, n)
  864.  
  865. int f, n;    /* arguments ignored */
  866.  
  867. {
  868.     mlforce("");
  869.     return(TRUE);
  870. }
  871.  
  872. /*    This function writes a string on the message line
  873.         mainly for macro usage            */
  874.  
  875. writemsg(f, n)
  876.  
  877. int f, n;    /* arguments ignored */
  878.  
  879. {
  880.     register int status;
  881.     char buf[NPAT];        /* buffer to recieve message into */
  882.  
  883.     if ((status = mlreply("Message to write: ", buf, NPAT - 1)) != TRUE)
  884.         return(status);
  885.  
  886.     /* expand all '%' to "%%" so mlwrite won't expect arguments */
  887.     makelit(buf, NPAT);
  888.  
  889.     /* write the message out */
  890.     mlforce(buf);
  891.     return(TRUE);
  892. }
  893.  
  894. #if    CFENCE
  895. /*    the cursor is moved to a matching fence    */
  896.  
  897. getfence(f, n)
  898.  
  899. int f, n;    /* not used */
  900.  
  901. {
  902.     register LINE *oldlp;    /* original line pointer */
  903.     register int oldoff;    /* and offset */
  904.     register int sdir;    /* direction of search (1/-1) */
  905.     register int count;    /* current fence level count */
  906.     register char ch;    /* fence type to match against */
  907.     register char ofence;    /* open fence */
  908.     register char c;    /* current character in scan */
  909.  
  910.     /* save the original cursor position */
  911.     oldlp = curwp->w_dotp;
  912.     oldoff = curwp->w_doto;
  913.  
  914.     /* get the current character */
  915.     if (oldoff == llength(oldlp))
  916.         ch = '\n';
  917.     else
  918.         ch = lgetc(oldlp, oldoff);
  919.  
  920.     /* setup proper matching fence */
  921.     switch (ch) {
  922.         case '(': ofence = ')'; sdir = FORWARD; break;
  923.         case '{': ofence = '}'; sdir = FORWARD; break;
  924.         case '[': ofence = ']'; sdir = FORWARD; break;
  925.         case '<': ofence = '>'; sdir = FORWARD; break;
  926.         case ')': ofence = '('; sdir = REVERSE; break;
  927.         case '}': ofence = '{'; sdir = REVERSE; break;
  928.         case ']': ofence = '['; sdir = REVERSE; break;
  929.         case '>': ofence = '<'; sdir = REVERSE; break;
  930.         default: TTbeep(); return(FALSE);
  931.     }
  932.  
  933.     /* set up for scan */
  934.     count = 1;
  935.  
  936.     /* scan until we find it, or reach the end of file */
  937.     while (count > 0) {
  938.         if (sdir == FORWARD)
  939.             {if (forwchar(FALSE, 1) == FALSE) break;}
  940.         else
  941.             {if (backchar(FALSE, 1) == FALSE) break;}
  942.  
  943.         if (curwp->w_doto == llength(curwp->w_dotp))
  944.             c = '\n';
  945.         else
  946.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  947.         if (c == ch)
  948.             ++count;
  949.         if (c == ofence)
  950.             --count;
  951.     }
  952.  
  953.     /* if count is zero, we have a match, move the sucker */
  954.     if (count == 0) {
  955.         curwp->w_flag |= WFMOVE;
  956.         return(TRUE);
  957.     }
  958.  
  959.     /* restore the current position */
  960.     curwp->w_dotp = oldlp;
  961.     curwp->w_doto = oldoff;
  962.     TTbeep();
  963.     return(FALSE);
  964. }
  965. #endif
  966.  
  967. /*    Close fences are matched against their partners, and if
  968.     on screen the cursor briefly lights there        */
  969.  
  970. fmatch(ch)
  971.  
  972. char ch;    /* fence type to match against */
  973.  
  974. {
  975.     register LINE *oldlp;    /* original line pointer */
  976.     register int oldoff;    /* and offset */
  977.     register LINE *toplp;    /* top line in current window */
  978.     register int count;    /* current fence level count */
  979.     register char opench;    /* open fence */
  980.     register char c;    /* current character in scan */
  981.     register int i;
  982.  
  983.     /* first get the display update out there */
  984.     update(FALSE);
  985.  
  986.     /* save the original cursor position */
  987.     oldlp = curwp->w_dotp;
  988.     oldoff = curwp->w_doto;
  989.  
  990.     /* setup proper open fence for passed close fence */
  991.     if (ch == ')')
  992.         opench = '(';
  993.     else if (ch == '}')
  994.         opench = '{';
  995.     else if (ch == ']')
  996.         opench = '[';
  997.     else
  998.         opench = '<';
  999.  
  1000.     /* find the top line and set up for scan */
  1001.     toplp = curwp->w_linep->l_bp;
  1002.     count = 1;
  1003.     backchar(FALSE, 1);
  1004.  
  1005.     /* scan back until we find it, or reach past the top of the window */
  1006.     while (count > 0 && backchar(FALSE, 1) == TRUE &&
  1007.             curwp->w_dotp != toplp) {
  1008.         if (curwp->w_doto == llength(curwp->w_dotp))
  1009.             c = '\n';
  1010.         else
  1011.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  1012.         if (c == ch)
  1013.             ++count;
  1014.         if (c == opench)
  1015.             --count;
  1016.     }
  1017.  
  1018.     /* if count is zero, we have a match, display the sucker */
  1019.     /* there is a real machine dependant timing problem here we have
  1020.        yet to solve......... */
  1021.     if (count == 0) {
  1022.         for (i = 0; i < term.t_pause; i++)
  1023.             update(FALSE);
  1024. #if    USG & MSC
  1025.         nap(250L);    /* pause for 250 ms */
  1026. #endif
  1027.     }
  1028.  
  1029.     /* restore the current position */
  1030.     curwp->w_dotp = oldlp;
  1031.     curwp->w_doto = oldoff;
  1032.     return(TRUE);
  1033. }
  1034.  
  1035. istring(f, n)    /* ask for and insert a string into the current
  1036.            buffer at the current point */
  1037.  
  1038. int f, n;    /* ignored arguments */
  1039.  
  1040. {
  1041.     register int status;    /* status return code */
  1042.     char tstring[NPAT+1];    /* string to add */
  1043.  
  1044.     /* ask for string to insert */
  1045.     status = mltreply("String to insert<META>: ", tstring, NPAT, metac);
  1046.     if (status != TRUE)
  1047.         return(status);
  1048.  
  1049.     if (f == FALSE)
  1050.         n = 1;
  1051.  
  1052.     if (n < 0)
  1053.         n = - n;
  1054.  
  1055.     /* insert it */
  1056.     while (n-- > 0 && status == TRUE)
  1057.         status = linstr(tstring);
  1058.  
  1059.     return(TRUE);
  1060. }
  1061.  
  1062. #if    DECEDT
  1063. /*
  1064.  * Display the length of a string which the cursor is inside.
  1065.  * Does not worry about backslashes.
  1066.  * Unbound.
  1067.  */
  1068. showslen(f, n)
  1069. {
  1070.     int i, left, right;
  1071.     char qch;
  1072.  
  1073.     left = right = (-1);
  1074.     if (llength(curwp->w_dotp) > 0)
  1075.         for (i=curwp->w_doto; i<llength(curwp->w_dotp); ++i) {
  1076.             qch = lgetc(curwp->w_dotp, i);
  1077.             if (qch == '\'' || qch == '\"') {right = i; break;}
  1078.             }
  1079.     if (right >= 0)
  1080.         for(i=curwp->w_doto-1; i>=0; --i)
  1081.             if (lgetc(curwp->w_dotp, i) == qch)
  1082.                 {left = i; break;}
  1083.     if (left >= 0)
  1084.         mlwrite("String length is %d", right - 1 - left);
  1085.     else
  1086.         mlwrite("[String not found]");
  1087.         return (TRUE);
  1088. }
  1089.  
  1090. /* set over write -- toggle overwrite mode */
  1091.  
  1092. setovrwrt(f, n)
  1093. {
  1094.     if (curwp->w_bufp->b_mode & MDOVER)
  1095.         curwp->w_bufp->b_mode &= ~MDOVER;
  1096.     else
  1097.         curwp->w_bufp->b_mode |= MDOVER;
  1098.     upmode();
  1099.     return (TRUE);
  1100. }
  1101. #endif
  1102.  
  1103.