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_cmds2.c 1.18 (gritter) 2/17/05";
#endif
#endif
/* from ex_cmds2.c 7.4 (Berkeley) 6/7/85 */
#include "ex.h"
#include "ex_argv.h"
#include "ex_temp.h"
#include "ex_tty.h"
#include "ex_vis.h"
extern bool pflag, nflag; /* mjm: extern; also in ex_cmds.c */
extern int poffset; /* mjm: extern; also in ex_cmds.c */
/*
* Subroutines for major command loop.
*/
/*
* Is there a single letter indicating a named buffer next?
*/
int
cmdreg(void)
{
register int c = 0;
register int wh = skipwh();
if (wh && isalpha(peekchar()))
c = getchar();
return (c);
}
/*
* Tell whether the character ends a command
*/
int
endcmd(int ch)
{
switch (ch) {
case '\n':
case EOF:
endline = 1;
return (1);
case '|':
case '"':
endline = 0;
return (1);
}
return (0);
}
/*
* Insist on the end of the command.
*/
void
eol(void)
{
if (!skipend())
error(catgets(catd, 1, 28,
"Extra chars|Extra characters at end of command"));
ignnEOF();
}
/*
* 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.
*/
void
error0(void)
{
if (vcatch) {
if (splitw == 0)
fixech();
if (!SO || !SE)
dingdong();
return;
}
if (input && exitoneof) {
input = strend(input) - 1;
if (*input == '\n')
setlastchar('\n');
input = 0;
}
setoutt();
flush();
resetflav();
if (!SO || !SE)
dingdong();
if (inopen) {
/*
* We are coming out of open/visual ungracefully.
* Restore TCOLUMNS, undo, and fix tty mode.
*/
TCOLUMNS = OCOLUMNS;
undvis();
ostop(normf);
/* ostop should be doing this
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.
*/
int
error1(char *str)
{
bool die;
if (io > 0) {
close(io);
io = -1;
}
die = (getpid() != ppid); /* Only children die */
inappend = inglobal = 0;
globp = NULL, vmacp = NULL, vglobp = NULL;
if (vcatch && !die) {
inopen = 1;
vcatch = 0;
if (str)
noonl();
fixol();
LONGJMP(vreslab,1);
}
if (str && !vcatch)
putNFL();
if (die)
exitex(1);
if (exitoneof)
lseek(0, (off_t)0, SEEK_END);
if (inglobal)
setlastchar('\n');
while (lastchar() != '\n' && lastchar() != EOF)
ignchar();
ungetchar(0);
endline = 1;
reset();
}
/*
* Print out the message in the error message file at str,
* with i an integer argument to printf.
*/
/*VARARGS2*/
void
error(char *str, ...)
{
va_list ap;
error0();
va_start(ap, str);
vmerror(str, ap);
va_end(ap);
if (writing) {
serror(catgets(catd, 1, 29,
" [Warning - %s is incomplete]"), file);
writing = 0;
}
error1(str);
}
/*
* Same as error(), but using a va_list as argument.
*/
void
verror(char *str, va_list ap)
{
error0();
vmerror(str, ap);
error(NULL);
if (writing) {
serror(catgets(catd, 1, 29,
" [Warning - %s is incomplete]"), file);
writing = 0;
}
error1(str);
}
/*
* Rewind the argument list.
*/
void
erewind(void)
{
argc = argc0;
argv = argv0;
args = args0;
if (argc > 1 && !hush) {
printf(mesg(catgets(catd, 1, 30, "%d files@to edit")), argc);
if (inopen)
putchar(' ');
else
putNFL();
}
}
void
fixol(void)
{
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?
*/
int
exclam(void)
{
if (peekchar() == '!') {
ignchar();
return (1);
}
return (0);
}
/*
* Make an argument list for e.g. next.
*/
void
makargs(void)
{
gglob(&frob);
argc0 = frob.argc0;
argv0 = frob.argv;
args0 = argv0[0];
erewind();
}
/*
* Advance to next file in argument list.
*/
void
next(void)
{
extern short isalt; /* defined in ex_io.c */
if (argc == 0)
error(catgets(catd, 1, 31, "No more files@to edit"));
morargc = argc;
isalt = (strcmp(altfile, args)==0) + 1;
if (savedfile[0])
strcpy(altfile, savedfile);
safecp(savedfile, args, sizeof savedfile, "File name too long");
argc--;
args = argv ? *++argv : strend(args) + 1;
}
/*
* Eat trailing flags and offsets after a command,
* saving for possible later post-command prints.
*/
void
newline(void)
{
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;
case '"':
comment();
setflav();
return;
default:
if (!endcmd(c))
serror(catgets(catd, 1, 32,
"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.
*/
void
nomore(void)
{
if (argc == 0 || morargc == argc)
return;
morargc = argc;
merror(catgets(catd, 1, 33, "%d more file"), argc);
serror(catgets(catd, 1, 34, "%s@to edit"), plural((long) argc));
}
/*
* Before edit of new file check that either an ! follows
* or the file has not been changed.
*/
int
quickly(void)
{
if (exclam())
return (1);
if (chng && dol > zero) {
/*
chng = 0;
*/
xchng = 0;
error(catgets(catd, 1, 35,
"No write@since last change (:%s! overrides)"), Command);
}
return (0);
}
/*
* Reset the flavor of the output to print mode with no numbering.
*/
void
resetflav(void)
{
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.
*/
void
serror(char *str, ...)
{
va_list ap;
if (str == NULL)
return;
va_start(ap, str);
error0();
vsmerror(str, ap);
error1(str);
va_end(ap);
}
/*
* 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.
*/
void
setflav(void)
{
if (inopen)
return;
setnumb(nflag || value(NUMBER));
setlist(listf || value(LIST));
setoutt();
}
/*
* Skip white space and tell whether command ends then.
*/
int
skipend(void)
{
pastwh();
return (endcmd(peekchar()) && peekchar() != '"');
}
/*
* Set the command name for non-word commands.
*/
void
tailspec(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.
*/
void
tail(char *comm)
{
tailprim(comm, 1, 0);
}
void
tail2of(char *comm)
{
tailprim(comm, 2, 0);
}
char tcommand[20];
void
tailprim(register char *comm, int xi, bool notinvis)
{
register char *cp;
register int c;
int i = xi;
Command = comm;
for (cp = tcommand; i > 0; i--)
*cp++ = *comm++;
while (*comm && peekchar() == *comm)
*cp++ = getchar(), comm++;
c = peekchar();
if (notinvis || isalpha(c)
#ifdef BIT8
|| xi == 0 && (c&(0200|QUOTE)) == 0200
#endif
) {
/*
* 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] && (c = peekchar(),
isalpha(c)
#ifdef BIT8
|| xi == 0 && (c&(0200|QUOTE)) == 0200
#endif
))
*cp++ = getchar();
*cp = 0;
if (notinvis)
serror(catgets(catd, 1, 36,
"What?|%s: No such command from open/visual"), tcommand);
else
serror(catgets(catd, 1, 37,
"What?|%s: Not an editor command"), tcommand);
}
ret:
*cp = 0;
}
/*
* Continue after a : command from open/visual.
*/
void
vcontin(bool ask)
{
if (vcnt > 0)
vcnt = -vcnt;
if (inopen) {
if (state != VISUAL) {
/*
* We don't know what a shell command may have left on
* the screen, so we move the cursor to the right place
* and then put out a newline. But this makes an extra
* blank line most of the time so we only do it for :sh
* since the prompt gets left on the screen.
*
* BUG: :!echo longer than current line \\c
* will screw it up, but be reasonable!
*/
if (state == CRTOPEN) {
termreset();
vgoto(WECHO, 0);
}
if (!ask) {
putch('\r');
putch('\n');
}
return;
}
if (ask) {
merror(catgets(catd, 1, 38,
"[Hit return to continue] "));
flush();
}
if (ask) {
#ifdef EATQS
/*
* Gobble ^Q/^S since the tty driver should be eating
* them (as far as the user can see)
*/
while (peekkey(0) == CTRL('Q')
|| peekkey() == CTRL('S'))
ignore(getkey());
#endif
if(getkey() == ':') {
/* Ugh. Extra newlines, but no other way */
putch('\n');
outline = WECHO;
ungetkey(':');
}
}
vclrech(1);
if (Peekkey != ':') {
putpad(TI);
tostart();
/* replaced by ostart.
putpad(VS);
putpad(KS);
*/
}
}
}
/*
* Put out a newline (before a shell escape)
* if in open/visual.
*/
void
vnfl(void)
{
if (inopen) {
if (state != VISUAL && state != CRTOPEN && destline <= WECHO)
vclean();
else
vmoveitup(1, 0);
vgoto(WECHO, 0);
vclrcell(vtube[WECHO], WCOLS);
tostop();
/* replaced by the ostop above
putpad(VE);
putpad(KE);
*/
}
flush();
}