home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / code / microema.sit / src / random.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-09  |  27.5 KB  |  1,159 lines  |  [TEXT/Earl]

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