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