home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / UE311C.ZIP / WORD.C < prev    next >
C/C++ Source or Header  |  1991-05-01  |  17KB  |  682 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.  
  7. #include    <stdio.h>
  8. #include    "estruct.h"
  9. #include    "eproto.h"
  10. #include    "edef.h"
  11. #include    "elang.h"
  12.  
  13. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  14.  * line and stop on the first word-break or the beginning of the line. If we
  15.  * reach the beginning of the line, jump back to the end of the word and start
  16.  * a new line.    Otherwise, break the line at the word-break, eat it, and jump
  17.  * back to the end of the word. Make sure we force the display back to the
  18.  * left edge of the current window
  19.  * Returns TRUE on success, FALSE on errors.
  20.  */
  21. PASCAL NEAR wrapword(f, n)
  22.  
  23. int f;        /* default flag */
  24. int n;        /* numeric argument */
  25.  
  26. {
  27.     register int cnt;    /* size of word wrapped to next line */
  28.     register int c;        /* charector temporary */
  29.  
  30.     /* backup from the <NL> 1 char */
  31.     if (!backchar(FALSE, 1))
  32.         return(FALSE);
  33.  
  34.     /* back up until we aren't in a word,
  35.        make sure there is a break in the line */
  36.     cnt = 0;
  37.     while (((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ')
  38.                 && (c != '\t')) {
  39.         cnt++;
  40.         if (!backchar(FALSE, 1))
  41.             return(FALSE);
  42.         /* if we make it to the beginning, start a new line */
  43.         if (curwp->w_doto == 0) {
  44.             gotoeol(FALSE, 0);
  45.             return(lnewline());
  46.         }
  47.     }
  48.  
  49.     /* delete the forward white space */
  50.     if (!forwdel(0, 1))
  51.         return(FALSE);
  52.  
  53.     /* put in a end of line */
  54.     if (!lnewline())
  55.         return(FALSE);
  56.  
  57.     /* and past the first word */
  58.     while (cnt-- > 0) {
  59.         if (forwchar(FALSE, 1) == FALSE)
  60.             return(FALSE);
  61.     }
  62.  
  63.     /* make sure the display is not horizontally scrolled */
  64.     if (curwp->w_fcol != 0) {
  65.         curwp->w_fcol = 0;
  66.         curwp->w_flag |= WFHARD | WFMOVE | WFMODE;
  67.     }
  68.  
  69.     return(TRUE);
  70. }
  71.  
  72. /*
  73.  * Move the cursor backward by "n" words. All of the details of motion are
  74.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  75.  * move beyond the buffers.
  76.  */
  77. PASCAL NEAR backword(f, n)
  78.  
  79. int f,n;    /* prefix flag and argument */
  80.  
  81. {
  82.     if (n < 0)
  83.         return(forwword(f, -n));
  84.     if (backchar(FALSE, 1) == FALSE)
  85.         return(FALSE);
  86.     while (n--) {
  87.         while (inword() == FALSE) {
  88.             if (backchar(FALSE, 1) == FALSE)
  89.                 return(FALSE);
  90.         }
  91.         while (inword() != FALSE) {
  92.             if (backchar(FALSE, 1) == FALSE)
  93.                 return(FALSE);
  94.         }
  95.     }
  96.     return(forwchar(FALSE, 1));
  97. }
  98.  
  99. /*
  100.  * Move the cursor forward by the specified number of words. All of the motion
  101.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  102.  */
  103. PASCAL NEAR forwword(f, n)
  104.  
  105. int f,n;    /* prefix flag and argument */
  106.  
  107. {
  108.     if (n < 0)
  109.         return(backword(f, -n));
  110.     while (n--) {
  111.         /* scan through the current word */
  112.         while (inword() == TRUE) {
  113.             if (forwchar(FALSE, 1) == FALSE)
  114.                 return(FALSE);
  115.         }
  116.  
  117.         /* scan through the intervening white space */
  118.         while (inword() == FALSE) {
  119.             if (forwchar(FALSE, 1) == FALSE)
  120.                 return(FALSE);
  121.         }
  122.     }
  123.     return(TRUE);
  124. }
  125.  
  126. /*
  127.  * Move forward to the end of the nth next word. Error if you move past
  128.  * the end of the buffer.
  129.  */
  130. PASCAL NEAR endword(f, n)
  131.  
  132. int f,n;    /* prefix flag and argument */
  133.  
  134. {
  135.     if (n < 0)
  136.         return(backword(f, -n));
  137.     while (n--) {
  138.         /* scan through the intervening white space */
  139.         while (inword() == FALSE) {
  140.             if (forwchar(FALSE, 1) == FALSE)
  141.                 return(FALSE);
  142.         }
  143.  
  144.         /* scan through the current word */
  145.         while (inword() == TRUE) {
  146.             if (forwchar(FALSE, 1) == FALSE)
  147.                 return(FALSE);
  148.         }
  149.     }
  150.     return(TRUE);
  151. }
  152.  
  153. /*
  154.  * Move the cursor forward by the specified number of words. As you move,
  155.  * convert any characters to upper case. Error if you try and move beyond the
  156.  * end of the buffer. Bound to "M-U".
  157.  */
  158. PASCAL NEAR upperword(f, n)
  159.  
  160. int f,n;    /* prefix flag and argument */
  161.  
  162. {
  163.     int c;
  164.  
  165.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  166.         return(rdonly());    /* we are in read only mode    */
  167.     if (n < 0)
  168.         return(FALSE);
  169.     while (n--) {
  170.         while (inword() == FALSE) {
  171.             if (forwchar(FALSE, 1) == FALSE)
  172.                 return(FALSE);
  173.         }
  174.         while (inword() != FALSE) {
  175.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  176.             if (islower(c)) {
  177.                 c = upperc(c);
  178.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  179.                 lchange(WFHARD);
  180.             }
  181.             if (forwchar(FALSE, 1) == FALSE)
  182.                 return(FALSE);
  183.         }
  184.     }
  185.     return(TRUE);
  186. }
  187.  
  188. /*
  189.  * Move the cursor forward by the specified number of words. As you move
  190.  * convert characters to lower case. Error if you try and move over the end of
  191.  * the buffer. Bound to "M-L".
  192.  */
  193. PASCAL NEAR lowerword(f, n)
  194.  
  195. int f,n;    /* prefix flag and argument */
  196.  
  197. {
  198.     int c;
  199.  
  200.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  201.         return(rdonly());    /* we are in read only mode    */
  202.     if (n < 0)
  203.         return(FALSE);
  204.     while (n--) {
  205.         while (inword() == FALSE) {
  206.             if (forwchar(FALSE, 1) == FALSE)
  207.                 return(FALSE);
  208.         }
  209.         while (inword() != FALSE) {
  210.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  211.             if (isupper(c)) {
  212.                 c = lowerc(c);
  213.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  214.                 lchange(WFHARD);
  215.             }
  216.             if (forwchar(FALSE, 1) == FALSE)
  217.                 return(FALSE);
  218.         }
  219.     }
  220.     return(TRUE);
  221. }
  222.  
  223. /*
  224.  * Move the cursor forward by the specified number of words. As you move
  225.  * convert the first character of the word to upper case, and subsequent
  226.  * characters to lower case. Error if you try and move past the end of the
  227.  * buffer. Bound to "M-C".
  228.  */
  229. PASCAL NEAR capword(f, n)
  230.  
  231. int f,n;    /* prefix flag and argument */
  232.  
  233. {
  234.     int c;
  235.  
  236.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  237.         return(rdonly());    /* we are in read only mode    */
  238.     if (n < 0)
  239.         return(FALSE);
  240.     while (n--) {
  241.         while (inword() == FALSE) {
  242.             if (forwchar(FALSE, 1) == FALSE)
  243.                 return(FALSE);
  244.         }
  245.         if (inword() != FALSE) {
  246.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  247.             if (islower(c)) {
  248.                 c = upperc(c);
  249.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  250.                 lchange(WFHARD);
  251.             }
  252.             if (forwchar(FALSE, 1) == FALSE)
  253.                 return(FALSE);
  254.             while (inword() != FALSE) {
  255.                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  256.                 if (isupper(c)) {
  257.                     c = lowerc(c);
  258.                     lputc(curwp->w_dotp, curwp->w_doto, c);
  259.                     lchange(WFHARD);
  260.                 }
  261.                 if (forwchar(FALSE, 1) == FALSE)
  262.                     return(FALSE);
  263.             }
  264.         }
  265.     }
  266.     return(TRUE);
  267. }
  268.  
  269. /*
  270.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  271.  * the right number of words. Put dot back where it was and issue the kill
  272.  * command for the right number of characters. With a zero argument, just
  273.  * kill one word and no whitespace. Bound to "M-D".
  274.  */
  275. PASCAL NEAR delfword(f, n)
  276.  
  277. int f,n;    /* prefix flag and argument */
  278.  
  279. {
  280.     register LINE    *dotp;    /* original cursor line */
  281.     register int    doto;    /*    and row */
  282.     register int c;        /* temp char */
  283.     long size;        /* # of chars to delete */
  284.  
  285.     /* don't allow this command if we are in read only mode */
  286.     if (curbp->b_mode&MDVIEW)
  287.         return(rdonly());
  288.  
  289.     /* ignore the command if there is a negative argument */
  290.     if (n < 0)
  291.         return(FALSE);
  292.  
  293.     /* Clear the kill buffer if last command wasn't a kill */
  294.     if ((lastflag&CFKILL) == 0)
  295.         kdelete();
  296.     thisflag |= CFKILL;    /* this command is a kill */
  297.  
  298.     /* save the current cursor position */
  299.     dotp = curwp->w_dotp;
  300.     doto = curwp->w_doto;
  301.  
  302.     /* figure out how many characters to give the axe */
  303.     size = 0;
  304.  
  305.     /* get us into a word.... */
  306.     while (inword() == FALSE) {
  307.         if (forwchar(FALSE, 1) == FALSE)
  308.             return(FALSE);
  309.         ++size;
  310.     }
  311.  
  312.     if (n == 0) {
  313.         /* skip one word, no whitespace! */
  314.         while (inword() == TRUE) {
  315.             if (forwchar(FALSE, 1) == FALSE)
  316.                 return(FALSE);
  317.             ++size;
  318.         }
  319.     } else {
  320.         /* skip n words.... */
  321.         while (n--) {
  322.     
  323.             /* if we are at EOL; skip to the beginning of the next */
  324.             while (curwp->w_doto == llength(curwp->w_dotp)) {
  325.                 if (forwchar(FALSE, 1) == FALSE)
  326.                     return(FALSE);
  327.                 ++size;
  328.             }
  329.     
  330.             /* move forward till we are at the end of the word */
  331.             while (inword() == TRUE) {
  332.                 if (forwchar(FALSE, 1) == FALSE)
  333.                     return(FALSE);
  334.                 ++size;
  335.             }
  336.     
  337.             /* if there are more words, skip the interword stuff */
  338.             if (n != 0)
  339.                 while (inword() == FALSE) {
  340.                     if (forwchar(FALSE, 1) == FALSE)
  341.                         return(FALSE);
  342.                     ++size;
  343.                 }
  344.         }
  345.     
  346.         /* skip whitespace and newlines */
  347.         while ((curwp->w_doto == llength(curwp->w_dotp)) ||
  348.             ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ') ||
  349.             (c == '\t')) {
  350.                 if (forwchar(FALSE, 1) == FALSE)
  351.                     break;
  352.                 ++size;
  353.         }
  354.     }
  355.  
  356.     /* restore the original position and delete the words */
  357.     curwp->w_dotp = dotp;
  358.     curwp->w_doto = doto;
  359.     return(ldelete(size, TRUE));
  360. }
  361.  
  362. /*
  363.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  364.  * counting the characters. When dot is finally moved to its resting place,
  365.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  366.  */
  367. PASCAL NEAR delbword(f, n)
  368.  
  369. int f,n;    /* prefix flag and argument */
  370.  
  371. {
  372.     long size;
  373.  
  374.     /* don't allow this command if we are in read only mode */
  375.     if (curbp->b_mode&MDVIEW)
  376.         return(rdonly());
  377.  
  378.     /* ignore the command if there is a nonpositive argument */
  379.     if (n <= 0)
  380.         return(FALSE);
  381.  
  382.     /* Clear the kill buffer if last command wasn't a kill */
  383.     if ((lastflag&CFKILL) == 0)
  384.         kdelete();
  385.     thisflag |= CFKILL;    /* this command is a kill */
  386.  
  387.     if (backchar(FALSE, 1) == FALSE)
  388.         return(FALSE);
  389.     size = 0;
  390.     while (n--) {
  391.         while (inword() == FALSE) {
  392.             if (backchar(FALSE, 1) == FALSE)
  393.                 return(FALSE);
  394.             ++size;
  395.         }
  396.         while (inword() != FALSE) {
  397.             ++size;
  398.             if (backchar(FALSE, 1) == FALSE)
  399.                 goto bckdel;
  400.         }
  401.     }
  402.     if (forwchar(FALSE, 1) == FALSE)
  403.         return(FALSE);
  404. bckdel:    if (forwchar(FALSE, size) == FALSE)
  405.         return(FALSE);
  406.     return(ldelete(-size, TRUE));
  407. }
  408.  
  409. /*
  410.  * Return TRUE if the character at dot is a character that is considered to be
  411.  * part of a word. The default word character list is hard coded. If $wchars
  412.  * has been set by the user, use that instead
  413.  */
  414.  
  415. PASCAL NEAR inword()
  416.  
  417. {
  418.     register int c;
  419.  
  420.     /* the end of a line is never in a word */
  421.     if (curwp->w_doto == llength(curwp->w_dotp))
  422.         return(FALSE);
  423.  
  424.     /* grab the word to check */
  425.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  426.  
  427.     /* if we are using the table.... */
  428.     if (wlflag)
  429.         return(wordlist[c]);
  430.  
  431.     /* else use the default hard coded check */
  432.     if (isletter(c))
  433.         return(TRUE);
  434.     if (c>='0' && c<='9')
  435.         return(TRUE);
  436.     if (c == '_')
  437.         return(TRUE);
  438.     return(FALSE);
  439. }
  440.  
  441. PASCAL NEAR fillpara(f, n)    /* Fill the current paragraph according to the
  442.                current fill column */
  443.  
  444. int f, n;    /* Default flag and Numeric argument */
  445.  
  446. {
  447.     register char *pp;    /* ptr into paragraph being reformed */
  448.     register char *para;    /* malloced buffer for paragraph */
  449.     register LINE *lp;    /* ptr to current line */
  450.     register int lsize;    /* bytes in current line */
  451.     register char *txtptr;    /* ptr into current line */
  452.     LINE *ptline;        /* line the point started on */
  453.     int ptoff;        /* offset of original point */
  454.     int back;        /* # of characters from origin point to eop */
  455.     int status;        /* return status from linstr() */
  456.     int psize;        /* byte size of paragraph */
  457.     LINE *bop;        /* ptr to beg of paragraph */
  458.     LINE *eop;        /* pointer to line just past EOP */
  459.  
  460.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  461.         return(rdonly());    /* we are in read only mode    */
  462.     if (fillcol == 0) {    /* no fill column set */
  463.         mlwrite(TEXT98);
  464. /*                      "No fill column set" */
  465.         return(FALSE);
  466.     }
  467.  
  468.     /* save the original point */
  469.     ptline = curwp->w_dotp;
  470.     ptoff = curwp->w_doto;
  471.  
  472.     /* record the pointer to the line just past the EOP */
  473.     gotoeop(FALSE, 1);
  474.     eop = lforw(curwp->w_dotp);
  475.  
  476.     /* and back top the beginning of the paragraph */
  477.     gotobop(FALSE, 1);
  478.     bop = lp = curwp->w_dotp;
  479.  
  480.     /* ok, how big is this paragraph? */
  481.     psize = 0;
  482.     while (lp != eop) {
  483.         psize += lp->l_used + 1;
  484.         lp = lp->l_fp;
  485.     }
  486.  
  487.     /* create a buffer to hold this stuff */
  488.     para = malloc(psize + 100);    /***** THIS IS TEMP *****/
  489.     if (para == NULL) {
  490.         mlwrite(TEXT94);
  491. /*                      "%%Out of memory" */
  492.         return(FALSE);
  493.     }
  494.  
  495.     /* now, grab all the text into a string */
  496.     back = 0;    /* counting the distance to backup when done */
  497.     lp = bop;
  498.     pp = para;
  499.     while (lp != eop) {
  500.         lsize = lp->l_used;
  501.         if (back == 0) {
  502.             if (lp == ptline)
  503.                 back = lsize - ptoff + 1;
  504.         } else
  505.             back += lsize + 1;
  506.         txtptr = lp->l_text;
  507.         while (lsize--)            /* copy a line */
  508.             *pp++ = *txtptr++;
  509.         *pp++ = ' ';            /* turn the NL to a space */
  510.         lp = lp->l_fp;
  511.         lfree(lp->l_bp);        /* free the old line */
  512.     }
  513.     *(--pp) = 0;    /* truncate the last space */
  514.  
  515.     /* reformat the paragraph in the buffer */
  516.     reform(para);
  517.  
  518.     /* insert the reformatted paragraph back into the current buffer */
  519.     status = linstr(para);
  520.     lnewline();        /* add the last newline to our paragraph */
  521.     if (status == TRUE)    /* reposition us to the same place */
  522.         status = backchar(FALSE, back);
  523.  
  524.     /* make sure the display is not horizontally scrolled */
  525.     if (curwp->w_fcol != 0) {
  526.         curwp->w_fcol = 0;
  527.         curwp->w_flag |= WFHARD | WFMOVE | WFMODE;
  528.     }
  529.  
  530.     /* free the buffer and return */
  531.     free(para);
  532.     return(status);
  533. }
  534.  
  535. PASCAL NEAR reform(para)    /* reformat a paragraph as stored in a string */
  536.  
  537. char *para;    /* string buffer containing paragraph */
  538.  
  539. {
  540.     register char *sp;        /* string scan pointer */
  541.     register int col;        /* current colomn position */
  542.     register char *lastword;    /* ptr to end of last word */
  543.  
  544.     /* scan string, replacing some whitespace with newlines */
  545.     sp = para;
  546.     lastword = para;
  547.     col = 0;
  548.     while (*sp) {
  549.         /* if we are at white space.... */
  550.         if ((*sp == ' ') || (*sp == '\t')) {
  551.             if (*sp == '\t')
  552.                 col = (col + 8) & (~7);
  553.             else
  554.                 col++;
  555.  
  556.             /* break on whitespace? */
  557.             if (col > fillcol) {
  558.                 *sp = '\r';
  559.                 col = 0;
  560.             }
  561.  
  562.             /* onward, resetting the most recent begin of word */
  563.             ++sp;
  564.             lastword = sp;
  565.  
  566.         } else {    /* a non-blank to process */
  567.  
  568.             ++sp;
  569.             ++col;
  570.             if (col > fillcol) {
  571.                 /* line break here! */
  572.                 if ((lastword > para) &&
  573.                    (*(lastword - 1) != '\r')) {
  574.                        *(lastword - 1) = '\r';
  575.                        sp = lastword;
  576.                        col = 0;
  577.                 }
  578.             }
  579.         }
  580.     }
  581. }
  582.  
  583. PASCAL NEAR killpara(f, n)    /* delete n paragraphs starting with the current one */
  584.  
  585. int f;    /* default flag */
  586. int n;    /* # of paras to delete */
  587.  
  588. {
  589.     register int status;    /* returned status of functions */
  590.  
  591.     while (n--) {        /* for each paragraph to delete */
  592.  
  593.         /* mark out the end and beginning of the para to delete */
  594.         gotoeop(FALSE, 1);
  595.  
  596.         /* set the mark here */
  597.         curwp->w_markp[0] = curwp->w_dotp;
  598.         curwp->w_marko[0] = curwp->w_doto;
  599.  
  600.         /* go to the beginning of the paragraph */
  601.         gotobop(FALSE, 1);
  602.         curwp->w_doto = 0;    /* force us to the beginning of line */
  603.     
  604.         /* and delete it */
  605.         if ((status = killregion(FALSE, 1)) != TRUE)
  606.             return(status);
  607.  
  608.         /* and clean up the 2 extra lines */
  609.         ldelete(2L, TRUE);
  610.     }
  611.     return(TRUE);
  612. }
  613.  
  614. /*    wordcount:    count the # of words in the marked region,
  615.             along with average word sizes, # of chars, etc,
  616.             and report on them.            */
  617.  
  618. PASCAL NEAR wordcount(f, n)
  619.  
  620. int f, n;    /* ignored numeric arguments */
  621.  
  622. {
  623.     register LINE *lp;    /* current line to scan */
  624.     register int offset;    /* current char to scan */
  625.     long size;        /* size of region left to count */
  626.     register int ch;    /* current character to scan */
  627.     register int wordflag;    /* are we in a word now? */
  628.     register int lastword;    /* were we just in a word? */
  629.     long nwords;        /* total # of words */
  630.     long nchars;        /* total number of chars */
  631.     int nlines;        /* total number of lines in region */
  632.     int avgch;        /* average number of chars/word */
  633.     int status;        /* status return code */
  634.     REGION region;        /* region to look at */
  635.  
  636.     /* make sure we have a region to count */
  637.     if ((status = getregion(®ion)) != TRUE)
  638.         return(status);
  639.     lp = region.r_linep;
  640.     offset = region.r_offset;
  641.     size = region.r_size;
  642.  
  643.     /* count up things */
  644.     lastword = FALSE;
  645.     nchars = 0L;
  646.     nwords = 0L;
  647.     nlines = 0;
  648.     while (size--) {
  649.  
  650.         /* get the current character */
  651.         if (offset == llength(lp)) {    /* end of line */
  652.             ch = '\r';
  653.             lp = lforw(lp);
  654.             offset = 0;
  655.             ++nlines;
  656.         } else {
  657.             ch = lgetc(lp, offset);
  658.             ++offset;
  659.         }
  660.  
  661.         /* and tabulate it */
  662.         wordflag = ((ch >= 'a' && ch <= 'z') ||
  663.                 (ch >= 'A' && ch <= 'Z') ||
  664.                 (ch >= '0' && ch <= '9'));
  665.         if (wordflag == TRUE && lastword == FALSE)
  666.             ++nwords;
  667.         lastword = wordflag;
  668.         ++nchars;
  669.     }
  670.  
  671.     /* and report on the info */
  672.     if (nwords > 0L)
  673.         avgch = (int)((100L * nchars) / nwords);
  674.     else
  675.         avgch = 0;
  676.  
  677.     mlwrite(TEXT100,
  678. /*              "Words %D Chars %D Lines %d Avg chars/word %f" */
  679.         nwords, nchars, nlines + 1, avgch);
  680.     return(TRUE);
  681. }
  682.