/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1981 Regents of the University of California */
#pragma ident "%Z%%M% %I% %E% SMI"
#include "ex.h"
#include "ex_re.h"
#include "ex_tty.h"
#include "ex_vis.h"
/*
* Entry points to open and visual from command mode processor.
* The open/visual code breaks down roughly as follows:
*
* ex_v.c entry points, checking of terminal characteristics
*
* ex_vadj.c logical screen control, use of intelligent operations
* insert/delete line and coordination with screen image;
* updating of screen after changes.
*
* ex_vget.c input of single keys and reading of input lines
* from the echo area, handling of \ escapes on input for
* uppercase only terminals, handling of memory for repeated
* commands and small saved texts from inserts and partline
* deletes, notification of multi line changes in the echo
* area.
*
* ex_vmain.c main command decoding, some command processing.
*
* ex_voperate.c decoding of operator/operand sequences and
* contextual scans, implementation of word motions.
*
* ex_vops.c major operator interfaces, undos, motions, deletes,
* changes, opening new lines, shifts, replacements and yanks
* coordinating logical and physical changes.
*
* ex_vops2.c subroutines for operator interfaces in ex_vops.c,
* insert mode, read input line processing at lowest level.
*
* ex_vops3.c structured motion definitions of ( ) { } and [ ] operators,
* indent for lisp routines, () and {} balancing.
*
* ex_vput.c output routines, clearing, physical mapping of logical cursor
* positioning, cursor motions, handling of insert character
* and delete character functions of intelligent and unintelligent
* terminals, visual mode tracing routines (for debugging),
* control of screen image and its updating.
*
* ex_vwind.c window level control of display, forward and backward rolls,
* absolute motions, contextual displays, line depth determination
*/
void setsize();
void winch();
void vintr();
void ovend(ttymode);
wchar_t atube[TUBESIZE];
jmp_buf venv;
int windowchg;
int sigok;
/* reinitialize window size after SIGWINCH */
void windowinit()
{
windowchg = 0;
setsize();
if(value(vi_WINDOW) >= lines || options[vi_WINDOW].odefault == value(vi_WINDOW))
value(vi_WINDOW) = lines -1;
options[vi_WINDOW].odefault = lines - 1;
if(options[vi_SCROLL].odefault == value(vi_SCROLL))
value(vi_SCROLL) = value(vi_WINDOW)/2;
options[vi_SCROLL].odefault = (lines - 1)/2;
vsetsiz(value(vi_WINDOW));
setwind();
vok(atube, 1);
}
void redraw()
{
vsave();
windowinit();
vclear();
vdirty(0, lines);
if(state != VISUAL) {
vclean();
vmoveto(dot, cursor, 0);
} else {
vredraw(WTOP);
vrepaint(cursor);
vfixcurs();
}
}
/*ARGSUSED*/
void
#ifdef __STDC__
winch(int sig)
#else
winch(sig)
int sig;
#endif
{
struct winsize jwin;
int l;
if(ioctl(0, TIOCGWINSZ, &jwin) != -1) {
#ifdef XPG4
oldlines = jwin.ws_row;
oldcolumns = jwin.ws_col;
#endif /* XPG4 */
if (sigok) {
if (columns != jwin.ws_col || lines != jwin.ws_row)
redraw();
}
}
else
windowchg++;
(void)signal(SIGWINCH, winch);
}
void
setsize()
{
struct winsize jwin;
int l;
if(ioctl(0, TIOCGWINSZ, &jwin) != -1) {
if (jwin.ws_col > 0)
columns = jwin.ws_col;
if (jwin.ws_row > 0)
lines = jwin.ws_row;
}
#ifdef XPG4
if (envlines != -1) {
lines = envlines;
}
if (envcolumns != -1) {
columns = envcolumns;
}
if (envlines != -1 || envcolumns != -1) {
jwin.ws_row = lines;
jwin.ws_col = columns;
if (ioctl(0, TIOCSWINSZ, &jwin) == -1) {
jwin.ws_row = oldlines;
jwin.ws_col = oldcolumns;
ioctl(0, TIOCSWINSZ, &jwin);
}
}
#endif /* XPG4 */
if (lines <= 1)
lines = 24;
l = lines;
if (columns <= 4)
columns = 1000;
value(vi_WINDOW) = options[vi_WINDOW].odefault = l - 1;
}
/*
* Enter open mode
*/
void
oop(void)
{
unsigned char *ic;
ttymode f; /* was register */
int resize;
windowchg = 0;
(void)signal(SIGWINCH, winch);
ovbeg();
if (peekchar() == '/') {
(void)vi_compile(getchar(), 1);
savere(&scanre);
if (execute(0, dot) == 0)
error(value(vi_TERSE) ? gettext("Fail") :
gettext("Pattern not found on addressed line"));
ic = (unsigned char *)loc1;
if (ic > linebuf && *ic == 0)
ic--;
} else {
getDOT();
ic = vskipwh(linebuf);
}
donewline();
/*
* If overstrike then have to HARDOPEN
* else if can move cursor up off current line can use CRTOPEN (~~vi1)
* otherwise have to use ONEOPEN (like adm3)
*/
if (over_strike && !erase_overstrike)
bastate = HARDOPEN;
else if (cursor_address || cursor_up)
bastate = CRTOPEN;
else
bastate = ONEOPEN;
setwind();
/*
* To avoid bombing on glass-crt's when the line is too long
* pretend that such terminals are 160 columns wide.
* If a line is too wide for display, we will dynamically
* switch to hardcopy open mode.
*/
if (state != CRTOPEN)
WCOLS = TUBECOLS;
if (!inglobal)
savevis();
vok(atube, 0);
if (state != CRTOPEN)
columns = WCOLS;
Outchar = vputchar;
f = ostart();
if (state == CRTOPEN) {
if (outcol == UKCOL)
outcol = 0;
vmoveitup(1, 1);
} else
outline = destline = WBOT;
vshow(dot, NOLINE);
vnline(ic);
vmain();
if (state != CRTOPEN)
vclean();
Command = (unsigned char *)"open";
ovend(f);
(void)signal(SIGWINCH, SIG_DFL);
}
void
ovbeg(void)
{
if (inopen)
error(gettext("Recursive open/visual not allowed"));
Vlines = lineDOL();
fixzero();
setdot();
pastwh();
dot = addr2;
}
void
ovend(ttymode f)
{
splitw++;
vgoto(WECHO, 0);
vclreol();
vgoto(WECHO, 0);
holdcm = 0;
splitw = 0;
ostop(f);
setoutt();
undvis();
columns = OCOLUMNS;
inopen = 0;
flusho();
netchHAD(Vlines);
}
/*
* Enter visual mode
*/
void
vop(void)
{
int c;
ttymode f; /* was register */
extern unsigned char termtype[];
if (!cursor_address && !cursor_up) {
if (initev) {
toopen:
if (generic_type)
merror(gettext("I don't know what kind of terminal you are on - all I have is '%s'."), termtype);
putNFL();
merror(gettext("[Using open mode]"));
putNFL();
oop();
return;
}
error(gettext("Visual needs addressable cursor or upline capability"));
}
if (over_strike && !erase_overstrike) {
if (initev)
goto toopen;
error(gettext("Can't use visual on a terminal which overstrikes"));
}
if (!clear_screen) {
if (initev)
goto toopen;
error(gettext("Visual requires clear screen capability"));
}
if (!scroll_forward) {
if (initev)
goto toopen;
error(gettext("Visual requires scrolling"));
}
windowchg = 0;
(void)signal(SIGWINCH, winch);
ovbeg();
bastate = VISUAL;
c = 0;
if (any(peekchar(), "+-^."))
c = getchar();
pastwh();
vsetsiz(isdigit(peekchar()) ? getnum() : value(vi_WINDOW));
setwind();
donewline();
vok(atube, 0);
if (!inglobal)
savevis();
Outchar = vputchar;
vmoving = 0;
f = ostart();
if (initev == 0) {
vcontext(dot, c);
vnline((unsigned char *)NOSTR);
}
vmain();
Command = (unsigned char *)"visual";
ovend(f);
(void)signal(SIGWINCH, SIG_DFL);
}
/*
* Hack to allow entry to visual with
* empty buffer since routines internally
* demand at least one line.
*/
void
fixzero(void)
{
if (dol == zero) {
bool ochng = chng;
vdoappend((unsigned char *)"");
if (!ochng)
sync();
addr1 = addr2 = one;
} else if (addr2 == zero)
addr2 = one;
}
/*
* Save lines before visual between unddol and truedol.
* Accomplish this by throwing away current [unddol,truedol]
* and then saving all the lines in the buffer and moving
* unddol back to dol. Don't do this if in a global.
*
* If you do
* g/xxx/vi.
* and then do a
* :e xxxx
* at some point, and then quit from the visual and undo
* you get the old file back. Somewhat weird.
*/
void
savevis(void)
{
if (inglobal)
return;
truedol = unddol;
saveall();
unddol = dol;
undkind = UNDNONE;
}
/*
* Restore a sensible state after a visual/open, moving the saved
* stuff back to [unddol,dol], and killing the partial line kill indicators.
*/
void
undvis(void)
{
if (ruptible)
signal(SIGINT, onintr);
squish();
pkill[0] = pkill[1] = 0;
unddol = truedol;
unddel = zero;
undap1 = one;
undap2 = dol + 1;
undkind = UNDALL;
if (undadot <= zero || undadot > dol)
undadot = zero+1;
}
/*
* Set the window parameters based on the base state bastate
* and the available buffer space.
*/
void
setwind(void)
{
WCOLS = columns;
switch (bastate) {
case ONEOPEN:
if (auto_right_margin)
WCOLS--;
/* fall into ... */
case HARDOPEN:
basWTOP = WTOP = WBOT = WECHO = 0;
ZERO = 0;
holdcm++;
break;
case CRTOPEN:
basWTOP = lines - 2;
/* fall into */
case VISUAL:
ZERO = lines - TUBESIZE / WCOLS;
if (ZERO < 0)
ZERO = 0;
if (ZERO > basWTOP)
error(gettext("Screen too large for internal buffer"));
WTOP = basWTOP; WBOT = lines - 2; WECHO = lines - 1;
break;
}
state = bastate;
basWLINES = WLINES = WBOT - WTOP + 1;
}
/*
* Can we hack an open/visual on this terminal?
* If so, then divide the screen buffer up into lines,
* and initialize a bunch of state variables before we start.
*/
static unsigned char vlinebuf[LBSIZE];
void
vok(wchar_t *atube, int undo)
{
int i;
static int beenhere;
if (WCOLS == 1000)
serror((unsigned char *)
gettext("Don't know enough about your terminal to use %s"),
Command);
if (WCOLS > TUBECOLS)
error(gettext("Terminal too wide"));
if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE)
error(gettext("Screen too large"));
vtube0 = atube;
if(beenhere)
vclrbyte(atube, WCOLS * (WECHO - ZERO + 1));
for (i = 0; i < ZERO; i++)
vtube[i] = (wchar_t *) 0;
for (; i <= WECHO; i++)
vtube[i] = atube, atube += WCOLS;
if(beenhere++) {
for (; i < TUBELINES; i++)
vtube[i] = (wchar_t *) 0;
}
vutmp = vlinebuf;
if(!undo) {
vundkind = VNONE;
vUNDdot = 0;
}
OCOLUMNS = columns;
inopen = 1;
#ifdef CBREAK
signal(SIGINT, vintr);
#endif
vmoving = 0;
splitw = 0;
doomed = 0;
holdupd = 0;
if(!undo)
Peekkey = 0;
vcnt = vcline = 0;
if (vSCROLL == 0)
vSCROLL = value(vi_SCROLL);
}
#ifdef CBREAK
/*ARGSUSED*/
void
#ifdef __STDC__
vintr(int sig)
#else
vintr(sig)
int sig;
#endif
{
signal(SIGINT, vintr);
if (vcatch)
onintr(0);
ungetkey(ATTN);
draino();
}
#endif
/*
* Set the size of the screen to size lines, to take effect the
* next time the screen is redrawn.
*/
void
vsetsiz(int size)
{
int b;
if (bastate != VISUAL)
return;
b = lines - 1 - size;
if (b >= lines - 1)
b = lines - 2;
if (b < 0)
b = 0;
basWTOP = b;
basWLINES = WBOT - b + 1;
}