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