home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / pine / pico / word.c < prev   
Encoding:
C/C++ Source or Header  |  1994-04-06  |  16.0 KB  |  522 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: word.c,v 4.3 1993/11/08 20:22:47 mikes Exp $";
  3. #endif
  4. /*
  5.  * Program:    Word at a time routines
  6.  *
  7.  *
  8.  * Michael Seibel
  9.  * Networks and Distributed Computing
  10.  * Computing and Communications
  11.  * University of Washington
  12.  * Administration Builiding, AG-44
  13.  * Seattle, Washington, 98195, USA
  14.  * Internet: mikes@cac.washington.edu
  15.  *
  16.  * Please address all bugs and comments to "pine-bugs@cac.washington.edu"
  17.  *
  18.  * Copyright 1991-1993  University of Washington
  19.  *
  20.  *  Permission to use, copy, modify, and distribute this software and its
  21.  * documentation for any purpose and without fee to the University of
  22.  * Washington is hereby granted, provided that the above copyright notice
  23.  * appears in all copies and that both the above copyright notice and this
  24.  * permission notice appear in supporting documentation, and that the name
  25.  * of the University of Washington not be used in advertising or publicity
  26.  * pertaining to distribution of the software without specific, written
  27.  * prior permission.  This software is made available "as is", and
  28.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  29.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  30.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  31.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  32.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  33.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  34.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  35.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  36.  *
  37.  * Pine and Pico are trademarks of the University of Washington.
  38.  * No commercial use of these trademarks may be made without prior
  39.  * written permission of the University of Washington.
  40.  *
  41.  */
  42. /*
  43.  * The routines in this file implement commands that work word at a time.
  44.  * There are all sorts of word mode commands. If I do any sentence and/or
  45.  * paragraph mode commands, they are likely to be put in this file.
  46.  */
  47.  
  48. #include        <stdio.h>
  49. #include        "estruct.h"
  50. #include        "pico.h"
  51. #include        <ctype.h>
  52. #include    "edef.h"
  53. #include    "osdep.h"
  54.  
  55.  
  56. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  57.  * line and stop on the first word-break or the beginning of the line. If we
  58.  * reach the beginning of the line, jump back to the end of the word and start
  59.  * a new line.  Otherwise, break the line at the word-break, eat it, and jump
  60.  * back to the end of the word.
  61.  * Returns TRUE on success, FALSE on errors.
  62.  */
  63. wrapword()
  64. {
  65.     register int   cnt = 0;    /* size of word wrapped to next line */
  66.     register int   bp;
  67.  
  68.     if(curwp->w_doto <= 0)        /* no line to wrap? */
  69.       return(FALSE);
  70.  
  71.     /* 
  72.      * back up until we aren't in a word,
  73.      * and make sure there is a break in the line
  74.      */
  75.     bp = llength(curwp->w_dotp);    /* start at end of line */
  76.     do{
  77.     if(--bp <= 0)            /* no place to break the line! */
  78.       return(FALSE);
  79.     
  80.     switch(cnt){
  81.       case 0:            /* break BEFORE fillcol */
  82.         if(bp > fillcol)
  83.           break;
  84.         else
  85.           cnt++;
  86.  
  87.       case 1:            /* find first breakable word */
  88.         if(isspace(lgetc(curwp->w_dotp, bp).c))
  89.           break;
  90.         else
  91.           cnt++;
  92.  
  93.       case 2:            /* and break in front of it */
  94.         if(!isspace(lgetc(curwp->w_dotp, bp).c))
  95.           break;
  96.         else
  97.           cnt = 10;
  98.  
  99.       default:
  100.         break;
  101.     }
  102.     }
  103.     while(cnt != 10);
  104.  
  105.     /* bp now points to the last character to remain on this line! */
  106.     cnt = curwp->w_doto - ++bp;
  107.     curwp->w_doto = bp;
  108.     
  109.     if(!lnewline())            /* break the line */
  110.       return(FALSE);
  111.  
  112.     /*
  113.      * if there's a line below, it doesn't start with whitespace 
  114.      * and there's room for this line...
  115.      */
  116.     if(lforw(curwp->w_dotp) != curbp->b_linep 
  117.        && llength(lforw(curwp->w_dotp)) 
  118.        && !isspace(lgetc(lforw(curwp->w_dotp), 0).c)
  119.        && (llength(curwp->w_dotp) + llength(lforw(curwp->w_dotp)) < fillcol)){
  120.     gotoeol(0, 1);            /* then pull text up from below */
  121.     if(lgetc(curwp->w_dotp, curwp->w_doto - 1).c != ' ')
  122.       linsert(1, ' ');
  123.  
  124.     forwdel(0, 1);
  125.     gotobol(0, 1);
  126.     }
  127.  
  128.     if(!forwchar(0, cnt < 0 ? cnt-1 : cnt)) /* restore dot (account for NL) */
  129.       return(FALSE);
  130.  
  131.     return(TRUE);
  132. }
  133.  
  134.  
  135. /*
  136.  * Move the cursor backward by "n" words. All of the details of motion are
  137.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  138.  * move beyond the buffers.
  139.  */
  140. backword(f, n)
  141. {
  142.         if (n < 0)
  143.                 return (forwword(f, -n));
  144.         if (backchar(FALSE, 1) == FALSE)
  145.                 return (FALSE);
  146.         while (n--) {
  147.                 while (inword() == FALSE) {
  148.                         if (backchar(FALSE, 1) == FALSE)
  149.                                 return (FALSE);
  150.                 }
  151.                 while (inword() != FALSE) {
  152.                         if (backchar(FALSE, 1) == FALSE)
  153.                                 return (FALSE);
  154.                 }
  155.         }
  156.         return (forwchar(FALSE, 1));
  157. }
  158.  
  159. /*
  160.  * Move the cursor forward by the specified number of words. All of the motion
  161.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  162.  */
  163. forwword(f, n)
  164. {
  165.         if (n < 0)
  166.                 return (backword(f, -n));
  167.         while (n--) {
  168. #if    NFWORD
  169.                 while (inword() != FALSE) {
  170.                         if (forwchar(FALSE, 1) == FALSE)
  171.                                 return (FALSE);
  172.                 }
  173. #endif
  174.                 while (inword() == FALSE) {
  175.                         if (forwchar(FALSE, 1) == FALSE)
  176.                                 return (FALSE);
  177.                 }
  178. #if    NFWORD == 0
  179.                 while (inword() != FALSE) {
  180.                         if (forwchar(FALSE, 1) == FALSE)
  181.                                 return (FALSE);
  182.                 }
  183. #endif
  184.         }
  185.     return(TRUE);
  186. }
  187.  
  188. #ifdef    MAYBELATER
  189. /*
  190.  * Move the cursor forward by the specified number of words. As you move,
  191.  * convert any characters to upper case. Error if you try and move beyond the
  192.  * end of the buffer. Bound to "M-U".
  193.  */
  194. upperword(f, n)
  195. {
  196.         register int    c;
  197.     CELL            ac;
  198.  
  199.     ac.a = 0;
  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).c;
  211.                         if (c>='a' && c<='z') {
  212.                                 ac.c = (c -= 'a'-'A');
  213.                                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  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 characters to lower case. Error if you try and move over the end of
  226.  * the buffer. Bound to "M-L".
  227.  */
  228. lowerword(f, n)
  229. {
  230.         register int    c;
  231.     CELL            ac;
  232.  
  233.     ac.a = 0;
  234.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  235.         return(rdonly());    /* we are in read only mode    */
  236.         if (n < 0)
  237.                 return (FALSE);
  238.         while (n--) {
  239.                 while (inword() == FALSE) {
  240.                         if (forwchar(FALSE, 1) == FALSE)
  241.                                 return (FALSE);
  242.                 }
  243.                 while (inword() != FALSE) {
  244.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  245.                         if (c>='A' && c<='Z') {
  246.                                 ac.c (c += 'a'-'A');
  247.                                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  248.                                 lchange(WFHARD);
  249.                         }
  250.                         if (forwchar(FALSE, 1) == FALSE)
  251.                                 return (FALSE);
  252.                 }
  253.         }
  254.         return (TRUE);
  255. }
  256.  
  257. /*
  258.  * Move the cursor forward by the specified number of words. As you move
  259.  * convert the first character of the word to upper case, and subsequent
  260.  * characters to lower case. Error if you try and move past the end of the
  261.  * buffer. Bound to "M-C".
  262.  */
  263. capword(f, n)
  264. {
  265.         register int    c;
  266.     CELL            ac;
  267.  
  268.     ac.a = 0;
  269.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  270.         return(rdonly());    /* we are in read only mode    */
  271.         if (n < 0)
  272.                 return (FALSE);
  273.         while (n--) {
  274.                 while (inword() == FALSE) {
  275.                         if (forwchar(FALSE, 1) == FALSE)
  276.                                 return (FALSE);
  277.                 }
  278.                 if (inword() != FALSE) {
  279.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  280.                         if (c>='a' && c<='z') {
  281.                 ac.c = (c -= 'a'-'A');
  282.                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  283.                 lchange(WFHARD);
  284.                         }
  285.                         if (forwchar(FALSE, 1) == FALSE)
  286.                                 return (FALSE);
  287.                         while (inword() != FALSE) {
  288.                                 c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  289.                                 if (c>='A' && c<='Z') {
  290.                     ac.c = (c += 'a'-'A');
  291.                     lputc(curwp->w_dotp, curwp->w_doto, ac);
  292.                     lchange(WFHARD);
  293.                                 }
  294.                                 if (forwchar(FALSE, 1) == FALSE)
  295.                                         return (FALSE);
  296.                         }
  297.                 }
  298.         }
  299.         return (TRUE);
  300. }
  301.  
  302. /*
  303.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  304.  * the right number of words. Put dot back where it was and issue the kill
  305.  * command for the right number of characters. Bound to "M-D".
  306.  */
  307. delfword(f, n)
  308. {
  309.         register int    size;
  310.         register LINE   *dotp;
  311.         register int    doto;
  312.  
  313.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  314.         return(rdonly());    /* we are in read only mode    */
  315.         if (n < 0)
  316.                 return (FALSE);
  317.         dotp = curwp->w_dotp;
  318.         doto = curwp->w_doto;
  319.         size = 0;
  320.         while (n--) {
  321. #if    NFWORD
  322.         while (inword() != FALSE) {
  323.             if (forwchar(FALSE,1) == FALSE)
  324.                 return(FALSE);
  325.             ++size;
  326.         }
  327. #endif
  328.                 while (inword() == FALSE) {
  329.                         if (forwchar(FALSE, 1) == FALSE)
  330.                                 return (FALSE);
  331.                         ++size;
  332.                 }
  333. #if    NFWORD == 0
  334.                 while (inword() != FALSE) {
  335.                         if (forwchar(FALSE, 1) == FALSE)
  336.                                 return (FALSE);
  337.                         ++size;
  338.                 }
  339. #endif
  340.         }
  341.         curwp->w_dotp = dotp;
  342.         curwp->w_doto = doto;
  343.         return (ldelete(size, TRUE));
  344. }
  345.  
  346. /*
  347.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  348.  * counting the characters. When dot is finally moved to its resting place,
  349.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  350.  */
  351. delbword(f, n)
  352. {
  353.         register int    size;
  354.  
  355.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  356.         return(rdonly());    /* we are in read only mode    */
  357.         if (n < 0)
  358.                 return (FALSE);
  359.         if (backchar(FALSE, 1) == FALSE)
  360.                 return (FALSE);
  361.         size = 0;
  362.         while (n--) {
  363.                 while (inword() == FALSE) {
  364.                         if (backchar(FALSE, 1) == FALSE)
  365.                                 return (FALSE);
  366.                         ++size;
  367.                 }
  368.                 while (inword() != FALSE) {
  369.                         if (backchar(FALSE, 1) == FALSE)
  370.                                 return (FALSE);
  371.                         ++size;
  372.                 }
  373.         }
  374.         if (forwchar(FALSE, 1) == FALSE)
  375.                 return (FALSE);
  376.         return (ldelete(size, TRUE));
  377. }
  378. #endif    /* MAYBELATER */
  379.  
  380. /*
  381.  * Return TRUE if the character at dot is a character that is considered to be
  382.  * part of a word. The word character list is hard coded. Should be setable.
  383.  */
  384. inword()
  385. {
  386.         register int    c;
  387.  
  388.         if (curwp->w_doto == llength(curwp->w_dotp))
  389.                 return (FALSE);
  390.         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  391.  
  392.         if (c>='a' && c<='z')
  393.                 return (TRUE);
  394.         if (c>='A' && c<='Z')
  395.                 return (TRUE);
  396.         if (c>='0' && c<='9')
  397.                 return (TRUE);
  398.         return (FALSE);
  399. }
  400.  
  401. fillpara(f, n)    /* Fill the current paragraph according to the current
  402.            fill column                        */
  403.  
  404. int f, n;    /* deFault flag and Numeric argument */
  405.  
  406. {
  407.     register int c;            /* current char durring scan    */
  408.     register int wordlen;        /* length of current word    */
  409.     register int clength;        /* position on line during fill    */
  410.     register int i;            /* index during word copy    */
  411.     register int newlength;        /* tentative new line length    */
  412.     register int eopflag;        /* Are we at the End-Of-Paragraph? */
  413.     register int firstflag;        /* first word? (needs no space)    */
  414.     register LINE *eopline;        /* pointer to line just past EOP */
  415.     register int dotflag;        /* was the last char a period?    */
  416.     char wbuf[NSTRING];        /* buffer for current word    */
  417.  
  418.  
  419.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  420.         return(rdonly());    /* we are in read only mode    */
  421.     if (fillcol == 0) {    /* no fill column set */
  422.         mlwrite("No fill column set");
  423.         return(FALSE);
  424.     }
  425.  
  426.     /* record the pointer to the line just past the EOP */
  427.     gotoeop(FALSE, 1);
  428.     eopline = lforw(curwp->w_dotp);
  429.  
  430.     /* and back to the beginning of the paragraph */
  431.     gotobop(FALSE, 1);
  432.  
  433.     /* let yank() know that it may be restoring a paragraph */
  434.     thisflag |= CFFILL;
  435.  
  436.     if(Pmaster == NULL)
  437.       sgarbk = TRUE;
  438.  
  439.         curwp->w_flag |= WFMODE;
  440.     kdelete();
  441.  
  442.     /* initialize various info */
  443.     clength = curwp->w_doto;
  444.     if (clength && curwp->w_dotp->l_text[0].c == TAB)
  445.         clength = 8;
  446.     wordlen = 0;
  447.     dotflag = FALSE;
  448.  
  449.     /* scan through lines, filling words */
  450.     firstflag = TRUE;
  451.     eopflag = FALSE;
  452.  
  453.     while (!eopflag) {
  454.         /* get the next character in the paragraph */
  455.         if (curwp->w_doto == llength(curwp->w_dotp)) {
  456.  
  457.             c = ' ';
  458.             if (lforw(curwp->w_dotp) == eopline)
  459.                 eopflag = TRUE;
  460.             kinsert('\n');
  461.         } else {
  462.             c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  463.             kinsert(c);
  464.         }
  465.  
  466.         /* and then delete it */
  467.         ldelete(1, FALSE);
  468.  
  469.         /* if not a separator, just add it in */
  470.         if (c != ' ' && c != '    ') {
  471.             /* 
  472.              * don't want to limit ourselves to only '.'
  473.              */
  474.             dotflag = (int)strchr(".?!:;\"", c);    /* dot ? */
  475.             if (wordlen < NSTRING - 1)
  476.                 wbuf[wordlen++] = c;
  477.         } else if (wordlen) {
  478.             /* at a word break with a word waiting */
  479.             /* calculate tantitive new length with word added */
  480.             newlength = clength + 1 + wordlen;
  481.             if (newlength <= fillcol) {
  482.                 /* add word to current line */
  483.                 if (!firstflag) {
  484.                     linsert(1, ' '); /* the space */
  485.                     ++clength;
  486.                 }
  487.                 firstflag = FALSE;
  488.             } else {
  489.                 /* start a new line */
  490.                 lnewline();
  491.                 clength = 0;
  492.             }
  493.  
  494.             /* and add the word in in either case */
  495.             for (i=0; i<wordlen; i++) {
  496.                 linsert(1, wbuf[i]);
  497.                 ++clength;
  498.             }
  499.  
  500.             /*  Strategy:  Handle 3 cases:
  501.              *     1. if . at end of line put extra space after it
  502.              *     2. if . and only 1 space, leave only one space 
  503.              *     3. if . and more than 1 space, leave 2 spaces
  504.              *
  505.              *  So, we know the current c is a space. if then 
  506.              *  is no next c or the next c is a ' ' then we 
  507.              *  need to insert a space else don't do it.
  508.              */
  509.             if (dotflag &&
  510.                    ((curwp->w_doto == llength(curwp->w_dotp)) || 
  511.                (' ' == lgetc(curwp->w_dotp, curwp->w_doto).c))){
  512.                 linsert(1, ' ');
  513.                 ++clength;
  514.             }
  515.             wordlen = 0;
  516.         }
  517.     }
  518.  
  519.     /* and add a last newline for the end of our new paragraph */
  520.     lnewline();
  521. }