home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / pine4.10.tar.gz / pine4.10.tar / pine4.10 / pico / word.c < prev   
C/C++ Source or Header  |  1998-04-02  |  16KB  |  554 lines

  1. #if    !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: word.c,v 4.30 1998/04/02 20:48: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.  *
  19.  * Pine and Pico are registered trademarks of the University of Washington.
  20.  * No commercial use of these trademarks may be made without prior written
  21.  * permission of the University of Washington.
  22.  * 
  23.  * Pine, Pico, and Pilot software and its included text are Copyright
  24.  * 1989-1998 by the University of Washington.
  25.  * 
  26.  * The full text of our legal notices is contained in the file called
  27.  * CPYRIGHT, included with this distribution.
  28.  *
  29.  */
  30. /*
  31.  * The routines in this file implement commands that work word at a time.
  32.  * There are all sorts of word mode commands. If I do any sentence and/or
  33.  * paragraph mode commands, they are likely to be put in this file.
  34.  */
  35.  
  36. #include    "headers.h"
  37.  
  38.  
  39. /* Word wrap on n-spaces. Back-over whatever precedes the point on the current
  40.  * line and stop on the first word-break or the beginning of the line. If we
  41.  * reach the beginning of the line, jump back to the end of the word and start
  42.  * a new line.  Otherwise, break the line at the word-break, eat it, and jump
  43.  * back to the end of the word.
  44.  * Returns TRUE on success, FALSE on errors.
  45.  */
  46. wrapword()
  47. {
  48.     register int cnt;            /* size of word wrapped to next line */
  49.     register int bp;            /* index to wrap on */
  50.     register int first = -1;
  51.     register int i;
  52.  
  53.     if(curwp->w_doto <= 0)        /* no line to wrap? */
  54.       return(FALSE);
  55.  
  56.     for(bp = cnt = i = 0; cnt < llength(curwp->w_dotp) && !bp; cnt++, i++){
  57.     if(isspace((unsigned char) lgetc(curwp->w_dotp, cnt).c)){
  58.         first = 0;
  59.         if(lgetc(curwp->w_dotp, cnt).c == TAB)
  60.           while(i+1 & 0x07)
  61.         i++;
  62.     }
  63.     else if(!first)
  64.       first = cnt;
  65.  
  66.     if(first > 0 && i >= fillcol)
  67.       bp = first;
  68.     }
  69.  
  70.     if(!bp)
  71.       return(FALSE);
  72.  
  73.     /* bp now points to the first character of the next line */
  74.     cnt = curwp->w_doto - bp;
  75.     curwp->w_doto = bp;
  76.  
  77.     if(!lnewline())            /* break the line */
  78.       return(FALSE);
  79.  
  80.     /* clean up trailing whitespace from line above ... */
  81.     if(backchar(FALSE, 1)){
  82.     while(llength(curwp->w_dotp) > 0 && backchar(FALSE, 1)
  83.           && isspace((unsigned char) lgetc(curwp->w_dotp, curwp->w_doto).c)
  84.           && (cnt > 0 || cnt < -1)){
  85.         forwdel(FALSE, 1);
  86.         if(cnt < 0)
  87.           ++cnt;
  88.     }
  89.  
  90.     gotoeol(FALSE, 1);
  91.     forwchar(FALSE, 1);        /* goto first char of next line */
  92.     }
  93.  
  94.     /*
  95.      * if there's a line below, it doesn't start with whitespace 
  96.      * and there's room for this line...
  97.      */
  98.     if(!(curbp->b_flag & BFWRAPOPEN)
  99.        && lforw(curwp->w_dotp) != curbp->b_linep 
  100.        && llength(lforw(curwp->w_dotp)) 
  101.        && !isspace((unsigned char) lgetc(lforw(curwp->w_dotp), 0).c)
  102.        && (llength(curwp->w_dotp) + llength(lforw(curwp->w_dotp)) < fillcol)){
  103.     gotoeol(0, 1);            /* then pull text up from below */
  104.     if(lgetc(curwp->w_dotp, curwp->w_doto - 1).c != ' ')
  105.       linsert(1, ' ');
  106.  
  107.     forwdel(0, 1);
  108.     gotobol(0, 1);
  109.     }
  110.  
  111.     curbp->b_flag &= ~BFWRAPOPEN;    /* don't open new line next wrap */
  112.                     /* restore dot (account for NL)  */
  113.     if(cnt && !forwchar(0, cnt < 0 ? cnt-1 : cnt))
  114.       return(FALSE);
  115.  
  116.     return(TRUE);
  117. }
  118.  
  119.  
  120. /*
  121.  * Move the cursor backward by "n" words. All of the details of motion are
  122.  * performed by the "backchar" and "forwchar" routines. Error if you try to
  123.  * move beyond the buffers.
  124.  */
  125. backword(f, n)
  126.     int f, n;
  127. {
  128.         if (n < 0)
  129.                 return (forwword(f, -n));
  130.         if (backchar(FALSE, 1) == FALSE)
  131.                 return (FALSE);
  132.         while (n--) {
  133.                 while (inword() == FALSE) {
  134.                         if (backchar(FALSE, 1) == FALSE)
  135.                                 return (FALSE);
  136.                 }
  137.                 while (inword() != FALSE) {
  138.                         if (backchar(FALSE, 1) == FALSE)
  139.                                 return (FALSE);
  140.                 }
  141.         }
  142.         return (forwchar(FALSE, 1));
  143. }
  144.  
  145. /*
  146.  * Move the cursor forward by the specified number of words. All of the motion
  147.  * is done by "forwchar". Error if you try and move beyond the buffer's end.
  148.  */
  149. forwword(f, n)
  150.     int f, n;
  151. {
  152.         if (n < 0)
  153.                 return (backword(f, -n));
  154.         while (n--) {
  155. #if    NFWORD
  156.                 while (inword() != FALSE) {
  157.                         if (forwchar(FALSE, 1) == FALSE)
  158.                                 return (FALSE);
  159.                 }
  160. #endif
  161.                 while (inword() == FALSE) {
  162.                         if (forwchar(FALSE, 1) == FALSE)
  163.                                 return (FALSE);
  164.                 }
  165. #if    NFWORD == 0
  166.                 while (inword() != FALSE) {
  167.                         if (forwchar(FALSE, 1) == FALSE)
  168.                                 return (FALSE);
  169.                 }
  170. #endif
  171.         }
  172.     return(TRUE);
  173. }
  174.  
  175. #ifdef    MAYBELATER
  176. /*
  177.  * Move the cursor forward by the specified number of words. As you move,
  178.  * convert any characters to upper case. Error if you try and move beyond the
  179.  * end of the buffer. Bound to "M-U".
  180.  */
  181. upperword(f, n)
  182. {
  183.         register int    c;
  184.     CELL            ac;
  185.  
  186.     ac.a = 0;
  187.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  188.         return(rdonly());    /* we are in read only mode    */
  189.         if (n < 0)
  190.                 return (FALSE);
  191.         while (n--) {
  192.                 while (inword() == FALSE) {
  193.                         if (forwchar(FALSE, 1) == FALSE)
  194.                                 return (FALSE);
  195.                 }
  196.                 while (inword() != FALSE) {
  197.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  198.                         if (c>='a' && c<='z') {
  199.                                 ac.c = (c -= 'a'-'A');
  200.                                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  201.                                 lchange(WFHARD);
  202.                         }
  203.                         if (forwchar(FALSE, 1) == FALSE)
  204.                                 return (FALSE);
  205.                 }
  206.         }
  207.         return (TRUE);
  208. }
  209.  
  210. /*
  211.  * Move the cursor forward by the specified number of words. As you move
  212.  * convert characters to lower case. Error if you try and move over the end of
  213.  * the buffer. Bound to "M-L".
  214.  */
  215. lowerword(f, n)
  216. {
  217.         register int    c;
  218.     CELL            ac;
  219.  
  220.     ac.a = 0;
  221.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  222.         return(rdonly());    /* we are in read only mode    */
  223.         if (n < 0)
  224.                 return (FALSE);
  225.         while (n--) {
  226.                 while (inword() == FALSE) {
  227.                         if (forwchar(FALSE, 1) == FALSE)
  228.                                 return (FALSE);
  229.                 }
  230.                 while (inword() != FALSE) {
  231.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  232.                         if (c>='A' && c<='Z') {
  233.                                 ac.c (c += 'a'-'A');
  234.                                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  235.                                 lchange(WFHARD);
  236.                         }
  237.                         if (forwchar(FALSE, 1) == FALSE)
  238.                                 return (FALSE);
  239.                 }
  240.         }
  241.         return (TRUE);
  242. }
  243.  
  244. /*
  245.  * Move the cursor forward by the specified number of words. As you move
  246.  * convert the first character of the word to upper case, and subsequent
  247.  * characters to lower case. Error if you try and move past the end of the
  248.  * buffer. Bound to "M-C".
  249.  */
  250. capword(f, n)
  251. {
  252.         register int    c;
  253.     CELL            ac;
  254.  
  255.     ac.a = 0;
  256.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  257.         return(rdonly());    /* we are in read only mode    */
  258.         if (n < 0)
  259.                 return (FALSE);
  260.         while (n--) {
  261.                 while (inword() == FALSE) {
  262.                         if (forwchar(FALSE, 1) == FALSE)
  263.                                 return (FALSE);
  264.                 }
  265.                 if (inword() != FALSE) {
  266.                         c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  267.                         if (c>='a' && c<='z') {
  268.                 ac.c = (c -= 'a'-'A');
  269.                 lputc(curwp->w_dotp, curwp->w_doto, ac);
  270.                 lchange(WFHARD);
  271.                         }
  272.                         if (forwchar(FALSE, 1) == FALSE)
  273.                                 return (FALSE);
  274.                         while (inword() != FALSE) {
  275.                                 c = lgetc(curwp->w_dotp, curwp->w_doto).c;
  276.                                 if (c>='A' && c<='Z') {
  277.                     ac.c = (c += 'a'-'A');
  278.                     lputc(curwp->w_dotp, curwp->w_doto, ac);
  279.                     lchange(WFHARD);
  280.                                 }
  281.                                 if (forwchar(FALSE, 1) == FALSE)
  282.                                         return (FALSE);
  283.                         }
  284.                 }
  285.         }
  286.         return (TRUE);
  287. }
  288.  
  289. /*
  290.  * Kill forward by "n" words. Remember the location of dot. Move forward by
  291.  * the right number of words. Put dot back where it was and issue the kill
  292.  * command for the right number of characters. Bound to "M-D".
  293.  */
  294. delfword(f, n)
  295. {
  296.         register long   size;
  297.         register LINE   *dotp;
  298.         register int    doto;
  299.  
  300.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  301.         return(rdonly());    /* we are in read only mode    */
  302.         if (n < 0)
  303.                 return (FALSE);
  304.         dotp = curwp->w_dotp;
  305.         doto = curwp->w_doto;
  306.         size = 0L;
  307.         while (n--) {
  308. #if    NFWORD
  309.         while (inword() != FALSE) {
  310.             if (forwchar(FALSE,1) == FALSE)
  311.                 return(FALSE);
  312.             ++size;
  313.         }
  314. #endif
  315.                 while (inword() == FALSE) {
  316.                         if (forwchar(FALSE, 1) == FALSE)
  317.                                 return (FALSE);
  318.                         ++size;
  319.                 }
  320. #if    NFWORD == 0
  321.                 while (inword() != FALSE) {
  322.                         if (forwchar(FALSE, 1) == FALSE)
  323.                                 return (FALSE);
  324.                         ++size;
  325.                 }
  326. #endif
  327.         }
  328.         curwp->w_dotp = dotp;
  329.         curwp->w_doto = doto;
  330.         return (ldelete(size, kinsert));
  331. }
  332.  
  333. /*
  334.  * Kill backwards by "n" words. Move backwards by the desired number of words,
  335.  * counting the characters. When dot is finally moved to its resting place,
  336.  * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
  337.  */
  338. delbword(f, n)
  339. {
  340.         register long   size;
  341.  
  342.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  343.         return(rdonly());    /* we are in read only mode    */
  344.         if (n < 0)
  345.                 return (FALSE);
  346.         if (backchar(FALSE, 1) == FALSE)
  347.                 return (FALSE);
  348.         size = 0L;
  349.         while (n--) {
  350.                 while (inword() == FALSE) {
  351.                         if (backchar(FALSE, 1) == FALSE)
  352.                                 return (FALSE);
  353.                         ++size;
  354.                 }
  355.                 while (inword() != FALSE) {
  356.                         if (backchar(FALSE, 1) == FALSE)
  357.                                 return (FALSE);
  358.                         ++size;
  359.                 }
  360.         }
  361.         if (forwchar(FALSE, 1) == FALSE)
  362.                 return (FALSE);
  363.         return (ldelete(size, kinsert));
  364. }
  365. #endif    /* MAYBELATER */
  366.  
  367. /*
  368.  * Return TRUE if the character at dot is a character that is considered to be
  369.  * part of a word. The word character list is hard coded. Should be setable.
  370.  */
  371. inword()
  372. {
  373.     return(curwp->w_doto < llength(curwp->w_dotp)
  374.        && isalnum((unsigned char)lgetc(curwp->w_dotp, curwp->w_doto).c));
  375. }
  376.  
  377.  
  378. /*
  379.  * Return TRUE if whatever starts the line matches the quote string
  380.  */
  381. quote_match(q, l)
  382.     char *q;
  383.     LINE *l;
  384. {
  385.     register int i;
  386.  
  387.     for(i = 0; i <= llength(l) && q[i]; i++)
  388.       if(q[i] != lgetc(l, i).c)
  389.     return(0);
  390.  
  391.     return(1);
  392. }
  393.  
  394.  
  395. fillpara(f, n)    /* Fill the current paragraph according to the current
  396.            fill column                        */
  397.  
  398. int f, n;    /* deFault flag and Numeric argument */
  399.  
  400. {
  401.     int        i, j, c, qlen, word[NSTRING], same_word,
  402.         spaces, word_len, line_len, line_last;
  403.     char   *qstr;
  404.     LINE   *eopline;
  405.     REGION  region;
  406.  
  407.     if(curbp->b_mode&MDVIEW){        /* don't allow this command if    */
  408.     return(rdonly());        /* we are in read only mode    */
  409.     }
  410.     else if (fillcol == 0) {        /* no fill column set */
  411.     mlwrite("No fill column set", NULL);
  412.     return(FALSE);
  413.     }
  414.     else if(curwp->w_dotp == curbp->b_linep) /* don't wrap! */
  415.       return(FALSE);
  416.  
  417.     /* record the pointer to the line just past the EOP */
  418.     if(gotoeop(FALSE, 1) == FALSE)
  419.       return(FALSE);
  420.  
  421.     eopline = curwp->w_dotp;        /* first line of para */
  422.  
  423.     /* and back to the beginning of the paragraph */
  424.     gotobop(FALSE, 1);
  425.  
  426.     /* determine if we're justifying quoted text or not */
  427.     qstr = (Pmaster && Pmaster->quote_str
  428.           && quote_match(Pmaster->quote_str, curwp->w_dotp))
  429.          ? Pmaster->quote_str : NULL;
  430.     qlen = qstr ? strlen(qstr) : 0;
  431.  
  432.     /* let yank() know that it may be restoring a paragraph */
  433.     thisflag |= CFFILL;
  434.  
  435.     if(!Pmaster)
  436.       sgarbk = TRUE;
  437.     
  438.     curwp->w_flag |= WFMODE;
  439.  
  440.     /* cut the paragraph into our fill buffer */
  441.     fdelete();
  442.     curwp->w_doto = 0;
  443.     getregion(®ion, eopline, llength(eopline));
  444.     if(!ldelete(region.r_size, finsert))
  445.       return(FALSE);
  446.  
  447.     /* Now insert it back wrapped */
  448.     spaces = word_len = line_len = same_word = 0;
  449.  
  450.     /* Beginning with leading quoting... */
  451.     if(qstr){
  452.     while(qstr[line_len])
  453.       linsert(1, qstr[line_len++]);
  454.  
  455.     line_last = ' ';            /* no word-flush space! */
  456.     }
  457.  
  458.     /* ...and leading white space */
  459.     for(i = qlen; (c = fremove(i)) == ' ' || c == TAB; i++){
  460.     linsert(1, line_last = c);
  461.     line_len += ((c == TAB) ? (~line_len & 0x07) + 1 : 1);
  462.     }
  463.  
  464.     /* then digest the rest... */
  465.     while((c = fremove(i++)) > 0){
  466.     switch(c){
  467.       case '\n' :
  468.         i += qlen;                /* skip next quote string */
  469.  
  470.       case TAB :
  471.       case ' ' :
  472.         spaces++;
  473.         same_word = 0;
  474.         break;
  475.  
  476.       default :
  477.         if(spaces){                /* flush word? */
  478.         if(line_len
  479.            && line_len + word_len + qlen + 1 > fillcol
  480.            && (line_len = fpnewline(qstr)))
  481.           line_last = ' ';    /* no word-flush space! */
  482.  
  483.         if(word_len){            /* word to write? */
  484.             if(line_len && !isspace((unsigned char) line_last)){
  485.             linsert(1, ' ');    /* need padding? */
  486.             line_len++;
  487.             }
  488.  
  489.             line_len += word_len;
  490.             for(j = 0; j < word_len; j++)
  491.               linsert(1, line_last = word[j]);
  492.  
  493.             if(spaces > 1 && strchr(".?!:;\")", line_last)){
  494.             linsert(2, line_last = ' ');
  495.             line_len += 2;
  496.             }
  497.  
  498.             word_len = 0;
  499.         }
  500.  
  501.         spaces = 0;
  502.         }
  503.  
  504.         if(word_len + 1 >= NSTRING){
  505.         /* Magic!  Fake that we output a wrapped word */
  506.         if(line_len && !same_word++)
  507.           line_len = fpnewline(qstr);
  508.  
  509.         line_len += word_len;
  510.         for(j = 0; j < word_len; j++)
  511.           linsert(1, word[j]);
  512.  
  513.         word_len  = 0;
  514.         line_last = ' ';
  515.         }
  516.  
  517.         word[word_len++] = c;
  518.         break;
  519.     }
  520.     }
  521.  
  522.     if(word_len){
  523.     if(line_len + word_len + qlen + 1 > fillcol)
  524.       (void) fpnewline(qstr);
  525.     else if(line_len && !isspace((unsigned char) line_last))
  526.       linsert(1, ' ');
  527.  
  528.     for(j = 0; j < word_len; j++)
  529.       linsert(1, word[j]);
  530.     }
  531.  
  532.     /* Leave cursor on first char of first line after paragraph */
  533.     curwp->w_dotp = lforw(curwp->w_dotp);
  534.     curwp->w_doto = 0;
  535.  
  536.     return(TRUE);
  537. }
  538.  
  539.  
  540. /*
  541.  * fpnewline - output a fill paragraph newline mindful of quote string
  542.  */
  543. fpnewline(quote)
  544. char *quote;
  545. {
  546.     int len;
  547.  
  548.     lnewline();
  549.     for(len = 0; quote && *quote; quote++, len++)
  550.       linsert(1, *quote);
  551.  
  552.     return(len);
  553. }
  554.