root/usr/src/cmd/vi/port/ex_set.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */


/* Copyright (c) 1981 Regents of the University of California */

#include "ex.h"
#include "ex_temp.h"
#include "ex_tty.h"

/*
 * Set command.
 */
unsigned char   optname[ONMSZ];

void
set(void)
{
        unsigned char *cp;
        struct option *op;
        int c;
        bool no;
        extern short ospeed;
#ifdef TRACE
        int k, label;
        line *tmpadr;
#endif

        setnoaddr();
        if (skipend()) {
                if (peekchar() != EOF)
                        ignchar();
                propts();
                return;
        }
        do {
                cp = optname;
                do {
                        if (cp < &optname[ONMSZ - 2])
                                *cp++ = getchar();
                } while (isalnum(peekchar()));
                *cp = 0;
                cp = optname;
                if (eq("all", cp)) {
                        if (inopen)
                                pofix();
                        prall();
                        goto next;
                }
                no = 0;
#ifdef TRACE
                /*
                 * General purpose test code for looking at address of those
                 * invisible marks (as well as the visible ones).
                 */
                if (eq("marks", cp)) {
                        viprintf("Marks   Address\n\r");
                        viprintf("                                      \n");
                        viprintf("\n");
                        for (k = 0; k <= 25; k++)
                                viprintf("Mark:%c\t%d\n", k+'a', names[k]);
                goto next;
                }

                /*
                 * General purpose test code for looking at
                 * named registers.
                 */

                if (eq("named",cp)) {
                        if (inopen)
                                pofix();
                        shownam();
                        goto next;
                }

                /*
                 * General purpose test code for looking at
                 * numbered registers.
                 */

                if (eq("nbrreg",cp)) {
                        if (inopen)
                                pofix();
                        shownbr();
                        goto next;
                }

                /*
                 * General purpose test code for looking at addresses
                 * in the edit and save areas of VI.
                 */

                if (eq("buffers",cp)) {
                        if (inopen)
                                pofix();
                        viprintf("\nLabels   Address    Contents\n");
                        viprintf("======   =======      ========");
                        for (tmpadr = zero; tmpadr <= dol; tmpadr++) {
                                label =0;
                                if (tmpadr == zero) {
                                        viprintf("ZERO:\t");
                                        label = 2;
                                }
                                if (tmpadr == one) {
                                        if (label > 0)
                                                viprintf("\nONE:\t");
                                        else
                                                viprintf("ONE:\t");
                                        label = 1;
                                }
                                if (tmpadr == dot) {
                                        if (label > 0)
                                                viprintf("\nDOT:\t");
                                        else
                                                viprintf("DOT:\t");
                                        label = 1;
                                }
                                if (tmpadr == undap1) {
                                        if (label > 0)
                                                viprintf("\nUNDAP1:\t");
                                        else
                                                viprintf("UNDAP1:\t");
                                        label = 1;
                                }
                                if (tmpadr == undap2) {
                                        if (label > 0)
                                                viprintf("\nUNDAP2:\t");
                                        else
                                                viprintf("UNDAP2:\t");
                                        label = 1;
                                }
                                if (tmpadr == unddel) {
                                        if (label > 0)
                                                viprintf("\nUNDDEL:\t");
                                        else
                                                viprintf("UNDDEL:\t");
                                        label = 1;
                                }
                                if (tmpadr == dol) {
                                        if (label > 0)
                                                viprintf("\nDOL:\t");
                                        else
                                                viprintf("DOL:\t");
                                        label = 1;
                                }
                                for (k=0; k<=25; k++)
                                        if (names[k] == (*tmpadr &~ 01)) {
                                                if (label > 0)
                                                        viprintf(
"\nMark:%c\t%d\t", k+'a', names[k]);
                                                else
                                                        viprintf(
"Mark:%c\t%d\t", k+'a', names[k]);
                                                label=1;
                                        }
                                if (label == 0)
                                        continue;

                                if (label == 2)
                                        viprintf("%d\n", tmpadr);
                                else  {
                                        viprintf("%d\t", tmpadr);
                                        getaline(*tmpadr);
                                        pline(lineno(tmpadr));
                                        putchar('\n');
                                }
                        }

                        for (tmpadr = dol+1; tmpadr <= unddol; tmpadr++) {
                                label =0;
                                if (tmpadr == dol+1) {
                                        viprintf("DOL+1:\t");
                                        label = 1;
                                }
                                if (tmpadr == unddel) {
                                        if (label > 0)
                                                viprintf("\nUNDDEL:\t");
                                        else
                                                viprintf("UNDDEL:\t");
                                        label = 1;
                                }
                                if (tmpadr == unddol) {
                                        if (label > 0)
                                                viprintf("\nUNDDOL:\t");
                                        else
                                                viprintf("UNDDOL:\t");
                                        label = 1;
                                }
                                for (k=0; k<=25; k++)
                                        if (names[k] == (*tmpadr &~ 01)) {
                                                if (label > 0)
                                                        viprintf(
"\nMark:%c\t%d\t", k+'a', names[k]);
                                                else
                                                        viprintf(
"Mark:%c\t%d\t", k+'a', names[k]);
                                                label=1;
                                        }
                                if (label == 0)
                                        continue;
                                if (label == 2)
                                        viprintf("%d\n", tmpadr);
                                else  {
                                        viprintf("%d\t", tmpadr);
                                        getaline(*tmpadr);
                                        pline(lineno(tmpadr));
                                        putchar('\n');
                                }
                        }
                        goto next;
                }
#endif
                if (cp[0] == 'n' && cp[1] == 'o' && cp[2] != 'v') {
                        cp += 2;
                        no++;
                }
                /* Implement w300, w1200, and w9600 specially */
                if (eq(cp, "w300")) {
                        if (ospeed >= B1200) {
dontset:
                                (void)getchar();        /* = */
                                (void)getnum(); /* value */
                                continue;
                        }
                        cp = (unsigned char *)"window";
                } else if (eq(cp, "w1200")) {
                        if (ospeed < B1200 || ospeed >= B2400)
                                goto dontset;
                        cp = (unsigned char *)"window";
                } else if (eq(cp, "w9600")) {
                        if (ospeed < B2400)
                                goto dontset;
                        cp = (unsigned char *)"window";
                }
                for (op = options; op < &options[vi_NOPTS]; op++)
                        if (eq(op->oname, cp) || op->oabbrev && eq(op->oabbrev, cp))
                                break;
                if (op->oname == 0)
                        serror(value(vi_TERSE) ? (unsigned char *)
                            gettext("%s: No such option") :
                            (unsigned char *)
gettext("%s: No such option - 'set all' gives all option values"), cp);
                c = skipwh();
                if (peekchar() == '?') {
                        ignchar();
printone:
                        propt(op);
                        noonl();
                        goto next;
                }
                if (op->otype == ONOFF) {
                        op->ovalue = 1 - no;
                        if (op == &options[vi_PROMPT])
                                oprompt = 1 - no;
                        goto next;
                }
                if (no)
                        serror((unsigned char *)
                            gettext("Option %s is not a toggle"), op->oname);
                if (c != 0 || setend())
                        goto printone;
                if (getchar() != '=')
                        serror(value(vi_TERSE) ? (unsigned char *)
                            gettext("Missing =") :
                            (unsigned char *)
                            gettext("Missing = in assignment to option %s"),
                            op->oname);
                switch (op->otype) {

                case NUMERIC:
                        if (!isdigit(peekchar()))
                                error(value(vi_TERSE) ?
gettext("Digits required") : gettext("Digits required after ="));
                        op->ovalue = getnum();
                        if (value(vi_TABSTOP) <= 0)
                                value(vi_TABSTOP) = TABS;
                        if (op == &options[vi_WINDOW]) {
                                if (value(vi_WINDOW) >= lines)
                                        value(vi_WINDOW) = lines-1;
                                vsetsiz(value(vi_WINDOW));
                        }
                        break;

                case STRING:
                case OTERM:
                        cp = optname;
                        while (!setend()) {
                                if (cp >= &optname[ONMSZ])
                                        error(value(vi_TERSE) ?
gettext("String too long") : gettext("String too long in option assignment"));
                                /* adb change:  allow whitepace in strings */
                                if( (*cp = getchar()) == '\\')
                                        if( peekchar() != EOF)
                                                *cp = getchar();
                                cp++;
                        }
                        *cp = 0;
                        if (op->otype == OTERM) {
/*
 * At first glance it seems like we shouldn't care if the terminal type
 * is changed inside visual mode, as long as we assume the screen is
 * a mess and redraw it. However, it's a much harder problem than that.
 * If you happen to change from 1 crt to another that both have the same
 * size screen, it's OK. But if the screen size if different, the stuff
 * that gets initialized in vop() will be wrong. This could be overcome
 * by redoing the initialization, e.g. making the first 90% of vop into
 * a subroutine. However, the most useful case is where you forgot to do
 * a setenv before you went into the editor and it thinks you're on a dumb
 * terminal. Ex treats this like hardcopy and goes into HARDOPEN mode.
 * This loses because the first part of vop calls oop in this case.
 */
                                if (inopen)
error(gettext("Can't change type of terminal from within open/visual"));
                                unterm();
                                setterm(optname);
                        } else {
                                CP(op->osvalue, optname);
                                op->odefault = 1;
                        }
                        break;
                }
next:
                flush();
        } while (!skipend());
        eol();
}

