home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
vile-src.zip
/
vile-8.1
/
insert.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-07-15
|
28KB
|
1,302 lines
/*
*
* insert.c
*
* Do various types of character insertion, including most of insert mode.
*
* Most code probably by Dan Lawrence or Dave Conroy for MicroEMACS
* Extensions for vile by Paul Fox
*
* $Header: /usr/build/vile/vile/RCS/insert.c,v 1.110 1998/07/15 23:41:13 tom Exp $
*
*/
#include "estruct.h"
#include "edef.h"
#define DOT_ARGUMENT ((dotcmdmode == PLAY) && dotcmdarg)
#define BackspaceLimit() (b_val(curbp,MDBACKLIMIT) && autoindented <= 0)\
? DOT.o\
: w_left_margin(curwp)
static int backspace (void);
static int doindent(int ind);
static int indented_newline (void);
static int indented_newline_above (void);
static int ins_anytime(int playback, int cur_count, int max_count, int *splice);
static int insbrace(int n, int c);
static int inspound (void);
static int nextindent(int *bracefp);
static int openlines(int n);
static int shiftwidth(int f, int n);
static int tab(int f, int n);
#if !SMALLER
static int istring(int f, int n, int mode);
#endif
/* value of insertmode maintained through subfuncs */
static int savedmode;
static int allow_aindent = TRUE;
static int skipindent;
/*--------------------------------------------------------------------------*/
/* If the wrapmargin mode is active (i.e., nonzero), and if it's not wider than
* the screen, return the difference from the current position to the wrap
* margin. Otherwise, return negative.
*/
static int
past_wrapmargin(int c)
{
register int n;
if ((n = b_val(curbp, VAL_WRAPMARGIN)) > 0
&& (n = (term.t_ncol - (nu_width(curwp) + n))) >= 0) {
int list = w_val(curwp,WMDLIST);
int used = getccol(list);
/* compute the effective screen column after adding the
* latest character
*/
return NEXT_COLUMN(used, c, list, curtabval) - n;
}
return -1;
}
/* Returns true iff wrap-margin or wrap-words is active and we'll wrap at the
* current column.
*/
static int
wrap_at_col(int c)
{
register int n;
if (past_wrapmargin(c) >= 0)
return TRUE;
if (b_val(curbp, MDWRAP)
&& (n = b_val(curbp, VAL_FILL)) > 0)
return (getccol(FALSE) > n);
return FALSE;
}
/* advance one character past the current position, for 'append()' */
static void
advance_one_char(void)
{
if (! is_header_line(DOT,curbp) && !is_at_end_of_line(DOT))
forwchar(TRUE,1); /* END OF LINE HACK */
}
/* common logic for i,I,a,A commands */
static int
ins_n_times(int f, int n, int advance)
{
register int status = TRUE;
register int i;
int flag = FALSE;
if (!f || n < 0)
n = 1;
for (i = 0; i < n; i++) {
if ((status = ins_anytime((i != 0), i, n, &flag)) != TRUE)
break;
if (advance && !flag)
advance_one_char();
}
return status;
}
/* open lines up before this one */
int
openup(int f, int n)
{
register int s;
if (!f) n = 1;
if (n < 0) return (FALSE);
if (n == 0) return ins();
(void)gotobol(TRUE,1);
/* if we are in C mode and this is a default <NL> */
if (allow_aindent && n == 1 &&
(is_c_mode(curbp) || b_val(curbp,MDAIND)) &&
!is_header_line(DOT,curbp)) {
s = indented_newline_above();
if (s != TRUE) return (s);
return(ins());
}
s = lnewline();
if (s != TRUE) return s;
(void)backline(TRUE,1); /* back to the blank line */
if ( n > 1) {
s = openlines(n-1);
if (s != TRUE) return s;
s = backline(TRUE, 1); /* backup over the first one */
if (s != TRUE) return s;
}
return(ins());
}
/*
* as above, but override all autoindenting and cmode-ing
*/
int
openup_no_aindent(int f, int n)
{
int s;
int oallow = allow_aindent;
allow_aindent = FALSE;
s = openup(f,n);
allow_aindent = oallow;
return s;
}
/* open lines up after this one */
int
opendown(int f, int n)
{
register int s;
if (!f) n = 1;
if (n < 0) return (FALSE);
if (n == 0) return ins();
s = openlines(n);
if (s != TRUE)
return (s);
return(ins());
}
/*
* as above, but override all autoindenting and cmode-ing
*/
int
opendown_no_aindent(int f, int n)
{
int s;
int oallow = allow_aindent;
allow_aindent = FALSE;
s = opendown(f,n);
allow_aindent = oallow;
return s;
}
/*
* Open up some blank space. The basic plan is to insert a bunch of newlines,
* and then back up over them.
*
* This interprets the repeat-count for the 'o' and 'O' commands. Unlike vi
* (which does not use the repeat-count), this specifies the number of blank
* lines to create before proceeding with inserting the string-argument of the
* command.
*/
static int
openlines(int n)
{
register int i = n; /* Insert newlines. */
register int s = TRUE;
while (i-- && s==TRUE) {
(void)gotoeol(FALSE,1);
s = newline(TRUE,1);
}
if (s == TRUE && n) /* Then back up over top */
(void)backline(TRUE, n-1); /* of them all. */
curgoal = -1;
return s;
}
/*
* Implements the vi 'i' command.
*/
int
insert(int f, int n)
{
return ins_n_times(f,n,TRUE);
}
/*
* as above, but override all autoindenting and cmode-ing
*/
int
insert_no_aindent(int f, int n)
{
int s;
int oallow = allow_aindent;
allow_aindent = FALSE;
s = ins_n_times(f,n,TRUE);
allow_aindent = oallow;
return s;
}
/*
* Implements the vi 'I' command.
*/
int
insertbol(int f, int n)
{
if (!DOT_ARGUMENT || (dotcmdrep == dotcmdcnt))
(void)firstnonwhite(FALSE,1);
return ins_n_times(f,n,TRUE);
}
/*
* Implements the vi 'a' command.
*/
int
append(int f, int n)
{
advance_one_char();
return ins_n_times(f,n, !DOT_ARGUMENT);
}
/*
* Implements the vi 'A' command.
*/
int
appendeol(int f, int n)
{
if (!is_header_line(DOT,curbp))
(void)gotoeol(FALSE,0);
return ins_n_times(f,n,TRUE);
}
/*
* Unlike most flags on the mode-line, we'll only show the insertion-mode on
* the current window.
*/
static void
set_insertmode(int mode)
{
insertmode = mode;
if (b_val(curbp, MDSHOWMODE))
curwp->w_flag |= WFMODE;
}
/*
* Function that returns the insertion mode if we're inserting into a given
* window
*/
int
ins_mode(WINDOW *wp)
{
return (wp == curwp) ? insertmode : FALSE;
}
/*
* Implements the vi 'R' command.
*
* This takes an optional repeat-count and a string-argument. The repeat-count
* (default 1) specifies the number of times that the string argument is
* inserted. The length of the string-argument itself determines the number of
* characters (beginning with the cursor position) to delete before beginning
* the insertion.
*/
int
overwritechars(int f, int n)
{
set_insertmode(OVERWRITE);
return ins_n_times(f,n, TRUE);
}
/*
* Implements the vi 'r' command.
*
* This takes an optional repeat-count and a single-character argument. The
* repeat-count (default 1) specifies the number of characters beginning with
* the cursor position that are replaced by the argument. Newline is treated
* differently from the other characters (only one newline is inserted).
*
* Unlike vi, the number of characters replaced can be longer than a line.
* Also, vile allows quoted characters.
*/
int
replacechar(int f, int n)
{
register int s = TRUE;
register int t = FALSE;
register int c;
if (!f && is_empty_line(DOT))
return FALSE;
if (clexec || isnamedcmd) {
int status;
static char cbuf[NLINE];
if ((status=mlreply("Replace with: ", cbuf, 2)) != TRUE)
return status;
c = cbuf[0];
} else {
set_insertmode(REPLACECHAR); /* need to fool SPEC prefix code */
if (dotcmdmode != PLAY)
(void)update(FALSE);
c = keystroke();
if (ABORTED(c)) {
set_insertmode(FALSE);
return ABORT;
}
}
c = kcod2key(c);
if (!f || !n)
n = 1;
if (n < 0)
s = FALSE;
else {
int vi_fix = (!DOT_ARGUMENT || (dotcmdrep <= 1));
(void)ldelete((B_COUNT)n, FALSE);
if (c == quotec) {
t = s = quote(f,n);
} else {
if (isreturn(c)) {
if (vi_fix)
s = lnewline();
} else {
if (isbackspace(c)) { /* vi beeps here */
s = TRUE; /* replaced with nothing */
} else {
t = s = linsert(n, c);
}
}
}
if ((t == TRUE) && (DOT.o > w_left_margin(curwp)) && vi_fix)
s = backchar(FALSE,1);
}
set_insertmode(FALSE);
return s;
}
/*
* This routine performs the principal decoding for insert mode (i.e.., the
* i,I,a,A,R commands). It is invoked via 'ins_n_times()', which loops over
* the repeat-count for direct commands. One complicating factor is that
* 'ins_n_times()' (actually its callers) is called once for each repetition in
* a '.' command. At this level we compute the effective loop counter (the '.'
* and the direct commands), because we have to handle the vi-compatibilty case
* of inserting a newline.
*
* We stop repeating insert after the first newline in the insertion-string
* (that's what vi does). If a user types
*
* 3iABC<nl>foo<esc>
*
* then we want to insert
*
* ABCABCABC<nl>foo
*/
static int last_insert_char;
static int
ins_anytime(int playback, int cur_count, int max_count, int *splice)
{
#if OPT_MOUSE || OPT_B_LIMITS
WINDOW *wp0 = curwp;
#endif
register int status;
int c; /* command character */
int backsp_limit;
static ITBUFF *insbuff;
int osavedmode;
if (DOT_ARGUMENT) {
max_count = cur_count + dotcmdcnt;
cur_count += dotcmdcnt - dotcmdrep;
}
if (playback && (insbuff != 0))
itb_first(insbuff);
else if (!itb_init(&insbuff, abortc))
return FALSE;
if (insertmode == FALSE)
set_insertmode(INSERT);
osavedmode = savedmode;
savedmode = insertmode;
backsp_limit = BackspaceLimit();
last_insert_char = EOS;
for_ever {
/*
* Read another character from the insertion-string.
*/
c = abortc;
if (playback) {
if (*splice && !itb_more(insbuff))
playback = FALSE;
else
c = itb_next(insbuff);
}
if (!playback) {
if (dotcmdmode != PLAY)
(void)update(FALSE);
c = mapped_keystroke();
#if OPT_MOUSE
/*
* Prevent user from starting insertion into a
* modifiable buffer, then clicking on another
* buffer to continue inserting. This assumes that
* 'setcursor()' handles entry into the other
* buffer.
*/
if (curwp != wp0) {
/* end insert mode for window we started in */
wp0->w_traits.insmode = FALSE;
if (b_val(wp0->w_bufp, MDSHOWMODE))
wp0->w_flag |= WFMODE;
unkeystroke(c);
goto leave;
}
#endif
if (!itb_append(&insbuff, c)) {
status = FALSE;
break;
}
}
if (isspecial(c)) {
/* if we're allowed to honor SPEC bindings,
then see if it's bound to something, and
execute it */
const CMDFUNC *cfp = kcod2fnc(c);
if (cfp) {
int savedexecmode = insertmode;
backsp_limit = w_left_margin(curwp);
if (curgoal < 0)
curgoal = getccol(FALSE);
(void)execute(cfp,FALSE,1);
insertmode = savedexecmode;
}
continue;
}
if (!isident(c))
abbr_check(&backsp_limit);
if (isreturn(c)) {
if ((cur_count+1) < max_count) {
if (DOT_ARGUMENT) {
while (itb_more(dotcmd))
(void)mapped_keystroke();
}
*splice = TRUE;
status = TRUE;
break;
} else if (DOT_ARGUMENT) {
*splice = TRUE;
}
}
/*
* Decode the character
*/
if (ABORTED(c)) {
#if OPT_MOUSE
leave:
#endif
/* an unfortunate Vi-ism that ensures one
can always type "ESC a" if you're not sure
you're in insert mode. */
if (DOT.o > w_left_margin(wp0))
backchar(TRUE,1);
if (autoindented >= 0) {
(void)trimline((void *)0,0,0);
autoindented = -1;
}
if (cur_count+1 == max_count)
*splice = TRUE;
status = TRUE;
break;
} else if ((c & HIGHBIT) && b_val(curbp, MDMETAINSBIND)) {
/* if we're allowed to honor meta-character bindings,
then see if it's bound to something, and
insert it if not */
const CMDFUNC *cfp = kcod2fnc(c);
if (cfp) {
int savedexecmode = insertmode;
backsp_limit = w_left_margin(curwp);
if (curgoal < 0)
curgoal = getccol(FALSE);
(void)execute(cfp,FALSE,1);
insertmode = savedexecmode;
continue;
}
}
if (c == startc || c == stopc) { /* ^Q and ^S */
continue;
}
#if OPT_SHELL && SYS_UNIX && defined(SIGTSTP) /* job control, ^Z */
else if (c == suspc) {
status = bktoshell(FALSE,1);
}
#endif
else {
status = inschar(c,&backsp_limit);
curgoal = -1;
}
if (status != TRUE)
break;
#if OPT_CFENCE
/* check for CMODE fence matching */
if (b_val(curbp, MDSHOWMAT))
fmatch(c);
#endif
/* check auto-save mode */
if (b_val(curbp, MDASAVE)) {
if (--curbp->b_acount <= 0) {
/* and save the file if needed */
(void)update(TRUE);
filesave(FALSE, 0);
curbp->b_acount = b_val(curbp,VAL_ASAVECNT);
}
}
}
set_insertmode(FALSE);
savedmode = osavedmode;
return (status);
}
/* grunt routine for insert mode */
int
ins(void)
{
int flag;
return ins_anytime(FALSE,1,1,&flag);
}
static int
isallspace(LINEPTR ln, int lb, int ub)
{
while (lb <= ub) {
if (!isSpace(lgetc(ln,ub)))
return FALSE;
ub--;
}
return TRUE;
}
/*
* This function is used when testing for wrapping, to see if there are any
* blanks already on the line. We explicitly exclude blanks before the
* autoindent margin, if any, to avoid inserting unnecessary blank lines.
*/
static int
blanks_on_line(void)
{
int code = FALSE;
int indentwas = b_val(curbp,MDAIND) ? previndent((int *)0) : 0;
int save = DOT.o;
int list = w_val(curwp,WMDLIST);
for (DOT.o = 0; DOT.o < llength(DOT.l); DOT.o++) {
if (isSpace(char_at(DOT))
&& getccol(list) >= indentwas) {
code = TRUE;
break;
}
}
DOT.o = save;
return code;
}
int
inschar(int c, int *backsp_limit_p)
{
CmdFunc execfunc; /* ptr to function to execute */
execfunc = NULL;
if (c == quotec) {
execfunc = quote;
} else {
/*
* If a space was typed, fill column is defined, the
* argument is non- negative, wrap mode is enabled, and
* we are now past fill column, perform word wrap.
*/
if (wrap_at_col(c)) {
int offset = past_wrapmargin(c);
int wm_flag = (offset >= 0);
int is_print = (!isspecial(c) && isPrint(c));
int is_space = (!isspecial(c) && isSpace(c));
if (is_space
|| (is_print && (offset >= 1) && blanks_on_line())) {
int status = wrapword(wm_flag, is_space);
*backsp_limit_p = w_left_margin(curwp);
if (wm_flag && is_space)
return status;
} else if (wm_flag
&& !blanks_on_line()
&& (c == '\t' || is_print)) {
kbd_alarm(); /* vi beeps past the margin */
}
}
if ( c == '\t') { /* tab */
execfunc = tab;
autoindented = -1;
} else if (isreturn(c)) {
execfunc = newline;
if (autoindented >= 0) {
(void)trimline((void *)0,0,0);
autoindented = -1;
}
*backsp_limit_p = w_left_margin(curwp);
} else if ( isbackspace(c) ||
c == tocntrl('D') ||
c == killc ||
c == wkillc) { /* ^U and ^W */
execfunc = nullproc;
/* all this says -- "is this a regular ^D for
backing up a shiftwidth?". otherwise,
we treat it as ^U, below */
if (c == tocntrl('D')
&& !(DOT.o > *backsp_limit_p
&& ((lgetc(DOT.l,DOT.o-1) == '0'
&& last_insert_char == '0')
|| (lgetc(DOT.l,DOT.o-1) == '^'
&& last_insert_char == '^'))
&& isallspace(DOT.l,w_left_margin(curwp),
DOT.o-2))) {
int goal, col, sw;
sw = shiftwid_val(curbp);
if (autoindented >=0)
*backsp_limit_p = w_left_margin(curwp);
col = getccol(FALSE);
if (col > 0)
goal = ((col-1)/sw)*sw;
else
goal = 0;
while (col > goal &&
DOT.o > *backsp_limit_p) {
backspace();
col = getccol(FALSE);
}
if (col < goal)
linsert(goal - col,' ');
} else {
/* have we backed thru a "word" yet? */
int saw_word = FALSE;
/* was it '^^D'? then set the flag
that tells us to skip a line
when calculating the autoindent
on the next newline */
if (c == tocntrl('D') &&
last_insert_char == '^')
skipindent = 1;
while (DOT.o > *backsp_limit_p) {
if (c == wkillc) {
if (isSpace( lgetc(DOT.l,
DOT.o-1))) {
if (saw_word)
break;
} else {
saw_word = TRUE;
}
}
backspace();
autoindented--;
if (c != wkillc && c != killc
&& c != tocntrl('D'))
break;
}
}
} else if ( c == tocntrl('T')) { /* ^T */
execfunc = shiftwidth;
}
last_insert_char = c;
}
if (execfunc != NULL)
return (*execfunc)(FALSE, 1);
/* make it a real character again */
c = kcod2key(c);
/* if we are in overwrite mode, not at eol,
and next char is not a tab or we are at a tab stop,
delete a char forword */
if ((insertmode == OVERWRITE)
&& (!DOT_ARGUMENT || (dotcmdrep <= 1))
&& (DOT.o < llength(DOT.l))
&& (char_at(DOT) != '\t' || DOT.o % curtabval == curtabval-1)) {
autoindented = -1;
(void)ldelete(1L, FALSE);
}
/* do the appropriate insertion */
if (allow_aindent && is_c_mode(curbp)) {
int dir;
if (is_user_fence(c, &dir) && dir == REVERSE) {
return insbrace(1, c);
} else if (c == '#') {
return inspound();
}
}
autoindented = -1;
return linsert(1, c);
}
#if ! SMALLER
int
appstring(int f, int n)
{
advance_one_char();
return istring(f,n,INSERT);
}
int
insstring(int f, int n)
{
return istring(f,n,INSERT);
}
int
overwstring(int f, int n)
{
return istring(f,n,OVERWRITE);
}
/* ask for and insert or overwrite a string into the current */
/* buffer at the current point */
static int
istring(int f, int n, int mode)
{
register char *tp; /* pointer into string to add */
register int status; /* status return code */
int backsp_limit;
static char tstring[NPAT+1]; /* string to add */
/* ask for string to insert */
status = mlreply("String to insert: ", tstring, NPAT);
if (status != TRUE)
return(status);
if (f == FALSE)
n = 1;
if (n < 0)
n = - n;
set_insertmode(mode);
backsp_limit = BackspaceLimit();
/* insert it */
while (n--) {
tp = &tstring[0];
while (*tp) {
status = inschar(*tp++,&backsp_limit);
if (status != TRUE) {
set_insertmode(FALSE);
return(status);
}
}
}
set_insertmode(FALSE);
return(TRUE);
}
#endif
static int
backspace(void)
{
register int s;
if ((s=backchar(TRUE, 1)) == TRUE && insertmode != OVERWRITE)
s = ldelete(1L, FALSE);
return (s);
}
/*
* Insert a newline. If we are in CMODE, do automatic
* indentation as specified.
*/
int
newline(int f, int n)
{
register int s;
if (!f)
n = 1;
else if (n < 0)
return (FALSE);
/* if we are in C or auto-indent modes and this is a default <NL> */
if (allow_aindent
&& (n == 1)
&& (is_c_mode(curbp) || b_val(curbp,MDAIND))
&& !is_header_line(DOT,curbp))
return indented_newline();
/* insert some lines */
while (n--) {
if ((s=lnewline()) != TRUE)
return (s);
curwp->w_flag |= WFINS;
}
return (TRUE);
}
/* insert a newline and indentation for C */
static int
indented_newline(void)
{
int cmode = allow_aindent && is_c_mode(curbp);
register int indentwas; /* indent to reproduce */
int bracef; /* was there a brace at the end of line? */
if (lnewline() == FALSE)
return FALSE;
indentwas = previndent(&bracef);
skipindent = 0;
if (cmode && bracef)
indentwas = next_sw(indentwas);
return doindent(indentwas);
}
/* insert a newline and indentation for autoindent */
static int
indented_newline_above(void)
{
int cmode = allow_aindent && is_c_mode(curbp);
register int indentwas; /* indent to reproduce */
int bracef; /* was there a brace at the beginning of line? */
indentwas = nextindent(&bracef);
if (lnewline() == FALSE)
return FALSE;
if (backline(TRUE,1) == FALSE)
return FALSE;
if (cmode && bracef)
indentwas = next_sw(indentwas);
return doindent(indentwas);
}
/* get the indent of the last previous non-blank line. also, if arg
is non-null, check if line ended in a brace */
int
previndent(int *bracefp)
{
int ind;
int cmode = allow_aindent && is_c_mode(curbp);
if (bracefp) *bracefp = FALSE;
MK = DOT;
/* backword() will leave us either on this line, if there's something
non-blank here, or on the nearest previous non-blank line. */
/* (at start of buffer, may leave us on empty line) */
do {
if (backword(FALSE,1) == FALSE || is_empty_line(DOT)) {
(void)gomark(FALSE,1);
return 0;
}
DOT.o = 0;
/* if the line starts with a #, then don't copy its indent */
} while ((skipindent-- > 0) || (cmode && lgetc(DOT.l, 0) == '#'));
ind = indentlen(DOT.l);
if (bracefp) {
int lc = lastchar(DOT.l);
int c = lgetc(DOT.l,lc);
int dir;
*bracefp = (lc >= 0 && (c == ':' ||
(is_user_fence(c, &dir) && dir == FORWARD)));
}
(void)gomark(FALSE,1);
return ind;
}
/* get the indent of the next non-blank line. also, if arg
is non-null, check if line starts in a brace */
static int
nextindent(int *bracefp)
{
int ind;
int fc;
MK = DOT;
/* we want the indent of this line if it's non-blank, or the indent
of the next non-blank line otherwise */
fc = firstchar(DOT.l);
if (fc < 0 && ( forwword(FALSE,1) == FALSE
|| (fc = firstchar(DOT.l)) < 0)) {
if (bracefp)
*bracefp = FALSE;
DOT = MK;
return 0;
}
ind = indentlen(DOT.l);
if (bracefp) {
*bracefp = ((lgetc(DOT.l,fc) == RBRACE) ||
(lgetc(DOT.l,fc) == RPAREN) ||
(lgetc(DOT.l,fc) == RBRACK));
}
DOT = MK;
return ind;
}
static int
doindent(int ind)
{
register int i, j;
/* first clean up existing leading whitespace */
if ((i = firstchar(DOT.l)) >= 0)
j = DOT.o - i;
else
j = 0;
if (j < 0)
j = 0;
DOT.o = w_left_margin(curwp);
if (i > 0)
(void)ldelete((B_COUNT)i,FALSE);
autoindented = 0;
/* if no indent was asked for, we're done */
if (ind > 0) {
i = ind/curtabval; /* how many tabs? */
if (i && b_val(curbp,MDTABINSERT)) {
autoindented += i;
if (tab(TRUE,i) == FALSE)
return FALSE;
ind %= curtabval; /* how many spaces remaining */
}
if (ind > 0) { /* only spaces now */
autoindented += ind;
if (linsert(ind, ' ') == FALSE)
return FALSE;
}
}
if (!autoindented)
autoindented = -1;
DOT.o += j; /* put dot back pointing to the same text as before */
return TRUE;
}
/* return the column indent of the specified line */
int
indentlen(LINE *lp)
{
register int ind, i, c;
ind = 0;
for (i=0; i<llength(lp); ++i) {
c = lgetc(lp, i);
if (!isSpace(c))
break;
if (c == '\t')
ind = nextab(ind);
else
++ind;
}
return ind;
}
/* insert a brace or paren into the text here... we are in CMODE */
static int
insbrace(
int n, /* repeat count */
int c) /* brace/paren to insert (always '}' or ')' for now) */
{
#if ! OPT_CFENCE
/* wouldn't want to back up from here, but fences might take us
forward */
/* if we are at the beginning of the line, no go */
if (DOT.o <= w_left_margin(curwp))
return(linsert(n,c));
#endif
if (autoindented >= 0) {
(void)trimline((void *)0,0,0);
} else {
return linsert(n,c);
}
skipindent = 0;
#if ! OPT_CFENCE /* no fences? then put brace one tab in from previous line */
doindent(((previndent(NULL)-1) / curtabval) * curtabval);
#else /* line up brace with the line containing its match */
doindent(fmatchindent(c));
#endif
autoindented = -1;
/* and insert the required brace(s) */
return(linsert(n, c));
}
static int
inspound(void) /* insert a # into the text here...we are in CMODE */
{
/* if we are at the beginning of the line, no go */
if (DOT.o <= w_left_margin(curwp))
return(linsert(1,'#'));
if (autoindented > 0) { /* must all be whitespace before us */
if (autoindented > llength(DOT.l))
autoindented = llength(DOT.l);
DOT.o = w_left_margin(curwp);
(void)ldelete((B_COUNT)autoindented,FALSE);
}
autoindented = -1;
/* and insert the required pound */
return(linsert(1, '#'));
}
/* insert a tab into the file */
static int
tab(int f, int n)
{
int ccol;
if (!f) n = 1;
if (n <= 0)
return FALSE;
if (b_val(curbp,MDTABINSERT))
return linsert(n, '\t');
ccol = getccol(FALSE);
return linsert((nextab(ccol) - ccol) + (n-1)*curtabval,' ');
}
/*ARGSUSED*/
static int
shiftwidth(int f GCC_UNUSED, int n GCC_UNUSED)
{
int logical_col;
int char_index;
int space_count;
int all_white;
int add_spaces;
int c;
int s;
char_index = DOT.o;
/*
* Compute the "logical" column; i.e. the column the cursor is
* in on the screen.
*
* While we're at it, compute the spaces just before the insert
* point.
*/
(void) gocol(0);
logical_col = 0;
space_count = 0;
all_white = TRUE;
while (DOT.o < char_index) {
c = char_at(DOT);
if (c == ' ') {
space_count++;
} else {
space_count = 0;
}
if (!isSpace(c)) {
all_white = FALSE;
}
if (c == '\t') {
logical_col += curtabval - (logical_col % curtabval);
} else {
logical_col++;
}
DOT.o++;
}
DOT.o = char_index;
/*
* Now we can compute the destination column. If this is the same
* as the tab column, delete the spaces before the insert point
* & insert a tab; otherwise, insert spaces as required.
*/
add_spaces = next_sw(logical_col) - logical_col;
if (space_count + add_spaces > curtabval) {
space_count = curtabval - add_spaces;
}
if (b_val(curbp,MDTABINSERT) &&
((add_spaces + logical_col) % curtabval == 0)) {
if (space_count > 0) {
DOT.o -= space_count;
s = ldelete((B_COUNT)space_count, FALSE);
} else {
space_count = 0;
s = TRUE;
}
if (s) {
space_count += add_spaces;
s = linsert((space_count + curtabval - 1) / curtabval, '\t');
}
} else {
s = linsert(add_spaces, ' ');
}
if (all_white && s) {
if (autoindented >= 0) {
int fc = firstchar(DOT.l);
if (fc >= 0)
autoindented = fc;
else /* all white */
autoindented = llength(DOT.l);
}
}
return s;
}
/*
* Quote the next character, and insert it into the buffer. All the characters
* are taken literally, with the exception of a) the newline, which always has
* its line splitting meaning, and b) decimal digits, which are accumulated
* (up to three of them) and the resulting value put in the buffer.
*
* A character is always read, even if it is inserted 0 times, for regularity.
*/
int
quote(int f, int n)
{
int s, c, digs, base, i, num, delta;
const char *str;
i = digs = 0;
num = 0;
c = keystroke_raw8();
if (!f)
n = 1;
if (n < 0)
return FALSE;
if (n == 0)
return TRUE;
/* accumulate up to 3 digits */
if (isDigit(c) || c == 'x') {
if (c == '0') {
digs = 4; /* including the leading '0' */
base = 8;
str = "octal";
} else if (c == 'x') {
digs = 3; /* including the leading 'x' */
base = 16;
c = '0';
str = "hex";
} else {
digs = 3;
base = 10;
str = "decimal";
}
do {
if (isbackspace(c)) {
num /= base;
if (--i < 0)
break;
} else {
if (c >= 'a' && c <= 'f')
delta = ('a' - 10);
else if (c >= 'A' && c <= 'F')
delta = ('A' - 10);
else
delta = '0';
num = num * base + c - delta;
i++;
}
mlwrite("Enter %s digits... %d", str, num);
if (i >= digs)
break;
(void)update(FALSE);
c = keystroke_raw8();
} while (isbackspace(c) ||
(isDigit(c) && base >= 10) ||
(base == 8 && c < '8') ||
(base == 16 && (c >= 'a' && c <= 'f')) ||
(base == 16 && (c >= 'A' && c <= 'F')));
}
mlerase();
/* did we get any digits at all? */
if (i > 0) {
if (ABORTED(c)) /* ESC gets us out painlessly */
return ABORT;
if (i < digs) /* any other character will be pushed back */
unkeystroke(c);
/* the accumulated value gets inserted */
c = (num > 255) ? 255 : num;
}
if (c == '\n') {
do {
s = lnewline();
} while (s==TRUE && --n);
return s;
} else {
return linsert(n, c);
}
}
#if OPT_EVAL
char *
current_modename(void)
{
switch (savedmode) {
default:
return "command";
case INSERT:
return "insert";
case OVERWRITE:
return "overwrite";
case REPLACECHAR:
return "replace";
}
}
#endif