BSD 3 release
[unix-history] / usr / src / cmd / ex / ex_cmds2.c
/* Copyright (c) 1979 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"
bool pflag, nflag;
int poffset;
/*
* Subroutines for major command loop.
*/
/*
* Is there a single letter indicating a named buffer next?
*/
cmdreg()
{
register int c = 0;
register int wh = skipwh();
if (wh && isalpha(peekchar()))
c = getchar();
return (c);
}
/*
* Tell whether the character ends a command
*/
endcmd(ch)
int ch;
{
switch (ch) {
case '\n':
case EOF:
endline = 1;
return (1);
case '|':
endline = 0;
return (1);
}
return (0);
}
/*
* Insist on the end of the command.
*/
eol()
{
if (!skipend())
error("Extra chars|Extra characters at end of command");
ignnEOF();
}
/*
* Print out the message in the error message file at str,
* with i an integer argument to printf.
*/
/*VARARGS2*/
error(str, i)
#ifdef lint
register char *str;
#else
register int str;
#endif
int i;
{
error0();
merror(str, i);
error1(str);
}
/*
* Rewind the argument list.
*/
erewind()
{
argc = argc0;
argv = argv0;
args = args0;
if (argc > 1 && !hush) {
printf(mesg("%d files@to edit"), argc);
if (inopen)
putchar(' ');
else
putNFL();
}
}
/*
* Guts of the pre-printing error processing.
* If in visual and catching errors, then we dont mung up the internals,
* just fixing up the echo area for the print.
* Otherwise we reset a number of externals, and discard unused input.
*/
error0()
{
if (vcatch) {
if (splitw == 0)
fixech();
if (!SO || !SE)
dingdong();
return;
}
if (input) {
input = strend(input) - 1;
if (*input == '\n')
setlastchar('\n');
input = 0;
}
setoutt();
flush();
resetflav();
if (laste) {
laste = 0;
sync();
}
if (!SO || !SE)
dingdong();
if (inopen) {
/*
* We are coming out of open/visual ungracefully.
* Restore COLUMNS, undo, and fix tty mode.
*/
COLUMNS = OCOLUMNS;
undvis();
ostop(normf);
putpad(VE);
putpad(KE);
putnl();
}
inopen = 0;
holdcm = 0;
}
/*
* Post error printing processing.
* Close the i/o file if left open.
* If catching in visual then throw to the visual catch,
* else if a child after a fork, then exit.
* Otherwise, in the normal command mode error case,
* finish state reset, and throw to top.
*/
error1(str)
char *str;
{
bool die;
if (io > 0) {
close(io);
io = -1;
}
die = (getpid() != ppid); /* Only children die */
if (vcatch && !die) {
inglobal = 0;
vglobp = vmacp = 0;
inopen = 1;
vcatch = 0;
fixol();
longjmp(vreslab,1);
}
if (str && !vcatch)
putNFL();
if (die)
exit(1);
lseek(0, 0L, 2);
if (inglobal)
setlastchar('\n');
inglobal = 0;
globp = 0;
while (lastchar() != '\n' && lastchar() != EOF)
ignchar();
ungetchar(0);
endline = 1;
reset();
}
fixol()
{
if (Outchar != vputchar) {
flush();
if (state == ONEOPEN || state == HARDOPEN)
outline = destline = 0;
Outchar = vputchar;
vcontin(1);
} else {
if (destcol)
vclreol();
vclean();
}
}
/*
* Does an ! character follow in the command stream?
*/
exclam()
{
if (peekchar() == '!') {
ignchar();
return (1);
}
return (0);
}
/*
* Make an argument list for e.g. next.
*/
makargs()
{
glob(&frob);
argc0 = frob.argc0;
argv0 = frob.argv;
args0 = argv0[0];
erewind();
}
/*
* Advance to next file in argument list.
*/
next()
{
if (argc == 0)
error("No more files@to edit");
morargc = argc;
if (savedfile[0])
CP(altfile, savedfile);
CP(savedfile, args);
argc--;
args = argv ? *++argv : strend(args) + 1;
}
/*
* Eat trailing flags and offsets after a command,
* saving for possible later post-command prints.
*/
newline()
{
register int c;
resetflav();
for (;;) {
c = getchar();
switch (c) {
case '^':
case '-':
poffset--;
break;
case '+':
poffset++;
break;
case 'l':
listf++;
break;
case '#':
nflag++;
break;
case 'p':
listf = 0;
break;
case ' ':
case '\t':
continue;
default:
if (!endcmd(c))
serror("Extra chars|Extra characters at end of \"%s\" command", Command);
if (c == EOF)
ungetchar(c);
setflav();
return;
}
pflag++;
}
}
/*
* Before quit or respec of arg list, check that there are
* no more files in the arg list.
*/
nomore()
{
if (argc == 0 || morargc == argc)
return;
morargc = argc;
merror("%d more file", argc);
serror("%s@to edit", plural((long) argc));
}
/*
* Before edit of new file check that either an ! follows
* or the file has not been changed.
*/
quickly()
{
if (exclam())
return (1);
if (chng && dol > zero) {
/*
chng = 0;
*/
xchng = 0;
error("No write@since last change (:%s! overrides)", Command);
}
return (0);
}
/*
* Reset the flavor of the output to print mode with no numbering.
*/
resetflav()
{
if (inopen)
return;
listf = 0;
nflag = 0;
pflag = 0;
poffset = 0;
setflav();
}
/*
* Print an error message with a %s type argument to printf.
* Message text comes from error message file.
*/
serror(str, cp)
#ifdef lint
register char *str;
#else
register int str;
#endif
char *cp;
{
error0();
smerror(str, cp);
error1(str);
}
/*
* Set the flavor of the output based on the flags given
* and the number and list options to either number or not number lines
* and either use normally decoded (ARPAnet standard) characters or list mode,
* where end of lines are marked and tabs print as ^I.
*/
setflav()
{
if (inopen)
return;
setnumb(nflag || value(NUMBER));
setlist(listf || value(LIST));
setoutt();
}
/*
* Skip white space and tell whether command ends then.
*/
skipend()
{
pastwh();
return (endcmd(peekchar()));
}
/*
* Set the command name for non-word commands.
*/
tailspec(c)
int c;
{
static char foocmd[2];
foocmd[0] = c;
Command = foocmd;
}
/*
* Try to read off the rest of the command word.
* If alphabetics follow, then this is not the command we seek.
*/
tail(comm)
char *comm;
{
tailprim(comm, 1, 0);
}
tail2of(comm)
char *comm;
{
tailprim(comm, 2, 0);
}
char tcommand[20];
tailprim(comm, i, notinvis)
register char *comm;
int i;
bool notinvis;
{
register char *cp;
register int c;
Command = comm;
for (cp = tcommand; i > 0; i--)
*cp++ = *comm++;
while (*comm && peekchar() == *comm)
*cp++ = getchar(), comm++;
c = peekchar();
if (notinvis || isalpha(c)) {
/*
* Of the trailing lp funny business, only dl and dp
* survive the move from ed to ex.
*/
if (tcommand[0] == 'd' && any(c, "lp"))
goto ret;
if (tcommand[0] == 's' && any(c, "gcr"))
goto ret;
while (cp < &tcommand[19] && isalpha(peekchar()))
*cp++ = getchar();
*cp = 0;
if (notinvis)
serror("What?|%s: No such command from open/visual", tcommand);
else
serror("What?|%s: Not an editor command", tcommand);
}
ret:
*cp = 0;
}
/*
* Continue after a shell escape from open/visual.
*/
vcontin(ask)
bool ask;
{
if (vcnt > 0)
vcnt = -vcnt;
if (inopen) {
if (state != VISUAL) {
/*
vtube[WECHO][0] = '*';
vnfl();
*/
return;
}
if (ask) {
merror("[Hit return to continue] ");
flush();
}
#ifndef CBREAK
vraw();
#endif
if (ask) {
/*
* Gobble ^Q/^S since the tty driver should be eating
* them (as far as the user can see)
*/
while (peekkey() == CTRL(Q) || peekkey() == CTRL(S))
ignore(getkey());
if(getkey() == ':')
ungetkey(':');
}
putpad(VS);
putpad(KS);
}
}
/*
* Put out a newline (before a shell escape)
* if in open/visual.
*/
vnfl()
{
if (inopen) {
if (state != VISUAL && state != CRTOPEN && destline <= WECHO)
vclean();
else
vmoveitup(1, 0);
vgoto(WECHO, 0);
vclrbyte(vtube[WECHO], WCOLS);
putpad(VE);
putpad(KE);
}
flush();
}