home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / progmisc / tde221.zip / WORDWRAP.C < prev   
C/C++ Source or Header  |  1993-04-01  |  30KB  |  975 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.  *
  29.  * This code is released into the public domain, Frank Davis.
  30.  * You may distribute it freely.
  31.  */
  32.  
  33. #include "tdestr.h"     /* global variables definitions */
  34. #include "common.h"     /* external global variable declarations */
  35. #include "define.h"
  36. #include "tdefunc.h"
  37.  
  38.  
  39. /*
  40.  * Name:    find_left_margin
  41.  * Purpose: find left margin depending on word wrap mode
  42.  * Date:    June 5, 1992
  43.  * Passed:  ll:         node pointer to current line
  44.  *          wrap_mode:  current word wrap mode
  45.  * Notes:   the algorithm used to figure the indent column was yanked out
  46.  *           of the insert_newline( ) function and was made into a more
  47.  *           general algorithm for figuring the left margin irregardless
  48.  *           of word wrap or indent mode.  when in the DYNAMIC_WRAP mode,
  49.  *           the user don't have to keep changing the left margin when
  50.  *           special indentation is needed.
  51.  */
  52. int  find_left_margin( line_list_ptr ll, int wrap_mode )
  53. {
  54. register int lm;
  55. int  len;
  56. text_ptr source;
  57.  
  58.    if (wrap_mode == FIXED_WRAP) {
  59.       /*
  60.        * for FIXED_WRAP mode, the left and paragraph margins are determined
  61.        *   from the master mode structure.
  62.        */
  63.       if (g_status.copied) {
  64.          source = (text_ptr)g_status.line_buff;
  65.          len    = g_status.line_buff_len;
  66.       } else {
  67.          if (ll->prev != NULL) {
  68.             source = ll->prev->line;
  69.             len    = ll->prev->len;
  70.          } else {
  71.             source = NULL;
  72.             len    = 0;
  73.          }
  74.       }
  75.       if (source == NULL)
  76.          lm = mode.parg_margin;
  77.       else if (find_end( source, len ) == 0)
  78.          lm = mode.parg_margin;
  79.       else
  80.          lm = mode.left_margin;
  81.    } else {
  82.       /*
  83.        * for Indent and DYNAMIC_WRAP modes, the left margin is determined
  84.        *  from the first non blank line above the cursor.
  85.        */
  86.       if (g_status.copied == TRUE) {
  87.          source = (text_ptr)g_status.line_buff;
  88.          len    = g_status.line_buff_len;
  89.       } else {
  90.          source = ll->line;
  91.          len    = ll->len;
  92.       }
  93.       lm = first_non_blank( source, len );
  94.       if (is_line_blank( source, len ) && ll->prev != NULL) {
  95.          for (ll=ll->prev; ll != NULL; ll=ll->prev) {
  96.             lm = first_non_blank( ll->line, ll->len );
  97.             if (!is_line_blank( ll->line, ll->len ))
  98.                break;
  99.          }
  100.       }
  101.    }
  102.    return( lm );
  103. }
  104.  
  105.  
  106. /*
  107.  * Name:    word_wrap
  108.  * Purpose: make sure lines don't get longer than right margin
  109.  * Date:    November 27, 1991
  110.  * Passed:  window:  pointer to current window
  111.  * Notes:   rcol, lm, rm, pm all start counting at zero.
  112.  *          len (line length) starts counting at 1.
  113.  *
  114.  *          when we compare margins and line lengths, we either have to
  115.  *          add one to the margins or subtract one from the len.  I add
  116.  *          one to the margins.
  117.  */
  118. void word_wrap( WINDOW *window )
  119. {
  120. int  c;                 /* character the user just entered. */
  121. register int len;       /* length of current line */
  122. int  i;                 /* padding spaces required */
  123. line_list_ptr p;        /* line above wrapped line */
  124. int  rcol;
  125. int  lm;
  126. int  rm;
  127. int  side;
  128. register WINDOW *win;          /* put window pointer in a register */
  129.  
  130.    win = window;
  131.  
  132.    /*
  133.     * set up a few local variables.
  134.     */
  135.    c = g_status.key_pressed;
  136.    rcol = win->rcol;
  137.    copy_line( win->ll );
  138.    detab_linebuff( );
  139.  
  140.    /*
  141.     * always start the right margin justification on the right side
  142.     *  at the beginning of paragraphs.  then, alternate with left margin.
  143.     */
  144.    side = 1;
  145.    p = win->ll->prev;
  146.    while (p != NULL  &&  !is_line_blank( p->line, p->len )) {
  147.       ++side;
  148.       p = p->prev;
  149.    }
  150.    side = (side & 1) ? RIGHT : LEFT;
  151.  
  152.  
  153.    /*
  154.     * when we wrap, we need know where the left margin is.
  155.     * let's look at the line above to see if this is the first line
  156.     * in a paragraph.
  157.     */
  158.    p = win->ll->prev;
  159.  
  160.    lm = find_left_margin( win->ll, mode.word_wrap );
  161.    rm = mode.right_margin;
  162.  
  163.    /*
  164.     * there two ways that words are pushed onto next line.
  165.     *  1. if the word being typed goes over the right margin
  166.     *  2. typing a word in the middle of the line pushes words at end of
  167.     *     line to next line
  168.     *
  169.     * if the user enters spaces past the right margin then we don't
  170.     *  word wrap spaces.
  171.     */
  172.    len = g_status.line_buff_len;
  173.    if (rcol > rm+1 && c != ' ') {
  174.  
  175.       /*
  176.        * if this is the first line in a paragraph then set left margin
  177.        *  to paragraph margin.
  178.        */
  179.       if ((p == NULL || is_line_blank( p->line, p->len )) &&
  180.            first_non_blank( (text_ptr)g_status.line_buff,
  181.                  g_status.line_buff_len ) > rm && mode.word_wrap == FIXED_WRAP)
  182.          lm = mode.parg_margin;
  183.  
  184.       /*
  185.        * simple word wrap.  the cursor goes past the right margin.
  186.        *  find the beginning of the word and put it on a new line.
  187.        *
  188.        * Special case - if the word begins at the left margin then
  189.        *  don't wrap it.
  190.        */
  191.       for (i=rcol-1; i > lm  &&  g_status.line_buff[i] != ' '; )
  192.          i--;
  193.       if (i > lm) {
  194.          i++;
  195.          win->rcol = i;
  196.          g_status.command = WordWrap;
  197.          insert_newline( win );
  198.          if (mode.right_justify == TRUE)
  199.             justify_right_margin( win, win->ll->prev,
  200.                  mode.word_wrap == FIXED_WRAP ? find_left_margin( win->ll->prev,
  201.                  mode.word_wrap ) : lm, rm, side );
  202.  
  203.          /*
  204.           * find out where to place the cursor on the new line.
  205.           */
  206.          win->rcol = lm + rcol - i;
  207.          check_virtual_col( win, win->rcol, win->rcol );
  208.  
  209.          /*
  210.           * we just wrapped the word at the eol.  now, let's see if
  211.           *  we can combine it with the line below.  since just added
  212.           *  a line, set new_line to false - don't add another line.
  213.           */
  214.  
  215.          len = find_end( win->ll->line, win->ll->len );
  216.          if (len < rm+1)
  217.             combine_wrap_spill( win, len, lm, rm, side, FALSE );
  218.       }
  219.    } else if (len > rm+1) {
  220.  
  221.       /*
  222.        * this is the second word wrap case.  we are pushing words onto
  223.        * next line.  we need to now what character is in the right margin.
  224.        *
  225.        * 1) if the character is not a space, then we need to search backwards
  226.        *    to find the start of the word that is on the right margin.
  227.        * 2) if the character is a space, then we need to search forward to
  228.        *    find the word that is over the right margin.
  229.        */
  230.  
  231.       /*
  232.        * don't wrap spaces past right margin
  233.        */
  234.       if (c == ' ' && rcol > rm) {
  235.          for (i=rcol; i<len && g_status.line_buff[i] == ' ';)
  236.             i++;
  237.  
  238.          /*
  239.           * if i == len then all that's left on line is blanks - don't wrap.
  240.           */
  241.          if (i < len)
  242.             combine_wrap_spill( win, i, lm, rm, side, TRUE );
  243.  
  244.       } else if (g_status.line_buff[rm+1] != ' ') {
  245.  
  246.          /*
  247.           * search backwards for the word to put on next line.
  248.           */
  249.          for (i=rm+1; i > lm  &&  g_status.line_buff[i] != ' '; )
  250.             i--;
  251.  
  252.          /*
  253.           * if we search all the way back to left margin then test for
  254.           * a special case - see the matching else for more info.
  255.           */
  256.          if (i > lm) {
  257.             i++;
  258.  
  259.             /*
  260.              * if i > rcol then cursor stays on same line.
  261.              */
  262.             if (i > rcol) {
  263.                combine_wrap_spill( win, i, lm, rm, side, TRUE );
  264.  
  265.             /*
  266.              * split the line at or behind the cursor.  almost the
  267.              *  same as when the cursor goes over the right margin.
  268.              */
  269.             } else if (i <= rcol) {
  270.                win->rcol = i;
  271.                g_status.command = WordWrap;
  272.                insert_newline( win );
  273.                if (mode.right_justify == TRUE)
  274.                   justify_right_margin( win, win->ll->prev,
  275.                    mode.word_wrap == FIXED_WRAP ?
  276.                    find_left_margin( win->ll->prev, mode.word_wrap ) : lm,
  277.                    rm, side );
  278.                win->rcol = lm + rcol - i;
  279.                check_virtual_col( win, win->rcol, win->rcol );
  280.                len = find_end( win->ll->line, win->ll->len );
  281.                if (len < rm+1)
  282.                   combine_wrap_spill( win, len, lm, rm, side, FALSE );
  283.             }
  284.          }
  285.  
  286.          /*
  287.           * if the user changed margins or for some reason there's a long
  288.           *  text line, let's see if there are any words past the right
  289.           *  margin.  if we get to this else, we know the current word
  290.           *  begins at least at the left margin.
  291.           *
  292.           * now search forwards for a break
  293.           */
  294.       } else {
  295.  
  296.          /*
  297.           * go to the right margin and see if there are any words past
  298.           *  right margin.
  299.           */
  300.          for (i=rm+1; i<len && g_status.line_buff[i] == ' '; )
  301.             i++;
  302.  
  303.          /*
  304.           * we either found a space or the eol.  test for eol.
  305.           * if i == len then this is one big word - don't wrap it.
  306.           */
  307.          if (i != len)
  308.             combine_wrap_spill( win, i, lm, rm, side, TRUE );
  309.       }
  310.    }
  311. }
  312.  
  313.  
  314. /*
  315.  * Name:    format_paragraph
  316.  * Purpose: format paragraph using left, right, and paragraph margins.
  317.  * Date:    November 27, 1991
  318.  * Passed:  window:  pointer to current window
  319.  */
  320. int  format_paragraph( WINDOW *window )
  321. {
  322. register int len;       /* length of current line */
  323. int  first_line;        /* boolean, first line formatted? */
  324. int  spaces;            /* no. of spaces to add */
  325. line_list_ptr p;        /* scratch pointers */
  326. line_list_ptr pp;
  327. char *source;           /* scratch line buffer pointers */
  328. char *dest;
  329. int  rcol;              /* scratch cols and margins */
  330. int  lm;
  331. int  rm;
  332. int  pm;
  333. int  margin;
  334. int  eop;               /* boolean, (e)nd (o)f (p)aragraph? */
  335. int  old_ww;            /* save state of word wrap flag */
  336. long rline;
  337. WINDOW w;               /* scratch window */
  338.  
  339.    if (window->ll->len == EOF)
  340.       return( ERROR );
  341.    entab_linebuff( );
  342.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  343.       return( ERROR );
  344.    if (!is_line_blank( window->ll->line, window->ll->len )) {
  345.       old_ww = mode.word_wrap;
  346.       if (old_ww == NO_WRAP)
  347.          mode.word_wrap = FIXED_WRAP;
  348.       dup_window_info( &w, window );
  349.  
  350.       /*
  351.        * find the beginning of the paragraph.
  352.        */
  353.       p = w.ll->prev;
  354.       if (g_status.command == FormatParagraph) {
  355.          while (p != NULL &&  !is_line_blank( p->line, p->len )) {
  356.             --w.rline;
  357.             w.ll = w.ll->prev;
  358.             p = p->prev;
  359.          }
  360.          pm = mode.parg_margin;
  361.  
  362.       /*
  363.        * if format text, don't find the beginning of the paragraph.
  364.        *  but we need to know if this is the first line in a paragraph.
  365.        */
  366.       } else if (g_status.command == FormatText) {
  367.          if (p == NULL || is_line_blank( p->line, p->len ))
  368.             pm = mode.parg_margin;
  369.          else
  370.             pm = mode.left_margin;
  371.       } else
  372.          pm = mode.left_margin;
  373.  
  374.       g_status.command = WordWrap;
  375.       p = w.ll;
  376.       if (mode.word_wrap == FIXED_WRAP)
  377.          lm = mode.left_margin;
  378.       else
  379.          lm = pm = find_left_margin( p, mode.word_wrap );
  380.       rm = mode.right_margin;
  381.       eop = FALSE;
  382.  
  383.       /*
  384.        * do the paragraph
  385.        */
  386.       for (first_line=TRUE; p != NULL  &&  !is_line_blank( p->line, p->len ) &&
  387.                             eop == FALSE  &&  !g_status.control_break;) {
  388.  
  389.          /*
  390.           * find out what margin to use
  391.           */
  392.          if (first_line) {
  393.             margin = pm;
  394.             first_line = FALSE;
  395.          } else
  396.             margin = lm;
  397.  
  398.          /*
  399.           * line up the margin
  400.           */
  401.          w.ll->dirty = TRUE;
  402.          copy_line( w.ll );
  403.          detab_linebuff( );
  404.          remove_spaces( 0 );
  405.          rcol = find_word( (text_ptr)g_status.line_buff,
  406.                                      g_status.line_buff_len, 0 );
  407.          if (rcol != ERROR && rcol != margin) {
  408.  
  409.             /*
  410.              * must add spaces to get the indentation right
  411.              */
  412.             if (rcol < margin) {
  413.                source = g_status.line_buff;
  414.                spaces = margin - rcol;
  415.                dest = source + spaces;
  416.  
  417.                assert( g_status.line_buff_len >= 0 );
  418.                assert( g_status.line_buff_len < MAX_LINE_LENGTH );
  419.  
  420.                memmove( dest, source, g_status.line_buff_len );
  421.                g_status.line_buff_len += spaces;
  422.                while (spaces--)
  423.                   *source++ = ' ';
  424.             } else {
  425.                w.rcol = margin;
  426.                word_delete( &w );
  427.                entab_linebuff( );
  428.                un_copy_line( p, &w, TRUE );
  429.                copy_line( w.ll );
  430.                detab_linebuff( );
  431.                remove_spaces( margin );
  432.             }
  433.          }
  434.  
  435.          /*
  436.           * now make sure rest of line is formatted
  437.           */
  438.  
  439.          source = g_status.line_buff;
  440.          len = g_status.line_buff_len;
  441.          for (; len < rm+1 && eop == FALSE;) {
  442.             pp = p->next;
  443.             if (is_line_blank( pp->line, pp->len ))
  444.                eop = TRUE;
  445.             else {
  446.                w.ll = p;
  447.                w.rcol = len + 1;
  448.                if (*(p->line+len-1) == '.')
  449.                   ++w.rcol;
  450.                word_delete( &w );
  451.                entab_linebuff( );
  452.                un_copy_line( p, &w, TRUE );
  453.                copy_line( p );
  454.                detab_linebuff( );
  455.                remove_spaces( margin );
  456.                len = g_status.line_buff_len;
  457.             }
  458.          }
  459.          if (len <= rm+1) {
  460.             entab_linebuff( );
  461.             un_copy_line( p, &w, TRUE );
  462.             p = p->next;
  463.             if (is_line_blank( p->line, p->len ))
  464.                eop = TRUE;
  465.             else {
  466.                w.ll = w.ll->next;
  467.                w.rline++;
  468.             }
  469.          } else {
  470.             w.rcol = rm;
  471.             g_status.key_pressed = *(w.ll->line + rm);
  472.             rline = w.rline;
  473.             word_wrap( &w );
  474.             if (rline == w.rline) {
  475.                w.ll = w.ll->next;
  476.                ++w.rline;
  477.             }
  478.          }
  479.          g_status.copied = FALSE;
  480.          p = w.ll;
  481.       }
  482.       mode.word_wrap = old_ww;
  483.       g_status.copied = FALSE;
  484.       w.file_info->dirty = GLOBAL;
  485.    }
  486.    return( OK );
  487. }
  488.  
  489.  
  490. /*
  491.  * Name:    combine_wrap_spill
  492.  * Purpose: combine word wrap lines so we don't push each word onto a
  493.  *          separate line.
  494.  * Date:    November 27, 1991
  495.  * Passed:  window:   pointer to current window
  496.  *          wrap_col: col to combine next line
  497.  *          lm:       left margin
  498.  *          rm:       right margin
  499.  *          side:     left or right margin to insert spaces
  500.  *          new_line: boolean, should we insert a new line?
  501.  */
  502. void combine_wrap_spill( WINDOW *window, int wrap_col, int lm, int rm,
  503.                          int side, int new_line )
  504. {
  505. line_list_ptr p;        /* line we wrapped */
  506. line_list_ptr pp;       /* pointer to next line after wrapped line */
  507. int  p_len;             /* length of line we just word wrapped */
  508. int  non_blank;         /* first non-blank column on next line */
  509. int  control_t;         /* number of times to call word_delete */
  510. int  next_line_len;     /* length of next line counting from 1st word */
  511. WINDOW w;               /* scratch window */
  512.  
  513.    dup_window_info( &w, window );
  514.    g_status.command = WordWrap;
  515.    w.rcol = wrap_col;
  516.    if (new_line) {
  517.       insert_newline( &w );
  518.       if (mode.right_justify == TRUE)
  519.          justify_right_margin( &w, w.ll->prev, mode.word_wrap == FIXED_WRAP ?
  520.                 find_left_margin( w.ll->prev, mode.word_wrap ) : lm, rm, side );
  521.       p = window->ll->next;
  522.    } else
  523.       p = window->ll;
  524.    if (p != NULL) {
  525.       p_len = find_end( p->line, p->len );
  526.       pp = p->next;
  527.       if (pp != NULL) {
  528.          non_blank = first_non_blank( pp->line, pp->len );
  529.          next_line_len = find_end( pp->line, pp->len ) - non_blank;
  530.          if (!is_line_blank( pp->line, pp->len ) && p_len + next_line_len <= rm) {
  531.             control_t = 1;
  532.             if (mode.inflate_tabs) {
  533.                if (*pp->line == ' '  ||  *pp->line == '\t')
  534.                   ++control_t;
  535.             } else if (*pp->line == ' ')
  536.                ++control_t;
  537.             w.ll = p;
  538.             w.rcol = p_len + 1;
  539.             if (*(p->line+p_len-1) == '.')
  540.                ++w.rcol;
  541.             while (control_t--)
  542.                word_delete( &w );
  543.             remove_spaces( lm );
  544.             un_copy_line( w.ll, &w, TRUE );
  545.          }
  546.          window->file_info->dirty = GLOBAL;
  547.       }
  548.    }
  549. }
  550.  
  551.  
  552. /*
  553.  * Name:    justify_right_margin
  554.  * Purpose: distribute blanks in line to justify right margin
  555.  * Date:    December 30, 1992
  556.  * Passed:  window:   pointer to current window
  557.  *          ll:       current node pointing to current line
  558.  *          lm:       left margin
  559.  *          rm:       right margin
  560.  *          side:     which side to start inserting space? LEFT or RIGHT
  561.  * Notes:   this routine is based on the spread function by
  562.  *           Kernighan and Plauger in _Software Tools_, Addison-Wesly,
  563.  *           Reading, Mass., 1976, ISBN 0-201-03669-X, pp 240-241.
  564.  */
  565. void justify_right_margin( WINDOW *window, line_list_ptr ll, int lm, int rm,
  566.                            int side )
  567. {
  568. int  len;
  569. int  i;
  570. int  word_count;
  571. int  holes;
  572. int  nb;
  573. int  spaces;
  574. text_ptr s;
  575.  
  576.    /*
  577.     * make sure line is longer than the left margin and less than the right.
  578.     */
  579.    len = find_end( ll->line, ll->len );
  580.    if (len <= lm || len >= rm+1)
  581.       return;
  582.  
  583.    /*
  584.     * now, count the number of words in line.
  585.     */
  586.    i = entab_adjust_rcol( ll->line, ll->len, lm );
  587.    s = ll->line + i;
  588.    len -= i;
  589.    word_count = 0;
  590.    while (len > 0) {
  591.       while (len-- > 0  &&  *s++ == ' ');
  592.       if (len == 0)
  593.          break;
  594.       ++word_count;
  595.       while (len-- > 0  &&  *s++ != ' ');
  596.    }
  597.  
  598.    /*
  599.     * can't justify right margin with one word or less.
  600.     */
  601.    if (word_count <= 1)
  602.       return;
  603.  
  604.    holes = word_count - 1;
  605.    copy_line( ll );
  606.    detab_linebuff( );
  607.    remove_spaces( lm );
  608.  
  609.    /*
  610.     * find out how many spaces we need.  if spaces <= 0, then get out.
  611.     */
  612.    i = g_status.line_buff_len - 1;
  613.    spaces = rm - i;
  614.    if (spaces <= 0)
  615.       return;
  616.    g_status.line_buff_len += spaces;
  617.  
  618.    /*
  619.     * this while loop is based on the while loop on page 241 in
  620.     *   _Software Tools_, Kernighan and Plauger.  I added a while loop
  621.     *   to skip extra blanks after a period or other space intentially
  622.     *   inserted into the text.
  623.     */
  624.    while (i < rm) {
  625.       g_status.line_buff[rm] = g_status.line_buff[i];
  626.       if (g_status.line_buff[rm] == ' ') {
  627.  
  628.          /*
  629.           * this while loop copies extra blanks after a period or
  630.           *   blanks otherwise intentially left in the text.
  631.           */
  632.          while (g_status.line_buff[i-1] == ' ')
  633.             g_status.line_buff[--rm] = g_status.line_buff[--i];
  634.  
  635.          nb = side == LEFT ? spaces / holes : (spaces - 1) / holes + 1;
  636.          spaces -= nb;
  637.          --holes;
  638.          while (nb-- > 0)
  639.             g_status.line_buff[--rm] = ' ';
  640.       }
  641.       --i;
  642.       --rm;
  643.    }
  644.    entab_linebuff( );
  645.    un_copy_line( ll, window, window->bottom_line );
  646. }
  647.  
  648.  
  649. /*
  650.  * Name:    remove_spaces
  651.  * Purpose: remove any extra spaces in the text
  652.  * Date:    December 30, 1992
  653.  * Passed:  lm:   left margin
  654.  * Notes:   this routine squeezes out extra space from a previous format.
  655.  *          the line must be placed in the line buffer before calling this
  656.  *            function.
  657.  */
  658. void remove_spaces( int lm )
  659. {
  660. int  period;
  661. int  len;
  662. int  i;
  663. int  c;
  664. char *s;
  665. char *d;
  666.  
  667.    if ((i = len = g_status.line_buff_len) <= lm)
  668.       return;
  669.  
  670.    period = FALSE;
  671.    s = d = g_status.line_buff + lm;
  672.    i -= lm;
  673.    c = (int)*s++;
  674.    while (c == ' ' && i > 0) {
  675.       c = *s++;
  676.       --i;
  677.       --len;
  678.    }
  679.    period = c == '.' ? TRUE : FALSE;
  680.    while (i > 0) {
  681.       *d++ = (char)c;
  682.       c = (int)*s++;
  683.       --i;
  684.       if (c != ' ')
  685.          period =  c == '.' ? TRUE : FALSE;
  686.       else {
  687.          *d++ = (char)c;
  688.          c = (int)*s++;
  689.          --i;
  690.          if (period  &&  c == ' ') {
  691.             *d++ = (char)c;
  692.             period = FALSE;
  693.             if (i > 0)
  694.                ++len;
  695.          }
  696.          while (c == ' '  &&  i > 0) {
  697.             c = (int)*s++;
  698.             --len;
  699.             --i;
  700.          }
  701.       }
  702.    }
  703.    *d = (char)c;
  704.    g_status.line_buff_len = len;
  705. }
  706.  
  707.  
  708. /*
  709.  * Name:    find_word
  710.  * Purpose: find a word on a line
  711.  * Date:    November 29, 1991
  712.  * Passed:  p:          pointer to a line of text
  713.  *          len:        len of line
  714.  *          start_col:  col to start the search
  715.  * Notes:   returns the column of the next word or -1 (ERROR) if no more words
  716.  */
  717. int  find_word( text_ptr p, int len, int start_col )
  718. {
  719. register int rc;
  720. register char c;
  721.  
  722.    if (len <= start_col  ||  len < 0  || start_col < 0)
  723.       return( ERROR );
  724.    p += start_col;
  725.    rc = start_col;
  726.  
  727.    if (mode.inflate_tabs) {
  728.       while (len-- > 0 && ((c = *p++) == ' ' || c == '\t'))
  729.          if (c != '\t')
  730.             ++rc;
  731.          else
  732.             rc += mode.ptab_size - (rc % mode.ptab_size);
  733.    } else
  734.       while (len-- > 0  &&  (c = *p++) == ' ')
  735.          ++rc;
  736.    if (len <= 0)
  737.      rc = ERROR;
  738.    return( rc );
  739. }
  740.  
  741.  
  742. /*
  743.  * Name:    flush_left
  744.  * Purpose: flush line on left margin
  745.  * Date:    November 27, 1991
  746.  * Passed:  window:  pointer to current window
  747.  */
  748. int  flush_left( WINDOW *window )
  749. {
  750. int  len;       /* length of current line */
  751. register int spaces;
  752. char *source;
  753. char *dest;
  754. int  rcol;
  755. int  lm;
  756. register WINDOW *win;          /* put window pointer in a register */
  757.  
  758.    win = window;
  759.    copy_line( win->ll );
  760.    detab_linebuff( );
  761.    lm = mode.left_margin;
  762.    rcol = find_word( (text_ptr)g_status.line_buff, g_status.line_buff_len, 0 );
  763.    if (rcol != ERROR && rcol != lm) {
  764.  
  765.       /*
  766.        * must add spaces to get the indentation correct
  767.        */
  768.       if (rcol < lm) {
  769.          source = g_status.line_buff;
  770.          spaces = lm - rcol;
  771.          dest = source + spaces;
  772.          len = g_status.line_buff_len;
  773.          if (len + spaces > MAX_LINE_LENGTH) {
  774.             /*
  775.              * line would be too long
  776.              */
  777.             error( WARNING, win->bottom_line, ww1 );
  778.             return( ERROR );
  779.          } else {
  780.             load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  781.  
  782.             assert( len >= 0 );
  783.             assert( len < MAX_LINE_LENGTH );
  784.  
  785.             memmove( dest, source, len );
  786.             g_status.line_buff_len += spaces;
  787.             while (spaces--)
  788.                *source++ = ' ';
  789.             win->file_info->dirty = GLOBAL;
  790.          }
  791.  
  792.       /*
  793.        * else delete spaces to get the indentation correct
  794.        */
  795.       } else {
  796.          dest = g_status.line_buff + lm;
  797.          source = g_status.line_buff + rcol;
  798.  
  799.          assert( g_status.line_buff_len - rcol >= 0 );
  800.          assert( g_status.line_buff_len - rcol < MAX_LINE_LENGTH );
  801.  
  802.          memmove( dest, source, g_status.line_buff_len - rcol );
  803.          g_status.line_buff_len -= (rcol - lm);
  804.          win->file_info->dirty = GLOBAL;
  805.       }
  806.       win->ll->dirty = TRUE;
  807.       show_changed_line( win );
  808.    }
  809.    return( OK );
  810. }
  811.  
  812.  
  813. /*
  814.  * Name:    flush_right
  815.  * Purpose: flush line on right margin
  816.  * Date:    November 27, 1991
  817.  * Passed:  window:  pointer to current window
  818.  */
  819. int  flush_right( WINDOW *window )
  820. {
  821. int  len;               /* length of current line */
  822. int  i;
  823. int  spaces;
  824. char *source;
  825. char *dest;
  826. register int rcol;
  827. int  rm;
  828. register WINDOW *win;   /* put window pointer in a register */
  829.  
  830.    win = window;
  831.    copy_line( win->ll );
  832.    detab_linebuff( );
  833.    source = g_status.line_buff;
  834.    len = g_status.line_buff_len;
  835.    if (!is_line_blank( (text_ptr)source, len )) {
  836.       rm = mode.right_margin;
  837.       for (rcol=len-1; rcol>=0 && *(source+rcol) == ' ';)
  838.          rcol--;
  839.       if (rcol != rm) {
  840.  
  841.          /*
  842.           * if rcol is less than right margin then we need to add spaces.
  843.           */
  844.          if (rcol < rm) {
  845.             spaces = rm - rcol;
  846.             dest = source + spaces;
  847.             if (len + spaces > MAX_LINE_LENGTH) {
  848.                /*
  849.                 * line would be too long
  850.                 */
  851.                error( WARNING, win->bottom_line, ww1 );
  852.                return( ERROR );
  853.             } else {
  854.                load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  855.  
  856.                assert( len >= 0 );
  857.                assert( len < MAX_LINE_LENGTH );
  858.  
  859.                memmove( dest, source, len );
  860.                g_status.line_buff_len += spaces;
  861.                while (spaces--)
  862.                   *source++ = ' ';
  863.                win->file_info->dirty = GLOBAL;
  864.             }
  865.  
  866.          /*
  867.           * if rcol is greater than right margin then we need to sub spaces.
  868.           */
  869.          } else {
  870.             load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  871.             rcol = rcol - rm;
  872.             i = first_non_blank( (text_ptr)source, len );
  873.             if (rcol > i)
  874.                rcol = i;
  875.             dest = source + rcol;
  876.  
  877.             assert( len - rcol >= 0 );
  878.             assert( len - rcol < MAX_LINE_LENGTH );
  879.  
  880.             memmove( source, dest, len - rcol );
  881.             g_status.line_buff_len -= (rcol - rm);
  882.             win->file_info->dirty = GLOBAL;
  883.          }
  884.          win->ll->dirty = TRUE;
  885.          show_changed_line( win );
  886.       }
  887.    }
  888.    return( OK );
  889. }
  890.  
  891.  
  892. /*
  893.  * Name:    flush_center
  894.  * Purpose: flush line in center of margins
  895.  * Date:    November 27, 1991
  896.  * Passed:  window:  pointer to current window
  897.  */
  898. int  flush_center( WINDOW *window )
  899. {
  900. int  len;               /* length of current line */
  901. char *source;           /* temp line buffer pointers */
  902. char *dest;
  903. int  rm;
  904. int  lm;
  905. register int spaces;    /* center of text on current line */
  906. int  center;            /* center of current margins */
  907. int  first;             /* column of first char on line */
  908. int  last;              /* column of last char on line */
  909. register WINDOW *win;   /* put window pointer in a register */
  910.  
  911.    win = window;
  912.    copy_line( win->ll );
  913.    detab_linebuff( );
  914.    source = g_status.line_buff;
  915.    len = g_status.line_buff_len;
  916.    if (!is_line_blank( (text_ptr)source, len )) {
  917.       rm = mode.right_margin;
  918.       lm = mode.left_margin;
  919.       center = (rm + lm) / 2;
  920.       first = first_non_blank( (text_ptr)source, len );
  921.       for (last=len-1; last>=0 && *(source+last) == ' ';)
  922.          last--;
  923.       spaces = last + first - 1;
  924.       spaces = (spaces / 2) + (spaces & 1);
  925.       if (spaces != center) {
  926.  
  927.          /*
  928.           * if spaces is less than center margin then we need to add spaces.
  929.           */
  930.          if (spaces < center) {
  931.             spaces = center - spaces;
  932.             dest = source + spaces;
  933.             if (len + spaces > MAX_LINE_LENGTH) {
  934.                /*
  935.                 * line would be too long
  936.                 */
  937.                error( WARNING, win->bottom_line, ww1 );
  938.                return( ERROR );
  939.             } else {
  940.                load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  941.  
  942.                assert( len >= 0 );
  943.                assert( len < MAX_LINE_LENGTH );
  944.  
  945.                memmove( dest, source, len );
  946.                g_status.line_buff_len += spaces;
  947.                while (spaces--)
  948.                   *source++ = ' ';
  949.                win->file_info->dirty = GLOBAL;
  950.             }
  951.  
  952.          /*
  953.           * if spaces is greater than center margin then we need to sub spaces.
  954.           */
  955.          } else {
  956.             load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  957.             spaces = spaces - center;
  958.             if (spaces > first)
  959.                spaces = first;
  960.             dest = source + spaces;
  961.  
  962.             assert( len - spaces >= 0 );
  963.             assert( len - spaces < MAX_LINE_LENGTH );
  964.  
  965.             memmove( source, dest, len - spaces );
  966.             g_status.line_buff_len -= spaces;
  967.             win->file_info->dirty = GLOBAL;
  968.          }
  969.          win->ll->dirty = TRUE;
  970.          show_changed_line( win );
  971.       }
  972.    }
  973.    return( OK );
  974. }
  975.