home *** CD-ROM | disk | FTP | other *** search
/ Best Objectech Shareware Selections / UNTITLED.iso / boss / word / text / 024 / wordwrap.c < prev   
C/C++ Source or Header  |  1993-06-04  |  30KB  |  978 lines

  1. /*
  2.  * This module contains the word wrap and format paragraph functions.  The
  3.  *  right_justify( ) function is based on the spread function in _Software
  4.  *  Tools_ by Brian Kernighan and P J Plauger.  My version of the spread
  5.  *  function handles lines with extra blanks in the text, e.g. two blanks
  6.  *  after periods.  All of the other word processing routines are original
  7.  *  and written by me, Frank, and are not guaranteed to work as designed.
  8.  *
  9.  * See:
  10.  *
  11.  *   Brian W. Kernighan and P. J. Plauger, _Software Tools_, Addison-
  12.  *    Wesly, Reading, Mass., 1976, Section 7.7, "Right Margin Justification",
  13.  *    pp 239-242.  ISBN 0-201-03669-X.
  14.  *
  15.  * Note: right margin justification was added in TDE 2.2.
  16.  *
  17.  * New editor name:  TDE, the Thomson-Davis Editor.
  18.  * Author:           Frank Davis
  19.  * Date:             June 5, 1991, version 1.0
  20.  * Date:             July 29, 1991, version 1.1
  21.  * Date:             October 5, 1991, version 1.2
  22.  * Date:             January 20, 1992, version 1.3
  23.  * Date:             February 17, 1992, version 1.4
  24.  * Date:             April 1, 1992, version 1.5
  25.  * Date:             June 5, 1992, version 2.0
  26.  * Date:             October 31, 1992, version 2.1
  27.  * Date:             April 1, 1993, version 2.2
  28.  * Date:             June 5, 1993, version 3.0
  29.  *
  30.  * This code is released into the public domain, Frank Davis.
  31.  * You may distribute it freely.
  32.  */
  33.  
  34. #include "tdestr.h"     /* global variables definitions */
  35. #include "common.h"     /* external global variable declarations */
  36. #include "define.h"
  37. #include "tdefunc.h"
  38.  
  39.  
  40. /*
  41.  * Name:    find_left_margin
  42.  * Purpose: find left margin depending on word wrap mode
  43.  * Date:    June 5, 1992
  44.  * Passed:  ll:         node pointer to current line
  45.  *          wrap_mode:  current word wrap mode
  46.  * Notes:   the algorithm used to figure the indent column was yanked out
  47.  *           of the insert_newline( ) function and was made into a more
  48.  *           general algorithm for figuring the left margin irregardless
  49.  *           of word wrap or indent mode.  when in the DYNAMIC_WRAP mode,
  50.  *           the user don't have to keep changing the left margin when
  51.  *           special indentation is needed.
  52.  */
  53. int  find_left_margin( line_list_ptr ll, int wrap_mode )
  54. {
  55. register int lm;
  56. int  len;
  57. text_ptr source;
  58.  
  59.    if (wrap_mode == FIXED_WRAP) {
  60.       /*
  61.        * for FIXED_WRAP mode, the left and paragraph margins are determined
  62.        *   from the master mode structure.
  63.        */
  64.       if (g_status.copied) {
  65.          source = (text_ptr)g_status.line_buff;
  66.          len    = g_status.line_buff_len;
  67.       } else {
  68.          if (ll->prev != NULL) {
  69.             source = ll->prev->line;
  70.             len    = ll->prev->len;
  71.          } else {
  72.             source = NULL;
  73.             len    = 0;
  74.          }
  75.       }
  76.       if (source == NULL)
  77.          lm = mode.parg_margin;
  78.       else if (find_end( source, len ) == 0)
  79.          lm = mode.parg_margin;
  80.       else
  81.          lm = mode.left_margin;
  82.    } else {
  83.       /*
  84.        * for Indent and DYNAMIC_WRAP modes, the left margin is determined
  85.        *  from the first non blank line above the cursor.
  86.        */
  87.       if (g_status.copied == TRUE) {
  88.          source = (text_ptr)g_status.line_buff;
  89.          len    = g_status.line_buff_len;
  90.       } else {
  91.          source = ll->line;
  92.          len    = ll->len;
  93.       }
  94.       lm = first_non_blank( source, len );
  95.       if (is_line_blank( source, len ) && ll->prev != NULL) {
  96.          for (ll=ll->prev; ll != NULL; ll=ll->prev) {
  97.             lm = first_non_blank( ll->line, ll->len );
  98.             if (!is_line_blank( ll->line, ll->len ))
  99.                break;
  100.          }
  101.       }
  102.    }
  103.    return( lm );
  104. }
  105.  
  106.  
  107. /*
  108.  * Name:    word_wrap
  109.  * Purpose: make sure lines don't get longer than right margin
  110.  * Date:    November 27, 1991
  111.  * Passed:  window:  pointer to current window
  112.  * Notes:   rcol, lm, rm, pm all start counting at zero.
  113.  *          len (line length) starts counting at 1.
  114.  *
  115.  *          when we compare margins and line lengths, we either have to
  116.  *          add one to the margins or subtract one from the len.  I add
  117.  *          one to the margins.
  118.  */
  119. void word_wrap( WINDOW *window )
  120. {
  121. int  c;                 /* character the user just entered. */
  122. register int len;       /* length of current line */
  123. int  i;                 /* padding spaces required */
  124. line_list_ptr p;        /* line above wrapped line */
  125. int  rcol;
  126. int  lm;
  127. int  rm;
  128. int  side;
  129. register WINDOW *win;          /* put window pointer in a register */
  130.  
  131.    win = window;
  132.  
  133.    /*
  134.     * set up a few local variables.
  135.     */
  136.    c = g_status.key_pressed;
  137.    rcol = win->rcol;
  138.    copy_line( win->ll );
  139.    detab_linebuff( );
  140.  
  141.    /*
  142.     * always start the right margin justification on the right side
  143.     *  at the beginning of paragraphs.  then, alternate with left margin.
  144.     */
  145.    side = 1;
  146.    p = win->ll->prev;
  147.    while (p != NULL  &&  !is_line_blank( p->line, p->len )) {
  148.       ++side;
  149.       p = p->prev;
  150.    }
  151.    side = (side & 1) ? RIGHT : LEFT;
  152.  
  153.  
  154.    /*
  155.     * when we wrap, we need know where the left margin is.
  156.     * let's look at the line above to see if this is the first line
  157.     * in a paragraph.
  158.     */
  159.    p = win->ll->prev;
  160.  
  161.    lm = find_left_margin( win->ll, mode.word_wrap );
  162.    rm = mode.right_margin;
  163.  
  164.    /*
  165.     * there two ways that words are pushed onto next line.
  166.     *  1. if the word being typed goes over the right margin
  167.     *  2. typing a word in the middle of the line pushes words at end of
  168.     *     line to next line
  169.     *
  170.     * if the user enters spaces past the right margin then we don't
  171.     *  word wrap spaces.
  172.     */
  173.    len = g_status.line_buff_len;
  174.    if (rcol > rm+1 && c != ' ') {
  175.  
  176.       /*
  177.        * if this is the first line in a paragraph then set left margin
  178.        *  to paragraph margin.
  179.        */
  180.       if ((p == NULL || is_line_blank( p->line, p->len )) &&
  181.            first_non_blank( (text_ptr)g_status.line_buff,
  182.                  g_status.line_buff_len ) > rm && mode.word_wrap == FIXED_WRAP)
  183.          lm = mode.parg_margin;
  184.  
  185.       /*
  186.        * simple word wrap.  the cursor goes past the right margin.
  187.        *  find the beginning of the word and put it on a new line.
  188.        *
  189.        * Special case - if the word begins at the left margin then
  190.        *  don't wrap it.
  191.        */
  192.       for (i=rcol-1; i > lm  &&  g_status.line_buff[i] != ' '; )
  193.          i--;
  194.       if (i > lm) {
  195.          i++;
  196.          win->rcol = i;
  197.          g_status.command = WordWrap;
  198.          insert_newline( win );
  199.          if (mode.right_justify == TRUE)
  200.             justify_right_margin( win, win->ll->prev,
  201.                  mode.word_wrap == FIXED_WRAP ? find_left_margin( win->ll->prev,
  202.                  mode.word_wrap ) : lm, rm, side );
  203.  
  204.          /*
  205.           * find out where to place the cursor on the new line.
  206.           */
  207.          win->rcol = lm + rcol - i;
  208.          check_virtual_col( win, win->rcol, win->rcol );
  209.  
  210.          /*
  211.           * we just wrapped the word at the eol.  now, let's see if
  212.           *  we can combine it with the line below.  since just added
  213.           *  a line, set new_line to false - don't add another line.
  214.           */
  215.  
  216.          len = find_end( win->ll->line, win->ll->len );
  217.          if (len < rm+1)
  218.             combine_wrap_spill( win, len, lm, rm, side, FALSE );
  219.       }
  220.    } else if (len > rm+1) {
  221.  
  222.       /*
  223.        * this is the second word wrap case.  we are pushing words onto
  224.        * next line.  we need to now what character is in the right margin.
  225.        *
  226.        * 1) if the character is not a space, then we need to search backwards
  227.        *    to find the start of the word that is on the right margin.
  228.        * 2) if the character is a space, then we need to search forward to
  229.        *    find the word that is over the right margin.
  230.        */
  231.  
  232.       /*
  233.        * don't wrap spaces past right margin
  234.        */
  235.       if (c == ' ' && rcol > rm) {
  236.          for (i=rcol; i<len && g_status.line_buff[i] == ' ';)
  237.             i++;
  238.  
  239.          /*
  240.