home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-387-Vol-3of3.iso
/
x
/
xvisrc.zoo
/
misccmds.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-07-28
|
11KB
|
521 lines
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)misccmds.c 2.2 (Chris & John Downey) 8/28/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
misccmds.c
* module function:
Miscellaneous functions.
This module will probably get hacked later and split
up more sensibly.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
/*
* Add a blank line above or below the current line.
* Returns TRUE for success, FALSE for failure to get memory.
*
* The single boolean parameter tells us whether to split the
* current line at the cursor position, or just to open a new
* line leaving the current one intact.
*/
bool_t
openfwd(split_line)
bool_t split_line;
{
Line *l; /* pointer to newly allocated line */
register Posn *oldposn;
register Line *oldline;
register char *otext;
oldposn = curwin->w_cursor;
oldline = oldposn->p_line;
otext = oldline->l_text;
/*
* First find space for new line.
*
* By asking for as much space as the prior line had we make sure
* that we'll have enough space for any auto-indenting.
*/
l = newline(strlen(otext) + SLOP);
if (l == NULL)
return(FALSE);
/*
* Link the new line into the list.
*/
repllines(curwin, oldline->l_next, 0L, l);
/*
* Do auto-indent.
*/
if (Pb(P_autoindent)) {
*l->l_text = '\0';
indentchars = set_indent(l, get_indent(oldline));
} else {
indentchars = 0;
}
/*
* If we're in insert mode, we need to move the remainder of the
* current line onto the new line. Otherwise the new line is left
* blank.
*/
if (split_line) {
char *s;
s = otext + oldposn->p_index;
replchars(curwin, l, indentchars, 0, s);
replchars(curwin, oldline, oldposn->p_index, strlen(s), "");
}
/*
* Move cursor to the new line.
*/
move_cursor(curwin, l, indentchars);
move_window_to_cursor(curwin);
cursupdate(curwin);
update_buffer(curbuf);
return(TRUE);
}
/*
* Add a blank line above the current line.
* Returns TRUE for success, FALSE for failure to get memory.
*/
bool_t
openbwd()
{
Line *l;
register Line *oldline;
register char *otext;
oldline = curwin->w_cursor->p_line;
otext = oldline->l_text;
/*
* First find space for new line.
*/
l = newline(strlen(otext) + SLOP);
if (l == NULL)
return(FALSE);
/*
* Link the new line into the list.
*/
repllines(curwin, oldline, 0L, l);
/*
* Do auto-indent.
*/
if (Pb(P_autoindent)) {
*l->l_text = '\0';
indentchars = set_indent(l, get_indent(oldline));
} else {
indentchars = 0;
}
/*
* Ensure the cursor is pointing at the right line.
*/
move_cursor(curwin, l, indentchars);
move_window_to_cursor(curwin);
cursupdate(curwin);
update_buffer(curbuf);
return(TRUE);
}
/*
* Count the number of lines between the two given lines.
* If the two given lines are the same, the return value
* is 1, not 0; i.e. the count is inclusive.
*
* Note that this function has been changed to give the
* correct number of lines, even if they are ordered wrongly.
* This change is backwards-compatible with the old version.
*/
long
cntllines(pbegin, pend)
Line *pbegin;
register Line *pend;
{
register Line *lp;
register long lnum;
bool_t swapped = FALSE;
/*
* Ensure correct ordering.
*/
if (later(pbegin, pend)) {
lp = pbegin;
pbegin = pend;
pend = lp;
swapped = TRUE;
}
for (lnum = 1, lp = pbegin; lp != pend; lp = lp->l_next) {
lnum++;
}
if (swapped)
lnum = - lnum;
return(lnum);
}
/*
* plines(lp) - return the number of physical screen lines taken by line 'lp'.
*/
long
plines(win, lp)
Xviwin *win;
Line *lp;
{
register long col;
register char *s;
s = lp->l_text;
if (*s == '\0') /* empty line */
return(1);
/*
* If list mode is on, then the '$' at the end of
* the line takes up one extra column.
*/
col = Pb(P_list) ? 1 : 0;
if (Pb(P_number)) {
col += NUM_SIZE;
}
for ( ; *s != '\0'; s++) {
col += vischar(*s, (char **) NULL, (int) col);
}
{
register int row;
register int columns;
columns = win->w_ncols;
for (row = 1; col > columns; ) {
row++;
col -= columns;
}
return row;
}
}
/*
* Count the number of physical lines between the two given lines.
*
* This routine is like cntllines(), except that:
* it counts physical rather than logical lines
* it always returns the absolute number of physical lines
* it is non-inclusive
* if the physical line count for a group of lines is greater
* than or equal to rows * 2, we just return rows * 2; we assume
* the caller isn't interested in the exact number.
*/
long
cntplines(win, pbegin, pend)
Xviwin *win;
Line *pbegin;
register Line *pend;
{
register Line *lp;
register long physlines;
unsigned toomuch;
/*
* Ensure correct ordering.
*/
if (later(pbegin, pend)) {
lp = pbegin;
pbegin = pend;
pend = lp;
}
toomuch = win->w_nrows * 2;
for (physlines = 0, lp = pbegin; lp != pend; lp = lp->l_next) {
physlines += plines(win, lp);
if (physlines >= toomuch)
break;
}
return(physlines);
}
/*
* gotoline(buffer, n) - return a pointer to line 'n' in the given buffer
*
* Returns the first line of the file if n is 0.
* Returns the last line of the file if n is beyond the end of the file.
*/
Line *
gotoline(b, n)
Buffer *b;
register unsigned long n;
{
if (n == 0) {
return(b->b_file);
} else {
register Line *lp;
for (lp = b->b_file; --n > 0 && lp->l_next != b->b_lastline;
lp = lp->l_next) {
;
}
return(lp);
}
}
int
get_indent(lp)
register Line *lp;
{
register char *text;
register int indent;
register int ts = Pn(P_tabstop); /* synonym for efficiency */
if (lp == NULL || (text = lp->l_text) == NULL) {
show_error(curwin, "Internal error: get_indent(NULL)");
return 0;
}
for (indent = 0; *text != '\0' && (*text == ' ' || *text == '\t');
text++) {
indent += *text == ' ' ? 1 : ts - indent % ts;
}
return indent;
}
/*
* Set number of columns of leading whitespace on line, regardless of
* what was there before, & return number of characters (not columns)
* used.
*/
int
set_indent(lp, indent)
Line *lp;
register int indent;
{
register char *cp; /* temp char pointer for loops */
register int ntabs; /* number of tabs to use */
unsigned nnew; /* no of chars used in old line */
unsigned nold; /* no of chars used in new version */
char *newstr; /* allocated string for new indent */
if (lp == NULL || lp->l_text == NULL) {
show_error(curwin, "Internal error: set_indent(0)");
return(0);
}
/*
* Find out how many tabs we need, & how many spaces.
*/
for (ntabs = 0; indent >= Pn(P_tabstop); ntabs++)
indent -= Pn(P_tabstop);
/*
* Find out how many characters were used for initial
* whitespace in the current (old) line.
*/
for (cp = lp->l_text; *cp == ' ' || *cp == '\t'; cp++) {
;
}
nold = cp - lp->l_text;
/*
* "nnew" is the number of characters we will use
* for indentation in the new version of the line.
*/
nnew = ntabs + indent;
/*
* Get some space, and place into it the string of tabs
* and spaces which will form the new indentation.
* If no space available, return nold as we have not
* changed the line; this is the correct action.
*/
newstr = alloc((unsigned) nnew + 1);
if (newstr == NULL)
return(nold);
cp = newstr;
while (ntabs-- > 0)
*cp++ = '\t';
while (indent-- > 0)
*cp++ = ' ';
*cp = '\0';
/*
* Finally, replace the old with the new.
*/
replchars(curwin, lp, 0, (int) nold, newstr);
free(newstr);
return(nnew);
}
/*
* tabinout(inout, start, finish)
*
* "inout" is either '<' or '>' to indicate left or right shift.
*/
void
tabinout(inout, start, finish)
int inout;
Line *start;
Line *finish;
{
Line *lp;
long nlines = 0;
if (!start_command(curwin)) {
return;
}
finish = finish->l_next;
for (lp = start; lp != finish; lp = lp->l_next) {
register char *p;
/*
* Find out whether it's a blank line (either
* empty or containing only spaces & tabs).
* If so, just remove all whitespace from it.
*/
for (p = lp->l_text; *p && (*p == '\t' || *p == ' '); p++)
;
if (*p == '\0') {
if (p > lp->l_text) {
replchars(curwin, lp, 0, p - lp->l_text, "");
}
} else if (inout == '<') {
int oldindent = get_indent(lp);
(void) set_indent(lp, (oldindent <= Pn(P_shiftwidth) ?
0 : oldindent - Pn(P_shiftwidth)));
} else {
(void) set_indent(lp, get_indent(lp) + Pn(P_shiftwidth));
}
nlines++;
}
end_command(curwin);
if (nlines > Pn(P_report)) {
show_message(curwin, "%ld lines %ced", nlines, inout);
}
}
/*
* Construct a vector of pointers into each word in
* the given string. Intervening whitespace will be
* converted to null bytes.
*
* Returned vector is constructed in allocated space,
* and so must be freed after use.
*
* An extra NULL pointer is always allocated for safety.
*
* If memory cannot be allocated, or if there are no
* words in the given string, or if it is a NULL ptr,
* then the returned values will be 0 and NULL.
*
* The "whites" argument is a pointer to an array of
* characters which are to be considered as whitespace.
*/
void
makeargv(str, argcp, argvp, whites)
char *str;
int *argcp;
char ***argvp;
char *whites;
{
int argc;
char **argv;
int argv_size;
*argcp = 0;
*argvp = NULL;
if (str == NULL)
return;
/*
* Scan past initial whitespace.
*/
while (*str != '\0' && strchr(whites, *str) != NULL) {
if (*str == '\\' && strchr(whites, str[1]) != NULL) {
str++;
}
str++;
}
if (*str == '\0')
return;
argv = (char **) alloc(sizeof(char *) * 8);
if (argv == NULL)
return;
argv_size = 8;
argc = 0;
do {
if (argc >= (argv_size - 1)) {
argv_size += 8;
argv = (char **) realloc((char *) argv,
(unsigned) argv_size * sizeof(char *));
if (argv == NULL)
return;
}
argv[argc++] = str;
while (*str != '\0' && strchr(whites, *str) == NULL) {
if (*str == '\\' && strchr(whites, str[1]) != NULL) {
char *p;
/*
* What a hack. Copy the rest of the string
* down by one byte to remove the backslash.
* Don't forget to copy the null byte.
*/
for (p = str + 1; (*(p-1) = *p) != '\0'; p++)
;
}
str++;
}
while (*str != '\0' && strchr(whites, *str) != NULL)
*str++ = '\0';
} while (*str != '\0');
argv[argc] = NULL;
*argvp = argv;
*argcp = argc;
}