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