home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / VILE327.ZIP / VILE327.TAR / vile3.27 / word.c < prev    next >
C/C++ Source or Header  |  1992-12-14  |  14KB  |  588 lines

  1. /*
  2.  * The routines in this file implement commands that work word or a
  3.  * paragraph at a time.  There are all sorts of word mode commands.  If I
  4.  * do any sentence mode commands, they are likely to be put in this file. 
  5.  *
  6.  * $Log: word.c,v $
  7.  * Revision 1.21  1992/08/20  23:40:48  foxharp
  8.  * typo fixes -- thanks, eric
  9.  *
  10.  * Revision 1.20  1992/06/12  22:23:42  foxharp
  11.  * changes for separate 'comments' r.e. for formatregion
  12.  *
  13.  * Revision 1.19  1992/06/03  08:40:22  foxharp
  14.  * initialize comment_char in formatregion, to suppress gcc warning
  15.  *
  16.  * Revision 1.18  1992/05/31  22:11:11  foxharp
  17.  * added C and shell comment reformatting
  18.  *
  19.  * Revision 1.17  1992/05/19  08:55:44  foxharp
  20.  * more prototype and shadowed decl fixups
  21.  *
  22.  * Revision 1.16  1992/05/16  12:00:31  pgf
  23.  * prototypes/ansi/void-int stuff/microsoftC
  24.  *
  25.  * Revision 1.15  1992/03/05  09:19:55  pgf
  26.  * changed some mlwrite() to mlforce(), due to new terse support
  27.  *
  28.  * Revision 1.14  1991/11/08  13:02:46  pgf
  29.  * ifdefed unneeded funcs
  30.  *
  31.  * Revision 1.13  1991/11/03  17:33:20  pgf
  32.  * use new lregexec() routine to check for patterns in lines
  33.  *
  34.  * Revision 1.12  1991/11/01  14:37:22  pgf
  35.  * saber cleanup
  36.  *
  37.  * Revision 1.11  1991/10/28  14:26:45  pgf
  38.  * eliminated TABVAL and fillcol macros -- now use curtabval and the VAL_FILL
  39.  * directly
  40.  *
  41.  * Revision 1.10  1991/10/28  01:01:06  pgf
  42.  * added start offset and end offset to regexec calls
  43.  *
  44.  * Revision 1.9  1991/10/27  01:57:45  pgf
  45.  * changed usage of issecbegin() in formatregion to use regexec instead
  46.  *
  47.  * Revision 1.8  1991/08/09  13:17:52  pgf
  48.  * formatregion now restarts with each fresh paragraph, so you can
  49.  * format an entire file at once, without collapsing it all into a
  50.  * single paragraph
  51.  *
  52.  * Revision 1.7  1991/08/07  12:35:07  pgf
  53.  * added RCS log messages
  54.  *
  55.  * revision 1.6
  56.  * date: 1991/08/06 15:27:52;
  57.  * removed old rdonly check
  58.  * 
  59.  * revision 1.5
  60.  * date: 1991/06/28 10:54:14;
  61.  * suppress trailing space after paragraph reformat
  62.  * 
  63.  * revision 1.4
  64.  * date: 1991/06/25 19:53:45;
  65.  * massive data structure restructure
  66.  * 
  67.  * revision 1.3
  68.  * date: 1991/06/06 13:58:09;
  69.  * added auto-indent mode
  70.  * 
  71.  * revision 1.2
  72.  * date: 1991/03/26 17:02:20;
  73.  * formatting now knows about ! and ? as well as .
  74.  * 
  75.  * revision 1.1
  76.  * date: 1990/09/21 10:26:25;
  77.  * initial vile RCS revision
  78.  */
  79.  
  80. #include    <stdio.h>
  81. #include    "estruct.h"
  82. #include    "edef.h"
  83.  
  84. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  85.  * line and stop on the first word-break or the beginning of the line. If we
  86.  * reach the beginning of the line, jump back to the end of the word and start
  87.  * a new line.    Otherwise, break the line at the word-break, eat it, and jump
  88.  * back to the end of the word.
  89.  * Returns TRUE on success, FALSE on errors.
  90.  */
  91. /* ARGSUSED */
  92. int
  93. wrapword(f,n)
  94. int f,n;
  95. {
  96.     register int cnt;    /* size of word wrapped to next line */
  97.     register int c;        /* character temporary */
  98.  
  99.     /* backup from the <NL> 1 char */
  100.     if (!backchar(0, 1))
  101.         return(FALSE);
  102.  
  103.     /* back up until we aren't in a word,
  104.        make sure there is a break in the line */
  105.     cnt = 0;
  106.     while (c = char_at(DOT), !isspace(c)) {
  107.         cnt++;
  108.         if (!backchar(0, 1))
  109.             return(FALSE);
  110.         /* if we make it to the beginning, start a new line */
  111.         if (DOT.o == 0) {
  112.             gotoeol(FALSE, 0);
  113.             return(lnewline());
  114.         }
  115.     }
  116.  
  117.     /* delete the forward white space */
  118.     if (!ldelete(1L, FALSE))
  119.         return(FALSE);
  120.  
  121.     /* put in a end of line */
  122.     if (!newline(TRUE,1))
  123.         return FALSE;
  124.  
  125.     /* and past the first word */
  126.     while (cnt-- > 0) {
  127.         if (forwchar(FALSE, 1) == FALSE)
  128.             return(FALSE);
  129.     }
  130.     return(TRUE);
  131. }
  132.  
  133.  
  134. /*
  135.  * Move the cursor forward by the specified number of words. All of the motion
  136.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  137.  *
  138.  * Returns of SORTOFTRUE result if we're doing a non-delete operation.  
  139.  * Whitespace after a word is always included on deletes (and non-operations,
  140.  * of course), but only on intermediate words for other operations, for
  141.  * example.  The last word of non-delete ops does _not_ include its whitespace.
  142.  */
  143.  
  144. int
  145. forwviword(f, n)
  146. int f,n;
  147. {
  148.     int s;
  149.  
  150.     if (n < 0)
  151.         return (backword(f, -n));
  152.     setchartype();
  153.     if (forwchar(FALSE, 1) == FALSE)
  154.         return (FALSE);
  155.     while (n--) {
  156.         while (((s = isnewviwordf()) == FALSE) || 
  157.                 (s == SORTOFTRUE && n != 0)) {
  158.             if (forwchar(FALSE, 1) == FALSE)
  159.                 return (FALSE);
  160.         }
  161.     }
  162.     return TRUE;
  163. }
  164.  
  165. /*
  166.  * Move the cursor forward by the specified number of words. All of the motion
  167.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  168.  */
  169. int
  170. forwword(f, n)
  171. int f,n;
  172. {
  173.     int s;
  174.  
  175.     if (n < 0)
  176.         return (backword(f, -n));
  177.     setchartype();
  178.     if (forwchar(FALSE, 1) == FALSE)
  179.         return (FALSE);
  180.     while (n--) {
  181.         while (((s = isnewwordf()) == FALSE) || 
  182.                 (s == SORTOFTRUE && n != 0)) {
  183.             if (forwchar(FALSE, 1) == FALSE)
  184.                 return (FALSE);
  185.         }
  186.     }
  187.     return(TRUE);
  188. }
  189.  
  190. /*
  191.  * Move the cursor forward by the specified number of words. All of the motion
  192.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  193.  */
  194. int
  195. forwviendw(f, n)
  196. int f,n;
  197. {
  198.     int s = FALSE;
  199.     if (!f)
  200.         n = 1;
  201.     else if (n <= 0)
  202.         return (FALSE);
  203.     if (forwchar(FALSE, 1) == FALSE)
  204.         return (FALSE);
  205.     setchartype();
  206.     while (n--) {
  207.         while ((s = isendviwordf()) == FALSE) {
  208.             if (forwchar(FALSE, 1) == FALSE)
  209.                 return (FALSE);
  210.         }
  211.  
  212.     }
  213.     if (s == SORTOFTRUE)
  214.         return TRUE;
  215.     else
  216.         return backchar(FALSE, 1);
  217. }
  218.  
  219. /*
  220.  * Move the cursor forward by the specified number of words. All of the motion
  221.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  222.  */
  223. int
  224. forwendw(f, n)
  225. int f,n;
  226. {
  227.     int s = FALSE;
  228.     if (!f)
  229.         n = 1;
  230.     else if (n <= 0)
  231.         return (FALSE);
  232.     if (forwchar(FALSE, 1) == FALSE)
  233.         return (FALSE);
  234.     setchartype();
  235.     while (n--) {
  236.         while ((s = isendwordf()) == FALSE) {
  237.             if (forwchar(FALSE, 1) == FALSE)
  238.                 return (FALSE);
  239.         }
  240.  
  241.     }
  242.     if (s == SORTOFTRUE)
  243.         return TRUE;
  244.     else
  245.         return backchar(FALSE, 1);
  246. }
  247.  
  248. /*
  249.  * Move the cursor backward by "n" words. All of the details of motion are
  250.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  251.  * move beyond the buffers.
  252.  */
  253. int
  254. backviword(f, n)
  255. int f,n;
  256. {
  257.     if (n < 0)
  258.         return (forwword(f, -n));
  259.     if (backchar(FALSE, 1) == FALSE)
  260.         return (FALSE);
  261.     setchartype();
  262.     while (n--) {
  263.         while (isnewviwordb() == FALSE) {
  264.             if (backchar(FALSE, 1) == FALSE)
  265.                 return (FALSE);
  266.         }
  267.     }
  268.     return (forwchar(FALSE, 1));
  269. }
  270.  
  271. /*
  272.  * Move the cursor backward by "n" words. All of the details of motion are
  273.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  274.  * move beyond the buffers.
  275.  */
  276. int
  277. backword(f, n)
  278. int f,n;
  279. {
  280.     if (n < 0)
  281.         return (forwword(f, -n));
  282.     if (backchar(FALSE, 1) == FALSE)
  283.         return (FALSE);
  284.     setchartype();
  285.     while (n--) {
  286.         while (isnewwordb() == FALSE) {
  287.             if (backchar(FALSE, 1) == FALSE)
  288.                 return (FALSE);
  289.         }
  290.     }
  291.     return (forwchar(FALSE, 1));
  292. }
  293.  
  294. #ifdef NEEDED
  295. /*
  296.  * Return TRUE if the character at dot is a character that is considered to be
  297.  * part of a word. The word character list is hard coded. Should be setable.
  298.  */
  299. int
  300. inword()
  301. {
  302.     register int    c;
  303.  
  304.     if (is_at_end_of_line(DOT))
  305.         return (FALSE);
  306.     c = char_at(DOT);
  307.     if (islower(c))
  308.         return (TRUE);
  309.     if (isupper(c))
  310.         return (TRUE);
  311.     if (isdigit(c))
  312.         return (TRUE);
  313.     return (FALSE);
  314. }
  315. #endif
  316.  
  317. int
  318. join(f,n)
  319. int f,n;
  320. {
  321.     register int s = TRUE;
  322.     register int doto;
  323.  
  324.     if (!f) {
  325.         n = 1;
  326.     } else {
  327.         if (n < 0) return FALSE;
  328.         if (n == 0) return TRUE;
  329.     }
  330.     if (is_last_line(DOT, curbp))
  331.         return FALSE;
  332.     while(n--) {
  333.         s = lastnonwhite(f,n);
  334.         if (s == TRUE) s = forwchar(FALSE,1);
  335.         if (s == TRUE) s = setmark();
  336.         if (s == TRUE) s = forwline(f,1);
  337.         if (s == TRUE) s = firstnonwhite(f,1);
  338.         if (s == TRUE) s = killregion();
  339.         if (s != TRUE)
  340.             return s ;
  341.  
  342.         doto = DOT.o;
  343.         if (doto == 0)
  344.             return  TRUE;
  345.         if (lgetc(DOT.l, doto) == ')')
  346.             return TRUE;
  347.         if (lgetc(DOT.l, doto-1) == '.')
  348.             s = linsert(2,' ');
  349.         else
  350.             s = linsert(1,' ');
  351.     }
  352.  
  353.     return s;
  354. }
  355.  
  356. int
  357. formatregion()
  358. {
  359.     register int c;            /* current char during scan    */
  360.     register int wordlen;        /* length of current word    */
  361.     register int clength;        /* position on line during fill    */
  362.     register int i;            /* index during word copy    */
  363.     register int newlen;        /* tentative new line length    */
  364.     register int finished;        /* Are we at the End-Of-Paragraph? */
  365.     register int firstflag;        /* first word? (needs no space)    */
  366.     register int is_comment;    /* doing a comment block?    */
  367.     register int comment_char = -1;    /* # or *, for shell or C    */
  368.     register int at_nl = TRUE;    /* just saw a newline?        */
  369.     register LINE *pastline;    /* pointer to line just past EOP */
  370.     register int sentence;        /* was the last char a period?    */
  371.     char wbuf[NSTRING];        /* buffer for current word    */
  372.     int secondindent;
  373.     REGION region;
  374.     regexp *expP, *expC;
  375.     int s;
  376.     
  377.     if (!sameline(MK, DOT)) {
  378.         getregion(®ion);
  379.         if (sameline(region.r_orig, MK))
  380.             swapmark();
  381.     }
  382.     pastline = MK.l;
  383.     if (pastline != curbp->b_line.l)
  384.         pastline = lforw(pastline);
  385.  
  386.     expP = b_val_rexp(curbp,VAL_PARAGRAPHS)->reg;
  387.     expC = b_val_rexp(curbp,VAL_COMMENTS)->reg;
  388.      finished = FALSE;
  389.      while (finished != TRUE) {  /* i.e. is FALSE or SORTOFTRUE */
  390.         while (lregexec(expP, DOT.l, 0, llength(DOT.l)) ||
  391.             lregexec(expC, DOT.l, 0, llength(DOT.l)) ) {
  392.             DOT.l = lforw(DOT.l);
  393.             if (DOT.l == pastline) {
  394.                 setmark();
  395.                 return TRUE;
  396.             }
  397.         }
  398.  
  399.         secondindent = indentlen(DOT.l);
  400.         
  401.         /* go forward to get the indent for the second
  402.             and following lines */
  403.         DOT.l = lforw(DOT.l);
  404.  
  405.         if (DOT.l != pastline) {
  406.             secondindent = indentlen(DOT.l);
  407.         }
  408.             
  409.         /* and back where we should be */
  410.         DOT.l = lback(DOT.l);
  411.         firstnonwhite(FALSE,1);
  412.         
  413.         clength = indentlen(DOT.l);
  414.         wordlen = 0;
  415.         sentence = FALSE;
  416.  
  417.         is_comment = ( ((c = char_at(DOT)) == '#') ||
  418.                 (c == '*') ||
  419.                 ((c == '/') &&
  420.                 DOT.o+1 < llength(DOT.l) &&
  421.                  lgetc(DOT.l,DOT.o+1) == '*'));
  422.  
  423.         if (is_comment)
  424.             comment_char = (c == '#') ? '#':'*';
  425.  
  426.         /* scan through lines, filling words */
  427.         firstflag = TRUE;
  428.         finished = FALSE;
  429.         while (finished == FALSE) { /* i.e. is not TRUE  */
  430.                         /* or SORTOFTRUE */
  431.             if (interrupted) return ABORT;
  432.  
  433.             /* get the next character */
  434.             if (is_at_end_of_line(DOT)) {
  435.                 c = ' ';
  436.                 DOT.l = lforw(DOT.l);
  437.                 if (DOT.l == pastline) {
  438.                     finished = TRUE;
  439.                 } else if (
  440.                 lregexec(expP, DOT.l, 0, llength(DOT.l)) ||
  441.                 lregexec(expC, DOT.l, 0, llength(DOT.l))) {
  442.                     /* we're at a section break */
  443.                     finished = SORTOFTRUE;
  444.                 }
  445.                 DOT.l = lback(DOT.l);
  446.                 at_nl = TRUE;
  447.             } else {
  448.                 c = char_at(DOT);
  449.                 if (at_nl && ( isspace(c) ||
  450.                     (is_comment && c == comment_char)))
  451.                     c = ' ';
  452.                 else
  453.                     at_nl = FALSE;
  454.             }
  455.             /* and then delete it */
  456.             if (finished == FALSE) {
  457.                 s = ldelete(1L, FALSE);
  458.                 if (s != TRUE) return s;
  459.             }
  460.  
  461.             /* if not a separator, just add it in */
  462.             if (c != ' ' && c != '\t') {
  463.                 /* was it the end of a "sentence"? */
  464.                 sentence = (c == '.' || c == '?' || c == '!');
  465.                 if (wordlen < NSTRING - 1)
  466.                     wbuf[wordlen++] = c;
  467.             } else if (wordlen) {
  468.                 /* at a word break with a word waiting */
  469.                 /* calculate tentative new length
  470.                             with word added */
  471.                 newlen = clength + 1 + wordlen;
  472.                 if (newlen <= b_val(curbp,VAL_FILL)) {
  473.                     /* add word to current line */
  474.                     if (!firstflag) {
  475.                         /* the space */
  476.                         s = linsert(1, ' ');
  477.                         if (s != TRUE) return s;
  478.                         ++clength;
  479.                     } 
  480.                 } else {
  481.                             if (lnewline() == FALSE ||
  482.                     ((i=secondindent/curtabval)!=0 &&
  483.                                    linsert(i, '\t')==FALSE) ||
  484.                     ((i=secondindent%curtabval)!=0 &&
  485.                                    linsert(i,  ' ')==FALSE)) {
  486.                                     return FALSE;
  487.                             }
  488.                     clength = secondindent;
  489.                     firstflag = TRUE;
  490.                 }
  491.                 if (firstflag && is_comment &&
  492.                         strncmp("/*",wbuf,2)) {
  493.                     s = linsert(1, comment_char);
  494.                     if (s != TRUE) return s;
  495.                     s = linsert(1, ' ');
  496.                     if (s != TRUE) return s;
  497.                     clength += 2;
  498.                 }
  499.                 firstflag = FALSE;
  500.  
  501.                 /* and add the word in in either case */
  502.                 for (i=0; i<wordlen; i++) {
  503.                     s = linsert(1, wbuf[i]);
  504.                     if (s != TRUE) return s;
  505.                     ++clength;
  506.                 }
  507.                 if (finished == FALSE && sentence) {
  508.                     s = linsert(1, ' ');
  509.                     if (s != TRUE) return s;
  510.                     ++clength;
  511.                 }
  512.                 wordlen = 0;
  513.             }
  514.         }
  515.         DOT.l = lforw(DOT.l);
  516.     }
  517.     setmark();
  518.     return(TRUE);
  519. }
  520.  
  521.  
  522. #if    WORDCOUNT    /* who cares? -pgf */
  523. /*    wordcount:    count the # of words in the marked region,
  524.             along with average word sizes, # of chars, etc,
  525.             and report on them.            */
  526. int
  527. wordcount(f, n)
  528. {
  529.     register LINE *lp;    /* current line to scan */
  530.     register int offset;    /* current char to scan */
  531.     long size;        /* size of region left to count */
  532.     register int ch;    /* current character to scan */
  533.     register int wordflag;    /* are we in a word now? */
  534.     register int lastword;    /* were we just in a word? */
  535.     long nwords;        /* total # of words */
  536.     long nchars;        /* total number of chars */
  537.     int nlines;        /* total number of lines in region */
  538.     int avgch;        /* average number of chars/word */
  539.     int status;        /* status return code */
  540.     REGION region;        /* region to look at */
  541.  
  542.     /* make sure we have a region to count */
  543.     if ((status = getregion(®ion)) != TRUE)
  544.         return(status);
  545.     lp = region.r_linep;
  546.     offset = region.r_offset;
  547.     size = region.r_size;
  548.  
  549.     /* count up things */
  550.     lastword = FALSE;
  551.     nchars = 0L;
  552.     nwords = 0L;
  553.     nlines = 0;
  554.     while (size--) {
  555.  
  556.         /* get the current character */
  557.         if (offset == llength(lp)) {    /* end of line */
  558.             ch = '\n';
  559.             lp = lforw(lp);
  560.             offset = 0;
  561.             ++nlines;
  562.         } else {
  563.             ch = lgetc(lp, offset);
  564.             ++offset;
  565.         }
  566.  
  567.         /* and tabulate it */
  568.         wordflag = ((ch >= 'a' && ch <= 'z') ||
  569.                 (ch >= 'A' && ch <= 'Z') ||
  570.                 (ch >= '0' && ch <= '9'));
  571.         if (wordflag == TRUE && lastword == FALSE)
  572.             ++nwords;
  573.         lastword = wordflag;
  574.         ++nchars;
  575.     }
  576.  
  577.     /* and report on the info */
  578.     if (nwords > 0L)
  579.         avgch = (int)((100L * nchars) / nwords);
  580.     else
  581.         avgch = 0;
  582.  
  583.     mlforce("lines %d, words, %D chars %D  avg chars/word %f",
  584.         nlines + 1, nwords, nchars, avgch);
  585.     return(TRUE);
  586. }
  587. #endif
  588.