Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * This code contains changes by
 *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
 *
 * Conditions 1, 2, and 4 and the no-warranty notice below apply
 * to these changes.
 *
 *
 * Copyright (c) 1980, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *   Redistributions of source code and documentation must retain the
 *    above copyright notice, this list of conditions and the following
 *    disclaimer.
 *   Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *   All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed or owned by Caldera
 *      International, Inc.
 *   Neither the name of Caldera International, Inc. nor the names of
 *    other contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef lint
#ifdef  DOSCCS
static char sccsid[] = "@(#)ex_v.c      1.17 (gritter) 11/27/04";
#endif
#endif

/* from ex_v.c  7.8.1 (2.11BSD GTE) 12/9/94 */

#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 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
 */

JMP_BUF venv;

/*
 * Enter open mode
 */
#ifdef u370
cell    atube[TUBESIZE+LBSIZE];
#endif
void 
oop(void)
{
        register char *ic;
#ifndef u370
        cell atube[TUBESIZE + LBSIZE];
#endif
        struct termios f;       /* mjm: was register */
        int resize;

        resize = SETJMP(venv);
        if (resize) {
                setsize();
                initev = (char *)0;
                inopen = 0;
                addr1 = addr2 = dot;
        }
#ifdef  SIGWINCH
        signal(SIGWINCH, onwinch);
#endif
        ovbeg();
        if (peekchar() == '/') {
                ignore(compile(getchar(), 1));
                savere(&scanre);
                if (execute(0, dot) == 0)
                        error(catgets(catd, 1, 207,
                                "Fail|Pattern not found on addressed line"));
                ic = loc1;
                if (ic > linebuf && *ic == 0)
                        ic--;
        } else {
                getDOT();
                ic = vskipwh(linebuf);
        }
        newline();

        /*
         * If overstrike then have to HARDOPEN
         * else if can move cursor up off current line can use CRTOPEN (~~vi1)
         * otherwise (ugh) have to use ONEOPEN (like adm3)
         */
        if (OS && !EO)
                bastate = HARDOPEN;
        else if (CA || 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);
        if (state != CRTOPEN)
                TCOLUMNS = 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 = "open";
        ovend(f);
#ifdef  SIGWINCH
        signal(SIGWINCH, SIG_DFL);
#endif
}

void 
ovbeg(void)
{

        if (!value(OPEN))
                error(catgets(catd, 1, 208,
                        "Can't use open/visual unless open option is set"));
        if (inopen)
                error(catgets(catd, 1, 209,
                                        "Recursive open/visual not allowed"));
        Vlines = lineDOL();
        fixzero();
        setdot();
        pastwh();
        dot = addr2;
}

void 
ovend(struct termios f)
{

        splitw++;
        vgoto(WECHO, 0);
        vclreol();
        vgoto(WECHO, 0);
        holdcm = 0;
        splitw = 0;
        ostop(f);
        setoutt();
        undvis();
        TCOLUMNS = OCOLUMNS;
        inopen = 0;
        flusho();
        netchHAD(Vlines);
}

/*
 * Enter visual mode
 */
void 
vop(void)
{
        register int c;
#ifndef u370
        cell atube[TUBESIZE + LBSIZE];
#endif
        struct termios f;       /* mjm: was register */
        int resize;

        if (!CA && UP == NOSTR) {
                if (initev) {
toopen:
                        merror(catgets(catd, 1, 210, "[Using open mode]"));
                        putNFL();
                        oop();
                        return;
                }
                error(catgets(catd, 1, 211,
                "Visual needs addressible cursor or upline capability"));
        }
        if (OS && !EO) {
                if (initev)
                        goto toopen;
                error(catgets(catd, 1, 212,
                        "Can't use visual on a terminal which overstrikes"));
        }
        if (!CL) {
                if (initev)
                        goto toopen;
                error(catgets(catd, 1, 213,
                        "Visual requires clear screen capability"));
        }
        if (NS && !SF) {
                if (initev)
                        goto toopen;
                error(catgets(catd, 1, 214, "Visual requires scrolling"));
        }
        resize = SETJMP(venv);
        if (resize) {
                setsize();
                initev = (char *)0;
                inopen = 0;
                addr1 = addr2 = dot;
        }
#ifdef  SIGWINCH
        signal(SIGWINCH, onwinch);
#endif
        ovbeg();
        bastate = VISUAL;
        c = 0;
        if (any(peekchar(), "+-^."))
                c = getchar();
        pastwh();
        vsetsiz(isdigit(peekchar()) ? getnum() : value(WINDOW));
        setwind();
        newline();
        vok(atube);
        if (!inglobal)
                savevis();
        Outchar = vputchar;
        vmoving = 0;
        f = ostart();
        if (initev == 0) {
                vcontext(dot, c);
                vnline(NOSTR);
        }
        vmain();
        Command = "visual";
        ovend(f);
#ifdef  SIGWINCH
        signal(SIGWINCH, SIG_DFL);
#endif
}

