⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wordwrap.c

📁 c 语言学习220例
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * This module contains the word wrap and format paragraph functions.  The
 *  right_justify( ) function is based on the spread function in _Software
 *  Tools_ by Brian Kernighan and P J Plauger.  My version of the spread
 *  function handles lines with extra blanks in the text, e.g. two blanks
 *  after periods.  All of the other word processing routines are original
 *  and written by me, Frank, and are not guaranteed to work as designed.
 *
 * See:
 *
 *   Brian W. Kernighan and P. J. Plauger, _Software Tools_, Addison-
 *    Wesly, Reading, Mass., 1976, Section 7.7, "Right Margin Justification",
 *    pp 239-242.  ISBN 0-201-03669-X.
 *
 * Note: right margin justification was added in TDE 2.2.
 *
 * New editor name:  TDE, the Thomson-Davis Editor.
 * Author:           Frank Davis
 * Date:             June 5, 1991, version 1.0
 * Date:             July 29, 1991, version 1.1
 * Date:             October 5, 1991, version 1.2
 * Date:             January 20, 1992, version 1.3
 * Date:             February 17, 1992, version 1.4
 * Date:             April 1, 1992, version 1.5
 * Date:             June 5, 1992, version 2.0
 * Date:             October 31, 1992, version 2.1
 * Date:             April 1, 1993, version 2.2
 * Date:             June 5, 1993, version 3.0
 * Date:             August 29, 1993, version 3.1
 *
 * This code is released into the public domain, Frank Davis.
 * You may distribute it freely.
 */

#include "tdestr.h"     /* global variables definitions */
#include "common.h"     /* external global variable declarations */
#include "define.h"
#include "tdefunc.h"


/*
 * Name:    find_left_margin
 * Purpose: find left margin depending on word wrap mode
 * Date:    June 5, 1992
 * Passed:  ll:         node pointer to current line
 *          wrap_mode:  current word wrap mode
 * Notes:   the algorithm used to figure the indent column was yanked out
 *           of the insert_newline( ) function and was made into a more
 *           general algorithm for figuring the left margin irregardless
 *           of word wrap or indent mode.  when in the DYNAMIC_WRAP mode,
 *           the user don't have to keep changing the left margin when
 *           special indentation is needed.
 */
int  find_left_margin( line_list_ptr ll, int wrap_mode )
{
register int lm;
int  len;
text_ptr source;

   if (wrap_mode == FIXED_WRAP) {
      /*
       * for FIXED_WRAP mode, the left and paragraph margins are determined
       *   from the master mode structure.
       */
      if (g_status.copied) {
         source = (text_ptr)g_status.line_buff;
         len    = g_status.line_buff_len;
      } else {
         if (ll->prev != NULL) {
            source = ll->prev->line;
            len    = ll->prev->len;
         } else {
            source = NULL;
            len    = 0;
         }
      }
      if (source == NULL)
         lm = mode.parg_margin;
      else if (find_end( source, len ) == 0)
         lm = mode.parg_margin;
      else
         lm = mode.left_margin;
   } else {
      /*
       * for Indent and DYNAMIC_WRAP modes, the left margin is determined
       *  from the first non blank line above the cursor.
       */
      if (g_status.copied == TRUE) {
         source = (text_ptr)g_status.line_buff;
         len    = g_status.line_buff_len;
      } else {
         source = ll->line;
         len    = ll->len;
      }
      lm = first_non_blank( source, len );
      if (is_line_blank( source, len ) && ll->prev != NULL) {
         for (ll=ll->prev; ll != NULL; ll=ll->prev) {
            lm = first_non_blank( ll->line, ll->len );
            if (!is_line_blank( ll->line, ll->len ))
               break;
         }
      }
   }
   return( lm );
}


/*
 * Name:    word_wrap
 * Purpose: make sure lines don't get longer than right margin
 * Date:    November 27, 1991
 * Passed:  window:  pointer to current window
 * Notes:   rcol, lm, rm, pm all start counting at zero.
 *          len (line length) starts counting at 1.
 *
 *          when we compare margins and line lengths, we either have to
 *          add one to the margins or subtract one from the len.  I add
 *          one to the margins.
 */
