mirror of
https://github.com/tildeclub/ex-vi.git
synced 2026-06-21 11:29:24 +00:00
Initial revision
This commit is contained in:
673
ex_cmds2.c
Normal file
673
ex_cmds2.c
Normal file
@@ -0,0 +1,673 @@
|
||||
/*
|
||||
* 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.17 (gritter) 12/1/04";
|
||||
#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) {
|
||||
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);
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user