void
unterm(void)
{
        /*
         *  All terminal mapped statements must be deleted.
         *  All user-defined mapped statements, cap=descr,
         *  are left unchanged.
         */

        int i;

        for (i=0; i < MAXNOMACS; i++) {

                /*
                 * Unmap any terminal-defined arrow keys
                 */

                if (arrows[i].cap && arrows[i].descr &&
                    strcmp(arrows[i].cap, arrows[i].descr))
                        addmac(arrows[i].cap, NOSTR, NOSTR, arrows);

                /*
                 * Unmap any terminal-defined function keys
                 */

                if (immacs[i].cap && immacs[i].descr && strcmp(immacs[i].cap, immacs[i].descr))
                        addmac(immacs[i].cap, NOSTR, NOSTR, immacs);

        }
}


int
setend(void)
{

        return (iswhite(peekchar()) || endcmd(peekchar()));
}

void
prall(void)
{
        int incr = (vi_NOPTS + 2) / 3;
        int rows = incr;
        struct option *op = options;

        for (; rows; rows--, op++) {
                propt(op);
                gotab(24);
                propt(&op[incr]);
                if (&op[2*incr] < &options[vi_NOPTS]) {
                        gotab(56);
                        propt(&op[2 * incr]);
                }
                putNFL();
        }
}

void
propts(void)
{
        struct option *op;

        for (op = options; op < &options[vi_NOPTS]; op++) {
                if (op == &options[vi_TTYTYPE])
                        continue;
                switch (op->otype) {

                case ONOFF:
                case NUMERIC:
                        if (op->ovalue == op->odefault)
                                continue;
                        break;

                case STRING:
                        if (op->odefault == 0)
                                continue;
                        break;
                }
                propt(op);
                putchar(' ');
        }
        noonl();
        flush();
}

void
propt(struct option *op)
{
        unsigned char *name;

        name = (unsigned char *)op->oname;

        switch (op->otype) {

        case ONOFF:
                viprintf("%s%s", op->ovalue ? "" : "no", name);
                break;

        case NUMERIC:
                viprintf("%s=%d", name, op->ovalue);
                break;

        case STRING:
        case OTERM:
                viprintf("%s=%s", name, op->osvalue);
                break;
        }
}