void word_wrap( WINDOW *window )
{
int  c;                 /* character the user just entered. */
register int len;       /* length of current line */
int  i;                 /* padding spaces required */
line_list_ptr p;        /* line above wrapped line */
int  rcol;
int  lm;
int  rm;
int  side;
register WINDOW *win;          /* put window pointer in a register */

   win = window;

   /*
    * set up a few local variables.
    */
   c = g_status.key_pressed;
   rcol = win->rcol;
   copy_line( win->ll );
   detab_linebuff( );

   /*
    * always start the right margin justification on the right side
    *  at the beginning of paragraphs.  then, alternate with left margin.
    */
   side = 1;
   p = win->ll->prev;
   while (p != NULL  &&  !is_line_blank( p->line, p->len )) {
      ++side;
      p = p->prev;
   }
   side = (side & 1) ? RIGHT : LEFT;


   /*
    * when we wrap, we need know where the left margin is.
    * let's look at the line above to see if this is the first line
    * in a paragraph.
    */
   p = win->ll->prev;

   lm = find_left_margin( win->ll, mode.word_wrap );
   rm = mode.right_margin;

   /*
    * there two ways that words are pushed onto next line.
    *  1. if the word being typed goes over the right margin
    *  2. typing a word in the middle of the line pushes words at end of
    *     line to next line
    *
    * if the user enters spaces past the right margin then we don't
    *  word wrap spaces.
    */
   len = g_status.line_buff_len;
   if (rcol > rm+1 && c != ' ') {

      /*
       * if this is the first line in a paragraph then set left margin
       *  to paragraph margin.
       */
      if ((p == NULL || is_line_blank( p->line, p->len )) &&
           first_non_blank( (text_ptr)g_status.line_buff,
                 g_status.line_buff_len ) > rm && mode.word_wrap == FIXED_WRAP)
         lm = mode.parg_margin;

      /*
       * simple word wrap.  the cursor goes past the right margin.
       *  find the beginning of the word and put it on a new line.
       *
       * Special case - if the word begins at the left margin then
       *  don't wrap it.
       */
      for (i=rcol-1; i > lm  &&  g_status.line_buff[i] != ' '; )
         i--;
      if (i > lm) {
         i++;
         win->rcol = i;
         g_status.command = WordWrap;
         insert_newline( win );
         if (mode.right_justify == TRUE)
            justify_right_margin( win, win->ll->prev,
                 mode.word_wrap == FIXED_WRAP ? find_left_margin( win->ll->prev,
                 mode.word_wrap ) : lm, rm, side );

         /*
          * find out where to place the cursor on the new line.
          */
         win->rcol = lm + rcol - i;
         check_virtual_col( win, win->rcol, win->rcol );

         /*
          * we just wrapped the word at the eol.  now, let's see if
          *  we can combine it with the line below.  since just added
          *  a line, set new_line to false - don't add another line.
          */

         len = find_end( win->ll->line, win->ll->len );
         if (len < rm+1)
            combine_wrap_spill( win, len, lm, rm, side, FALSE );
      }
   } else if (len > rm+1) {

      /*
       * this is the second word wrap case.  we are pushing words onto
       * next line.  we need to now what character is in the right margin.
       *
       * 1) if the character is not a space, then we need to search backwards
       *    to find the start of the word that is on the right margin.
       * 2) if the character is a space, then we need to search forward to
       *    find the word that is over the right margin.
       */

      /*
       * don't wrap spaces past right margin
       */
      if (c == ' ' && rcol > rm) {
         for (i=rcol; i<len && g_status.line_buff[i] == ' ';)
            i++;

         /*
          * if i == len then all that's left on line is blanks - don't wrap.
          */
         if (i < len)
            combine_wrap_spill( win, i, lm, rm, side, TRUE );

      } else if (g_status.line_buff[rm+1] != ' ') {

         /*
          * search backwards for the word to put on next line.
          */
         for (i=rm+1; i > lm  &&  g_status.line_buff[i] != ' '; )
            i--;

         /*
          * if we search all the way back to left margin then test for
          * a special case - see the matching else for more info.
          */
         if (i > lm) {
            i++;

            /*
             * if i > rcol then cursor stays on same line.
             */
            if (i > rcol) {
               combine_wrap_spill( win, i, lm, rm, side, TRUE );

            /*
             * split the line at or behind the cursor.  almost the
             *  same as when the cursor goes over the right margin.
             */
            } else if (i <= rcol) {
               win->rcol = i;
               g_status.command = WordWrap;
               insert_newline( win );
               if (mode.right_justify == TRUE)
                  justify_right_margin( win, win->ll->prev,
                   mode.word_wrap == FIXED_WRAP ?
                   find_left_margin( win->ll->prev, mode.word_wrap ) : lm,
                   rm, side );
               win->rcol = lm + rcol - i;
               check_virtual_col( win, win->rcol, win->rcol );
               len = find_end( win->ll->line, win->ll->len );
               if (len < rm+1)
                  combine_wrap_spill( win, len, lm, rm, side, FALSE );
            }
         }

         /*
          * if the user changed margins or for some reason there's a long
          *  text line, let's see if there are any words past the right
          *  margin.  if we get to this else, we know the current word
          *  begins at least at the left margin.
          *
          * now search forwards for a break
          */
      } else {

         /*
          * go to the right margin and see if there are any words past
          *  right margin.
          */
         for (i=rm+1; i<len && g_status.line_buff[i] == ' '; )
            i++;

         /*
          * we either found a space or the eol.  test for eol.
          * if i == len then this is one big word - don't wrap it.
          */
         if (i != len)
            combine_wrap_spill( win, i, lm, rm, side, TRUE );
      }
   }
}


