/*
* 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
* 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) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1981 Regents of the University of California */
#include "ex.h"
#include "ex_argv.h"
#include "ex_temp.h"
#include "ex_tty.h"
#include "ex_vis.h"
int poffset;
/*
* Main loop for command mode command decoding.
* A few commands are executed here, but main function
* is to strip command addresses, do a little address oriented
* processing and call command routines to do the real work.
*/
extern unsigned char *Version;
void
{
int c;
int lchng;
int given;
int seensemi;
int cnt;
bool hadpr;
bool gotfile;
#ifdef XPG4
int d;
#endif /* XPG4 */
unsigned char *vgetpass();
resetflav();
nochng();
for (;;) {
if (!firstpat)
laste = 0;
/*
* If dot at last command
* ended up at zero, advance to one if there is a such.
*/
}
shudclob = 0;
/*
* If autoprint or trailing print flags,
* print the line at the specified offset
* before the next command.
*/
pflag = 0;
nochng();
poffset = 0;
gettext("Offset out-of-bounds") :
gettext("Offset after command "
"too large"));
setdot1();
goto print;
}
}
nochng();
/*
* Print prompt if appropriate.
* If not in global flush output first to prevent
* going into pfast mode unreasonably.
*/
if (inglobal == 0) {
flush();
putchar(':');
hadpr = 1;
}
TSYNC();
}
/*
* Gobble up the address.
* Degenerate addresses yield ".".
*/
addr2 = 0;
do {
c = getcd();
if (addr == 0) {
if (c == ',' || c == ';')
else if (addr1 != 0) {
break;
} else
break;
}
given++;
if (c == ';') {
c = ',';
seensemi = 1;
}
} while (c == ',');
if (c == '%') {
/* %: same as 1,$ */
given = 2;
c = getchar();
}
if (addr1 == 0)
/*
* eat multiple colons
*/
while (c == ':')
c = getchar();
/*
* Set command name for special character commands.
*/
tailspec(c);
/*
* If called via : escape from open or visual, limit
* the set of available commands here to save work below.
*/
if (inopen) {
if (c == '\n' || c == '\r' ||
if (addr2)
if (c == EOF)
return;
continue;
}
if (any(c, "o"))
}
switch (c) {
case 'a':
switch (peekchar()) {
case 'b':
/* abbreviate */
tail("abbreviate");
setnoaddr();
mapcmd(0, 1);
anyabbrs = 1;
continue;
case 'r':
/* args */
tail("args");
setnoaddr();
eol();
pargs();
continue;
}
/* append */
if (inopen)
goto notinvis;
tail("append");
setdot();
donewline();
vmacchng(0);
deletenone();
inappend = 1;
inappend = 0;
nochng();
continue;
case 'c':
switch (peekchar()) {
/* copy */
case 'o':
tail("copy");
vmacchng(0);
vi_move();
continue;
/* crypt */
case 'r':
tail("crypt");
crflag = -1;
setnoaddr();
xflag = 1;
if (permflag)
(void) crypt_close(perm);
permflag = 1;
xflag = 0;
kflag = 0;
crflag = 0;
"not available\n"));
}
if (kflag == 0)
crflag = 0;
continue;
/* cd */
case 'd':
tail("cd");
goto changdir;
/* chdir */
case 'h':
ignchar();
if (peekchar() == 'd') {
unsigned char *p;
tail2of("chdir");
if (savedfile[0] == '/' ||
(void) exclam();
else
(void) quickly();
if (skipend()) {
p = (unsigned char *)
getenv("HOME");
if (p == NULL)
"Home directory"
/*CSTYLED*/
" unknown"));
} else
eol();
if (chdir((char *)p) < 0)
filioerr(p);
if (savedfile[0] != '/')
edited = 0;
continue;
}
if (inopen)
tailprim((unsigned char *)"change",
2, 1);
tail2of("change");
break;
default:
if (inopen)
goto notinvis;
tail("change");
break;
}
/* change */
#ifdef XPG4ONLY
setcount2();
donewline();
#else /* XPG6 and Solaris */
setCNL();
#endif /* XPG4ONLY */
vmacchng(0);
(void) delete(0);
inappend = 1;
#ifdef XPG4
/*
* assertion 214(A). If nothing changed,
* set dot to the line preceding the lines
* to be changed.
*/
#else /* XPG4 */
#endif /* XPG4 */
}
inappend = 0;
nochng();
continue;
/* delete */
case 'd':
/*
* Caution: dp and dl have special meaning already.
*/
tail("delete");
c = cmdreg();
#ifdef XPG4ONLY
setcount2();
donewline();
#else /* XPG6 and Solaris */
setCNL();
#endif /* XPG4ONLY */
vmacchng(0);
if (c)
(void) YANKreg(c);
(void) delete(0);
appendnone();
continue;
/* edit */
/* ex */
case 'e':
crflag = -1;
c = 'E';
gotfile = 0;
if (c == 'E') {
filename(c);
gotfile = 1;
}
if (!exclam()) {
ckaw();
xchng = 0;
gettext("No write") :
gettext("No write since "
"last change (:%s! "
"overrides)"),
Command);
}
}
}
if (gotfile == 0)
filename(c);
setnoaddr();
init();
laste++;
sync();
rop(c);
nochng();
continue;
/* file */
case 'f':
tail("file");
setnoaddr();
filename(c);
noonl();
/*
* synctmp();
*/
continue;
/* global */
case 'g':
tail("global");
nochng();
continue;
/* insert */
case 'i':
if (inopen)
goto notinvis;
tail("insert");
setdot();
nonzero();
donewline();
vmacchng(0);
deletenone();
inappend = 1;
inappend = 0;
nochng();
continue;
/* join */
case 'j':
tail("join");
c = exclam();
setcount();
nonzero();
donewline();
vmacchng(0);
#ifdef XPG4ONLY
/*
* if no count was specified, addr1 == addr2. if only
* 1 range arg was specified, inc addr2 to allow
* joining of the next line.
*/
addr2++;
#else /* XPG6 and Solaris */
addr2++;
#endif /* XPG4ONLY */
(void) join(c);
continue;
/* k */
case 'k':
pastwh();
c = getchar();
if (endcmd(c))
(unsigned char *)gettext("Mark what?") :
(unsigned char *)
gettext("%s requires following "
"letter"), Command);
donewline();
if (!islower(c))
gettext("Mark must specify a letter"));
setdot();
nonzero();
anymarks = 1;
continue;
/* list */
case 'l':
tail("list");
#ifdef XPG4ONLY
setcount2();
donewline();
#else /* XPG6 and Solaris */
setCNL();
#endif /* XPG4ONLY */
(void) setlist(1);
pflag = 0;
goto print;
case 'm':
if (peekchar() == 'a') {
ignchar();
if (peekchar() == 'p') {
/* map */
tail2of("map");
setnoaddr();
mapcmd(0, 0);
continue;
}
/* mark */
tail2of("mark");
goto casek;
}
/* move */
tail("move");
vmacchng(0);
vi_move();
continue;
case 'n':
if (peekchar() == 'u') {
tail("number");
goto numberit;
}
/* next */
tail("next");
setnoaddr();
if (!exclam()) {
ckaw();
xchng = 0;
gettext("No write") :
gettext("No write since last "
"change (:%s! overrides)"),
Command);
}
}
if (getargs())
makargs();
next();
c = 'e';
filename(c);
goto doecmd;
/* open */
case 'o':
tail("open");
oop();
pflag = 0;
nochng();
continue;
case 'p':
case 'P':
switch (peekchar()) {
#ifdef TAG_STACK
/* pop */
case 'o':
tail("pop");
if (!inopen)
else
nochng();
continue;
#endif
/* put */
case 'u':
tail("put");
setdot();
c = cmdreg();
eol();
vmacchng(0);
if (c)
(void) putreg(c);
else
(void) put();
continue;
case 'r':
ignchar();
if (peekchar() == 'e') {
/* preserve */
tail2of("preserve");
eol();
if (preserve() == 0)
"Preserve failed!"));
else {
#ifdef XPG4
/*
* error() incs errcnt. this is
* misleading here; and a
* violation of POSIX. so call
* noerror() instead.
* this is for assertion ex:222.
*/
gettext("File preserved."));
#else /* XPG4 */
gettext("File preserved."));
#endif /* XPG4 */
}
}
tail2of("print");
break;
default:
tail("print");
break;
}
/* print */
setCNL();
pflag = 0;
nonzero();
flush1();
vclear();
}
/*
* poffset is nonzero if trailing + or - flags
* were given, and in that case we need to
* adjust dot before printing a line.
*/
if (poffset == 0)
else
continue;
/* quit */
case 'q':
tail("quit");
setnoaddr();
c = quickly();
eol();
if (!c)
quit:
if (nomore())
continue;
if (inopen) {
if (!ateopr())
vnfl();
else {
tostop();
}
flush();
ixlatctl(1);
}
cleanup(1);
case 'r':
if (peekchar() == 'e') {
ignchar();
switch (peekchar()) {
/* rewind */
case 'w':
tail2of("rewind");
setnoaddr();
if (!exclam()) {
ckaw();
/*CSTYLED*/
gettext("No write") :
gettext("No write "
"since last "
"change (:rewi"
/*CSTYLED*/
"nd! overrides)"));
}
eol();
erewind();
next();
c = 'e';
filename(c);
goto doecmd;
/* recover */
case 'c':
tail2of("recover");
setnoaddr();
c = 'e';
c = 'E';
filename(c);
if (c == 'E') {
(void) quickly();
}
init();
laste++;
sync();
recover();
rop2();
revocer();
if (status == 0)
rop3(c);
change();
nochng();
continue;
}
tail2of("read");
} else
tail("read");
/* read */
/* restore crflag for new input text */
crflag = -1;
c = 'e';
pastwh();
vmacchng(0);
if (peekchar() == '!') {
setdot();
ignchar();
unix0(0, 1);
(void) vi_filter(0);
continue;
}
filename(c);
rop(c);
nochng();
continue;
case 's':
switch (peekchar()) {
/*
* Caution: 2nd char cannot be c, g, or r
* because these have meaning to substitute.
*/
/* set */
case 'e':
tail("set");
setnoaddr();
set();
continue;
/* shell */
case 'h':
tail("shell");
setNAEOL();
vnfl();
putpad((unsigned char *)exit_ca_mode);
flush();
resetterm();
vcontin(0);
continue;
/* source */
case 'o':
#ifdef notdef
if (inopen)
goto notinvis;
#endif
tail("source");
setnoaddr();
getone();
eol();
continue;
#ifdef SIGTSTP
/* stop, suspend */
case 't':
tail("stop");
goto suspend;
case 'u':
#ifdef XPG4
/*
* for POSIX, "su" with no other distinguishing
* characteristics, maps to "s". Re. P1003.D11,
* 5.10.7.3.
*
* so, unless the "su" is followed by a "s" or
* a "!", we assume that the user means "s".
*/
switch (d = peekchar()) {
case 's':
case '!':
#endif /* XPG4 */
tail("suspend");
c = exclam();
eol();
if (!c)
ckaw();
onsusp(0);
continue;
#ifdef XPG4
}
#endif /* XPG4 */
#endif
}
/* fall into ... */
/* & */
/* ~ */
/* substitute */
case '&':
case '~':
Command = (unsigned char *)"substitute";
if (c == 's')
vmacchng(0);
if (!substitute(c))
pflag = 0;
continue;
/* t */
case 't':
if (peekchar() == 'a') {
tail("tag");
tagflg = 0;
if (!inopen)
else
nochng();
continue;
}
tail("t");
vmacchng(0);
vi_move();
continue;
case 'u':
if (peekchar() == 'n') {
ignchar();
switch (peekchar()) {
/* unmap */
case 'm':
tail2of("unmap");
setnoaddr();
mapcmd(1, 0);
continue;
/* unabbreviate */
case 'a':
tail2of("unabbreviate");
setnoaddr();
anyabbrs = 1;
continue;
}
/* undo */
tail2of("undo");
} else
tail("undo");
setnoaddr();
markDOT();
c = exclam();
donewline();
undo(c);
continue;
case 'v':
switch (peekchar()) {
case 'e':
/* version */
tail("version");
setNAEOL();
noonl();
continue;
/* visual */
case 'i':
tail("visual");
if (inopen) {
c = 'e';
goto editcmd;
}
vop();
pflag = 0;
nochng();
continue;
}
/* v */
tail("v");
global(0);
nochng();
continue;
/* write */
case 'w':
c = peekchar();
wq:
pofix();
ignchar();
setall();
unix0(0, 1);
(void) vi_filter(1);
} else {
setall();
if (c == 'q')
write_quit = 1;
else
write_quit = 0;
wop(1);
nochng();
}
if (c == 'q')
goto quit;
continue;
/* X: crypt */
case 'X':
goto ent_crypt;
case 'C':
goto ent_crypt;
/* xit */
case 'x':
tail("xit");
if (!chng)
goto quit;
c = 'q';
goto wq;
/* yank */
case 'y':
tail("yank");
c = cmdreg();
#ifdef XPG4ONLY
setcount2();
#else /* XPG6 and Solaris */
setcount();
#endif /* XPG4ONLY */
eol();
vmacchng(0);
if (c)
(void) YANKreg(c);
else
(void) yank();
continue;
/* z */
case 'z':
zop(0);
pflag = 0;
continue;
/* * */
/* @ */
case '*':
case '@':
c = getchar();
if (c == '\n' || c == '\r')
ungetchar(c);
if (any(c, "@*\n\r"))
c = lastmac;
if (isupper(c))
c = tolower(c);
if (!islower(c))
donewline();
setdot();
cmdmac(c);
continue;
/* | */
case '|':
endline = 0;
goto caseline;
/* \n */
case '\n':
endline = 1;
notempty();
if (addr2 == 0) {
!inglobal)
c = CTRL('k');
if (inglobal)
else {
gettext("At EOF") :
gettext("At end-of-file"));
}
}
setdot();
nonzero();
if (seensemi)
if (c == CTRL('k')) {
flush1();
destline--;
if (hadpr)
shudclob = 1;
}
continue;
/* " */
case '"':
comment();
continue;
/* # */
case '#':
setCNL();
(void) setnumb(1);
pflag = 0;
goto print;
/* = */
case '=':
donewline();
setall();
if (inglobal == 2)
pofix();
noonl();
continue;
/* ! */
case '!':
if (addr2 != 0) {
vmacchng(0);
unix0(0, 1);
setdot();
(void) vi_filter(2);
} else {
pofix();
putpad((unsigned char *)exit_ca_mode);
flush();
resetterm();
if (!tagflg) {
} else {
" contains shell escape"));
}
nochng();
}
continue;
/* < */
/* > */
case '<':
case '>':
ignchar();
setCNL();
vmacchng(0);
continue;
/* ^D */
/* EOF */
case CTRL('d'):
case EOF:
if (exitoneof) {
if (addr2 != 0)
return;
}
if (!isatty(0)) {
if (intty)
/*
* Chtty sys call at UCB may cause a
* input which was a tty to suddenly be
*/
onhup(0);
return;
}
if (addr2 != 0) {
setlastchar('\n');
putnl();
}
if (addr2 == 0)
putnl();
notempty();
}
continue;
default:
break;
ungetchar(c);
tailprim((unsigned char *)"", 0, 0);
}
ungetchar(c);
{
int length;
if (length < 0)
gettext("Unknown command character '%s'"),
multic);
}
}
}