/*
 * Hack to allow entry to visual with
 * empty buffer since routines internally
 * demand at least one line.
 */
void 
fixzero(void)
{

        if (dol == zero) {
                register bool ochng = chng;

                vdoappend("");
                if (!ochng)
                        synced();
                fixedzero++;
                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 = TCOLUMNS;
        switch (bastate) {

        case ONEOPEN:
                if (AM)
                        WCOLS--;
                /* fall into ... */

        case HARDOPEN:
                basWTOP = WTOP = WBOT = WECHO = 0;
                ZERO = 0;
                holdcm++;
                break;

        case CRTOPEN:
                basWTOP = TLINES - 2;
                /* fall into */

        case VISUAL:
                ZERO = TLINES - TUBESIZE / WCOLS;
                if (ZERO < 0)
                        ZERO = 0;
                if (ZERO > basWTOP)
                        error(catgets(catd, 1, 215,
                                "Screen too large for internal buffer"));
                WTOP = basWTOP; WBOT = TLINES - 2; WECHO = TLINES - 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.
 */
void 
vok(register cell *atube)
{
        register int i;

        if (WCOLS == 1000)
                serror(catgets(catd, 1, 216,
                "Don't know enough about your terminal to use %s"), Command);
        if (WCOLS > TUBECOLS)
                error(catgets(catd, 1, 217, "Terminal too wide"));
        if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE)
                error(catgets(catd, 1, 218, "Screen too large"));

        vtube0 = atube;
        vclrcell(atube, WCOLS * (WECHO - ZERO + 1));
        for (i = 0; i < ZERO; i++)
                vtube[i] = (cell *) 0;
        for (; i <= WECHO; i++)
                vtube[i] = atube, atube += WCOLS;
        for (; i < TUBELINES; i++)
                vtube[i] = (cell *) 0;
        vutmp = (char *)atube;
        vundkind = VNONE;
        vUNDdot = 0;
        OCOLUMNS = TCOLUMNS;
        inopen = 1;
        signal(SIGINT, vintr);
        vmoving = 0;
        splitw = 0;
        doomed = 0;
        holdupd = 0;
        Peekkey = 0;
        vcnt = vcline = 0;
        if (vSCROLL == 0)
                vSCROLL = value(SCROLL);
                /*old vSCROLL = (value(WINDOW)+1)/2;*//* round up so dft=6,11 */
}

void 
vintr(int signum)
{
        extern JMP_BUF readbuf;
        extern int doingread;

        signal(SIGINT, vintr);
        if (vcatch)
                onintr(SIGINT);
        ungetkey(ATTN);
        draino();
        if (doingread) {
                doingread = 0;
                LONGJMP(readbuf, 1);
        }
}

/*
 * Set the size of the screen to size lines, to take effect the
 * next time the screen is redrawn.
 */
void
vsetsiz(int size)
{
        register int b;

        if (bastate != VISUAL)
                return;
        b = TLINES - 1 - size;
        if (b >= TLINES - 1)
                b = TLINES - 2;
        if (b < 0)
                b = 0;
        basWTOP = b;
        basWLINES = WBOT - b + 1;
}

#ifdef  SIGWINCH
void 
onwinch(int signum)
{
        vsave();
        setty(normf);
        LONGJMP(venv, 1);
}
#endif