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