/*
 * Name:    format_paragraph
 * Purpose: format paragraph using left, right, and paragraph margins.
 * Date:    November 27, 1991
 * Passed:  window:  pointer to current window
 */
int  format_paragraph( WINDOW *window )
{
register int len;       /* length of current line */
int  first_line;        /* boolean, first line formatted? */
int  spaces;            /* no. of spaces to add */
line_list_ptr p;        /* scratch pointers */
line_list_ptr pp;
char *source;           /* scratch line buffer pointers */
char *dest;
int  rcol;              /* scratch cols and margins */
int  lm;
int  rm;
int  pm;
int  margin;
int  eop;               /* boolean, (e)nd (o)f (p)aragraph? */
int  old_ww;            /* save state of word wrap flag */
long rline;
WINDOW w;               /* scratch window */

   if (window->ll->len == EOF)
      return( ERROR );
   entab_linebuff( );
   if (un_copy_line( window->ll, window, TRUE ) == ERROR)
      return( ERROR );
   if (!is_line_blank( window->ll->line, window->ll->len )) {
      old_ww = mode.word_wrap;
      if (old_ww == NO_WRAP)
         mode.word_wrap = FIXED_WRAP;
      dup_window_info( &w, window );
      g_status.screen_display = FALSE;

      /*
       * find the beginning of the paragraph.
       */
      p = w.ll->prev;
      if (g_status.command == FormatParagraph) {
         while (p != NULL &&  !is_line_blank( p->line, p->len )) {
            --w.rline;
            w.ll = w.ll->prev;
            p = p->prev;
         }
         pm = mode.parg_margin;

      /*
       * if format text, don't find the beginning of the paragraph.
       *  but we need to know if this is the first line in a paragraph.
       */
      } else if (g_status.command == FormatText) {
         if (p == NULL || is_line_blank( p->line, p->len ))
            pm = mode.parg_margin;
         else
            pm = mode.left_margin;
      } else
         pm = mode.left_margin;

      g_status.command = WordWrap;
      p = w.ll;
      if (mode.word_wrap == FIXED_WRAP)
         lm = mode.left_margin;
      else
         lm = pm = find_left_margin( p, mode.word_wrap );
      rm = mode.right_margin;
      eop = FALSE;

      /*
       * do the paragraph
       */
      for (first_line=TRUE; p != NULL  &&  !is_line_blank( p->line, p->len ) &&
                            eop == FALSE  &&  !g_status.control_break;) {

         /*
          * find out what margin to use
          */
         if (first_line) {
            margin = pm;
            first_line = FALSE;
         } else
            margin = lm;

         /*
          * line up the margin
          */
         w.ll->dirty = TRUE;
         copy_line( w.ll );
         detab_linebuff( );
         remove_spaces( 0 );
         rcol = find_word( (text_ptr)g_status.line_buff,
                                     g_status.line_buff_len, 0 );
         if (rcol != ERROR && rcol != margin) {

            /*
             * must add spaces to get the indentation right
             */
            if (rcol < margin) {
               source = g_status.line_buff;
               spaces = margin - rcol;
               dest = source + spaces;

               assert( g_status.line_buff_len >= 0 );
               assert( g_status.line_buff_len < MAX_LINE_LENGTH );

               memmove( dest, source, g_status.line_buff_len );
               g_status.line_buff_len += spaces;
               while (spaces--)
                  *source++ = ' ';
            } else {
               w.rcol = margin;
               word_delete( &w );
               entab_linebuff( );
               un_copy_line( p, &w, TRUE );
               copy_line( w.ll );
               detab_linebuff( );
               remove_spaces( margin );
            }
         }

         /*
          * now make sure rest of line is formatted
          */

         source = g_status.line_buff;
         len = g_status.line_buff_len;
         for (; len < rm+1 && eop == FALSE;) {
            pp = p->next;
            if (is_line_blank( pp->line, pp->len ))
               eop = TRUE;
            else {
               w.ll = p;
               w.rcol = len + 1;
               if (*(p->line+len-1) == '.')
                  ++w.rcol;
               word_delete( &w );
               entab_linebuff( );
               un_copy_line( p, &w, TRUE );
               copy_line( p );
               detab_linebuff( );
               remove_spaces( margin );
               len = g_status.line_buff_len;
            }
         }
         if (len <= rm+1) {
            entab_linebuff( );
            un_copy_line( p, &w, TRUE );
            p = p->next;
            if (is_line_blank( p->line, p->len ))
               eop = TRUE;
            else {
               w.ll = w.ll->next;
               w.rline++;
            }
         } else {
            w.rcol = rm;
            g_status.key_pressed = *(w.ll->line + rm);
            rline = w.rline;
            word_wrap( &w );
            if (rline == w.rline) {
               w.ll = w.ll->next;
               ++w.rline;
            }
         }
         g_status.copied = FALSE;
         p = w.ll;
      }
      mode.word_wrap = old_ww;
      g_status.copied = FALSE;
      w.file_info->dirty = GLOBAL;
      g_status.screen_display = TRUE;
   }
   return( OK );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -