home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
editors
/
tde150.arj
/
WORDWRAP.C
< prev
Wrap
C/C++ Source or Header
|
1992-04-01
|
20KB
|
631 lines
/*
* This module contains the word wrap and format paragraph functions.
*
* 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
*
* 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: word_wrap
* Purpose: make sure lines don't get longer than right margin
* Date: November 27, 1991
* Passed: window: information allowing access to the 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 */
int line; /* line on screen to save and show prompt */
text_ptr p; /* line above wrapped line */
int rcol;
int lm;
int rm;
register WINDOW *win; /* put window pointer in a register */
win = window;
/*
* set up a few local variables.
*/
c = g_status.key_pressed;
line = win->bottom_line;
rcol = win->rcol;
copy_line( win->cursor, line );
/*
* 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.
*/
win->cursor = cpf( win->cursor );
p = cpb( win->cursor );
p = find_prev( p );
lm = mode.left_margin;
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 = linelen( g_status.line_buff );
if (rcol > rm+1 && c != ' ') {
/*
* if this is the first line in a paragraph then set left margin
* to paragraph margin.
*/
if ((*p == CONTROL_Z || p == NULL || is_line_blank( p )) &&
first_non_blank( g_status.line_buff ) > rm)
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 );
/*
* 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 = linelen( win->cursor );
if (len < rm+1)
combine_wrap_spill( win, len, rm, 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, rm, 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, rm, 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 );
win->rcol = lm + rcol - i;
check_virtual_col( win, win->rcol, win->rcol );
len = linelen( win->cursor );
if (len < rm+1)
combine_wrap_spill( win, len, rm, 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, rm, TRUE );
}
}
}
/*
* Name: format_paragraph
* Purpose: format paragraph using left, right, and paragraph margins.
* Date: November 27, 1991
* Passed: window: information allowing access to the current window
*/
void 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 */
int line; /* line on screen to save and show prompt */
int control_t; /* number of times to call WordDelete */
int non_blank;
text_ptr p; /* scratch text pointers */
text_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 */
un_copy_line( window->cursor, window, TRUE );
if (!is_line_blank( window->cursor )) {
old_ww = mode.word_wrap;
mode.word_wrap = TRUE;
window->cursor = cpf( window->cursor );
dup_window_info( &w, window );
line = window->bottom_line;
/*
* find the beginning of the paragraph.
*/
p = w.cursor = cpb( w.cursor );
p = find_prev( p );
if (g_status.command == FormatParagraph) {
while (p != NULL && *p != CONTROL_Z && !is_line_blank( cpf( p ) )) {
--w.rline;
w.cursor = find_prev( w.cursor );
p = find_prev( p );
}
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 || *p == CONTROL_Z || is_line_blank( p ))
pm = mode.parg_margin;
else
pm = mode.left_margin;
}
g_status.command = WordWrap;
eop = FALSE;
lm = mode.left_margin;
rm = mode.right_margin;
p = w.cursor = cpf( w.cursor );
/*
* do the paragraph
*/
for (first_line=TRUE; *p != CONTROL_Z && p != NULL &&
!is_line_blank( p ) && eop == FALSE;) {
/*
* find out what margin to use
*/
if (first_line) {
margin = pm;
first_line = FALSE;
} else
margin = lm;
/*
* line up the margin
*/
copy_line( w.cursor, line );
rcol = find_word( p, 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;
memmove( dest, source, linelen( source )+2 );
while (spaces--)
*source++ = ' ';
} else {
w.rcol = margin;
word_delete( &w );
un_copy_line( p, &w, TRUE );
}
}
/*
* now make sure rest of line is formatted
*/
source = g_status.line_buff;
len = linelen( source );
for (; len < rm+1 && eop == FALSE;) {
pp = find_next( p );
if (is_line_blank( pp ))
eop = TRUE;
else {
non_blank = first_non_blank( pp );
control_t = 1;
if (*pp == ' ')
++control_t;
w.cursor = p;
w.rcol = len + 1;
if (*(p+len-1) == '.')
++w.rcol;
while (control_t--)
word_delete( &w );
un_copy_line( p, &w, TRUE );
copy_line( p, line );
len = linelen( source );
}
}
if (len <= rm+1) {
un_copy_line( p, &w, TRUE );
p = find_next( p );
if (is_line_blank( p ))
eop = TRUE;
else {
w.cursor = find_next( w.cursor );
w.rline++;
}
} else {
w.rcol = rm;
g_status.key_pressed = *(w.cursor + rm);
rline = w.rline;
word_wrap( &w );
if (rline == w.rline) {
w.cursor = find_next( w.cursor);
++w.rline;
}
}
g_status.copied = FALSE;
p = w.cursor = cpf( w.cursor );
}
mode.word_wrap = old_ww;
g_status.copied = FALSE;
w.file_info->dirty = GLOBAL;
}
}
/*
* Name: combine_wrap_spill
* Purpose: combine word wrap lines so we don't push each word onto a
* separate line.
* Date: November 27, 1991
* Passed: window: information allowing access to the current window
* wrap_col: col to combine next line
* rm: right margin
* new_line: boolean, should we insert a new line?
*/
void combine_wrap_spill( WINDOW *window, int wrap_col, int rm, int new_line )
{
text_ptr p; /* line we wrapped */
text_ptr pp; /* pointer to next line after wrapped line */
int p_len; /* length of line we just word wrapped */
int non_blank; /* first non-blank column on next line */
int control_t; /* number of times to call word_delete */
WINDOW w; /* scratch window */
dup_window_info( &w, window );
g_status.command = WordWrap;
w.rcol = wrap_col;
if (new_line) {
insert_newline( &w );
p = find_next( window->cursor );
} else
p = cpf( window->cursor );
if (p != NULL) {
p_len = linelen( p );
pp = find_next( p );
if (pp != NULL) {
non_blank = first_non_blank( pp );
if (!is_line_blank( pp ) && p_len + linelen( pp + non_blank ) <= rm) {
control_t = 1;
if (*pp == ' ')
++control_t;
w.cursor = p;
w.rcol = p_len + 1;
if (*(p+p_len-1) == '.')
++w.rcol;
while (control_t--)
word_delete( &w );
un_copy_line( w.cursor, &w, TRUE );
}
window->file_info->dirty = GLOBAL;
}
}
}
/*
* Name: find_word
* Purpose: find a word on a line
* Date: November 29, 1991
* Passed: p: information allowing access to the current window
* start_col: col to start the search
* Notes: returns the column of the next word or -1 if no more words
*/
int find_word( text_ptr p, int start_col )
{
register int rc;
register char c;
p = cpf( p );
p += start_col;
rc = start_col;
while ((c = *p++) == ' ')
++rc;
if (c == '\n' || c == CONTROL_Z)
rc = ERROR;
return( rc );
}
/*
* Name: left_justify
* Purpose: left justify a line according to left margin
* Date: November 27, 1991
* Passed: window: information allowing access to the current window
*/
void left_justify( WINDOW *window )
{
int len; /* length of current line */
register int spaces;
char *source;
char *dest;
int rcol;
int lm;
register WINDOW *win; /* put window pointer in a register */
win = window;
copy_line( win->cursor, win->bottom_line );
lm = mode.left_margin;
rcol = find_word( g_status.line_buff, 0 );
if (rcol != -1 && rcol != lm) {
/*
* must add spaces to get the indentation correct
*/
if (rcol < lm) {
source = g_status.line_buff;
spaces = lm - rcol;
dest = source + spaces;
len = linelen( source ) + 2;
if (len + spaces > MAX_LINE_LENGTH) {
error( WARNING, win->bottom_line, "line would be too long." );
return;
} else {
load_undo_buffer( win->cursor );
memmove( dest, source, len );
while (spaces--)
*source++ = ' ';
win->file_info->dirty = GLOBAL;
}
/*
* else delete spaces to get the indentation correct
*/
} else {
dest = g_status.line_buff + lm;
source = g_status.line_buff + rcol;
memmove( dest, source, linelen( source ) + 2 );
win->file_info->dirty = GLOBAL;
}
show_changed_line( win );
}
}
/*
* Name: right_justify
* Purpose: right justify a line according to right margin
* Date: November 27, 1991
* Passed: window: information allowing access to the current window
*/
void right_justify( WINDOW *window )
{
int len; /* length of current line */
int i;
int spaces;
char *source;
char *dest;
register int rcol;
int rm;
register WINDOW *win; /* put window pointer in a register */
win = window;
copy_line( win->cursor, win->bottom_line );
source = g_status.line_buff;
if (!is_line_blank( source )) {
rm = mode.right_margin;
len = linelen( source );
for (rcol=len-1; rcol>=0 && *(source+rcol) == ' ';)
rcol--;
if (rcol != rm) {
/*
* if rcol is less than right margin then we need to add spaces.
*/
if (rcol < rm) {
spaces = rm - rcol;
dest = source + spaces;
len = linelen( source ) + 2;
if (len + spaces > MAX_LINE_LENGTH) {
error( WARNING, win->bottom_line, "line would be too long." );
return;
} else {
load_undo_buffer( win->cursor );
memmove( dest, source, len );
while (spaces--)
*source++ = ' ';
win->file_info->dirty = GLOBAL;
}
/*
* if rcol is greater than right margin then we need to sub spaces.
*/
} else {
load_undo_buffer( win->cursor );
rcol = rcol - rm;
i = first_non_blank( source );
if (rcol > i)
rcol = i;
dest = source + rcol;
memmove( source, dest, linelen( dest ) + 2 );
win->file_info->dirty = GLOBAL;
}
show_changed_line( win );
}
}
}
/*
* Name: center_justify
* Purpose: center a line according to left and right margin
* Date: November 27, 1991
* Passed: window: information allowing access to the current window
*/
void center_justify( WINDOW *window )
{
int len; /* length of current line */
char *source; /* temp line buffer pointers */
char *dest;
int rm;
int lm;
register int spaces; /* center of text on current line */
int center; /* center of current margins */
int first; /* column of first char on line */
int last; /* column of last char on line */
register WINDOW *win; /* put window pointer in a register */
win = window;
copy_line( win->cursor, win->bottom_line );
source = g_status.line_buff;
if (!is_line_blank( source )) {
rm = mode.right_margin;
lm = mode.left_margin;
center = (rm + lm) / 2;
first = first_non_blank( source );
len = linelen( source );
for (last=len-1; last>=0 && *(source+last) == ' ';)
last--;
spaces = last + first - 1;
spaces = (spaces / 2) + (spaces & 1);
if (spaces != center) {
/*
* if spaces is less than center margin then we need to add spaces.
*/
if (spaces < center) {
spaces = center - spaces;
dest = source + spaces;
len = linelen( source ) + 2;
if (len + spaces > MAX_LINE_LENGTH) {
error( WARNING, win->bottom_line, "line would be too long." );
return;
} else {
load_undo_buffer( win->cursor );
memmove( dest, source, len );
while (spaces--)
*source++ = ' ';
win->file_info->dirty = GLOBAL;
}
/*
* if spaces is greater than center margin then we need to sub spaces.
*/
} else {
load_undo_buffer( win->cursor );
spaces = spaces - center;
if (spaces > first)
spaces = first;
dest = source + spaces;
memmove( source, dest, linelen( dest ) + 2 );
win->file_info->dirty = GLOBAL;
}
show_changed_line( win );
}
}
}