511 lines
9.8 KiB
C
511 lines
9.8 KiB
C
/* main.c */
|
|
|
|
/* Author:
|
|
* Steve Kirkendall
|
|
* 14407 SW Teal Blvd. #C
|
|
* Beaverton, OR 97005
|
|
* kirkenda@cs.pdx.edu
|
|
*/
|
|
|
|
|
|
/* This file contains the main() function of vi */
|
|
|
|
/* HACK! bcc needs to disable use of precompiled headers for this file,
|
|
or else command line args will not be passed to elvis */
|
|
#if __BORLANDC__
|
|
#include "borland.h"
|
|
#endif
|
|
|
|
#include "config.h"
|
|
#include <setjmp.h>
|
|
#include "vi.h"
|
|
|
|
extern SIGTYPE trapint(); /* defined below */
|
|
jmp_buf jmpenv;
|
|
|
|
#ifndef NO_DIGRAPH
|
|
static init_digraphs();
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
|
|
#if AMIGA
|
|
# include "amiwild.c"
|
|
main (argc, argv)
|
|
#else
|
|
# if VMS
|
|
# include "vmswild.c"
|
|
main (argc, argv)
|
|
# else
|
|
void main(argc, argv)
|
|
# endif
|
|
#endif
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int i;
|
|
char *cmd = (char *)0;
|
|
char *err = (char *)0;
|
|
char *str;
|
|
char *tag = (char *)0;
|
|
|
|
/* set mode to MODE_VI or MODE_EX depending on program name */
|
|
switch (argv[0][strlen(argv[0]) - 1])
|
|
{
|
|
case 'x': /* "ex" */
|
|
mode = MODE_EX;
|
|
break;
|
|
|
|
case 'w': /* "view" */
|
|
mode = MODE_VI;
|
|
*o_readonly = TRUE;
|
|
break;
|
|
#ifndef NO_EXTENSIONS
|
|
case 't': /* "edit" or "input" */
|
|
mode = MODE_VI;
|
|
*o_inputmode = TRUE;
|
|
break;
|
|
#endif
|
|
default: /* "vi" or "elvis" */
|
|
mode = MODE_VI;
|
|
}
|
|
|
|
#ifndef DEBUG
|
|
# ifdef SIGQUIT
|
|
/* normally, we ignore SIGQUIT. SIGINT is trapped later */
|
|
signal(SIGQUIT, SIG_IGN);
|
|
# endif
|
|
#endif
|
|
|
|
/* temporarily ignore SIGINT */
|
|
signal(SIGINT, SIG_IGN);
|
|
|
|
/* start curses */
|
|
initscr();
|
|
cbreak();
|
|
noecho();
|
|
scrollok(stdscr, TRUE);
|
|
|
|
/* arrange for deadly signals to be caught */
|
|
# ifdef SIGHUP
|
|
signal(SIGHUP, deathtrap);
|
|
# endif
|
|
# ifndef DEBUG
|
|
# ifdef SIGILL
|
|
signal(SIGILL, deathtrap);
|
|
# endif
|
|
# ifdef SIGBUS
|
|
signal(SIGBUS, deathtrap);
|
|
# endif
|
|
# ifdef SIGSEGV
|
|
signal(SIGSEGV, deathtrap);
|
|
# endif
|
|
# ifdef SIGSYS
|
|
signal(SIGSYS, deathtrap);
|
|
# endif
|
|
# endif /* !DEBUG */
|
|
# ifdef SIGPIPE
|
|
signal(SIGPIPE, deathtrap);
|
|
# endif
|
|
# ifdef SIGTERM
|
|
signal(SIGTERM, deathtrap);
|
|
# endif
|
|
# ifdef SIGUSR1
|
|
signal(SIGUSR1, deathtrap);
|
|
# endif
|
|
# ifdef SIGUSR2
|
|
signal(SIGUSR2, deathtrap);
|
|
# endif
|
|
|
|
/* initialize the options - must be done after initscr(), so that
|
|
* we can alter LINES and COLS if necessary.
|
|
*/
|
|
initopts();
|
|
|
|
/* map the arrow keys. The KU,KD,KL,and KR variables correspond to
|
|
* the :ku=: (etc.) termcap capabilities. The variables are defined
|
|
* as part of the curses package.
|
|
*/
|
|
if (has_KU) mapkey(has_KU, "k", WHEN_VICMD|WHEN_INMV, "<Up>");
|
|
if (has_KD) mapkey(has_KD, "j", WHEN_VICMD|WHEN_INMV, "<Down>");
|
|
if (has_KL) mapkey(has_KL, "h", WHEN_VICMD|WHEN_INMV, "<Left>");
|
|
if (has_KR) mapkey(has_KR, "l", WHEN_VICMD|WHEN_INMV, "<Right>");
|
|
if (has_HM) mapkey(has_HM, "^", WHEN_VICMD|WHEN_INMV, "<Home>");
|
|
if (has_EN) mapkey(has_EN, "$", WHEN_VICMD|WHEN_INMV, "<End>");
|
|
if (has_PU) mapkey(has_PU, "\002", WHEN_VICMD|WHEN_INMV, "<PageUp>");
|
|
if (has_PD) mapkey(has_PD, "\006", WHEN_VICMD|WHEN_INMV, "<PageDn>");
|
|
if (has_KI) mapkey(has_KI, "i", WHEN_VICMD|WHEN_INMV, "<Insert>");
|
|
#if MSDOS
|
|
# if RAINBOW
|
|
if (!strcmp("rainbow", o_term))
|
|
{
|
|
mapkey("\033[1~", "/", WHEN_VICMD, "<Find>");
|
|
mapkey("\033[3~", "x", WHEN_VICMD|WHEN_INMV, "<Remove>");
|
|
mapkey("\033[4~", "v", WHEN_VICMD|WHEN_INMV, "<Select>");
|
|
mapkey("\033[17~", ":sh\n", WHEN_VICMD, "<Intrpt>");
|
|
mapkey("\033[19~", ":q\n", WHEN_VICMD, "<Cancel>");
|
|
mapkey("\033[21~", "ZZ", WHEN_VICMD, "<Exit>");
|
|
mapkey("\033[26~", "V", WHEN_VICMD|WHEN_INMV, "<AddlOp>");
|
|
mapkey("\033[28~", "\\", WHEN_VICMD|WHEN_INMV, "<Help>");
|
|
mapkey("\033[29~", "K", WHEN_VICMD|WHEN_INMV, "<Do>");
|
|
}
|
|
else
|
|
# endif /* RAINBOW */
|
|
{
|
|
mapkey("#S", "x", WHEN_VICMD|WHEN_INMV, "<Delete>");
|
|
mapkey("#s", "B", WHEN_VICMD|WHEN_INMV, "^<Left>");
|
|
mapkey("#t", "W", WHEN_VICMD|WHEN_INMV, "^<Right>");
|
|
}
|
|
#else /* not MSDOS */
|
|
# if COHERENT
|
|
mapkey("\033[P", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
|
|
# else
|
|
#if AMIGA
|
|
mapkey("\233?~", "\\", WHEN_VICMD|WHEN_INMV, "<Help>");
|
|
#endif
|
|
|
|
if (ERASEKEY != '\177')
|
|
{
|
|
mapkey("\177", "x", WHEN_VICMD|WHEN_INMV, "<Del>");
|
|
}
|
|
# endif
|
|
#endif
|
|
|
|
#ifndef NO_DIGRAPH
|
|
init_digraphs();
|
|
#endif /* NO_DIGRAPH */
|
|
|
|
/* process any flags */
|
|
for (i = 1; i < argc && *argv[i] == '-'; i++)
|
|
{
|
|
switch (argv[i][1])
|
|
{
|
|
case 'R': /* readonly */
|
|
*o_readonly = TRUE;
|
|
break;
|
|
|
|
case 'L':
|
|
case 'r': /* recover */
|
|
msg("Use the `elvrec` program to recover lost files");
|
|
endmsgs();
|
|
refresh();
|
|
endwin();
|
|
exit(1);
|
|
break;
|
|
|
|
case 't': /* tag */
|
|
if (argv[i][2])
|
|
{
|
|
tag = argv[i] + 2;
|
|
}
|
|
else
|
|
{
|
|
tag = argv[++i];
|
|
}
|
|
break;
|
|
|
|
case 'v': /* vi mode */
|
|
mode = MODE_VI;
|
|
break;
|
|
|
|
case 'e': /* ex mode */
|
|
mode = MODE_EX;
|
|
break;
|
|
#ifndef NO_EXTENSIONS
|
|
case 'i': /* input mode */
|
|
*o_inputmode = TRUE;
|
|
break;
|
|
#endif
|
|
#ifndef NO_ERRLIST
|
|
case 'm': /* use "errlist" as the errlist */
|
|
if (argv[i][2])
|
|
{
|
|
err = argv[i] + 2;
|
|
}
|
|
else if (i + 1 < argc)
|
|
{
|
|
err = argv[++i];
|
|
}
|
|
else
|
|
{
|
|
err = "";
|
|
}
|
|
break;
|
|
#endif
|
|
#ifndef CRUNCH
|
|
case 'c': /* run the following command, later */
|
|
if (argv[i][2])
|
|
{
|
|
cmd = argv[i] + 2;
|
|
}
|
|
else
|
|
{
|
|
cmd = argv[++i];
|
|
}
|
|
break;
|
|
|
|
case 'w': /* set the window size */
|
|
if (argv[i][2])
|
|
{
|
|
*o_window = atoi(argv[i] + 2);
|
|
wset = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*o_window = atoi(argv[++i]);
|
|
wset = TRUE;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
msg("Ignoring unknown flag \"%s\"", argv[i]);
|
|
}
|
|
}
|
|
|
|
/* if we were given an initial ex command, save it... */
|
|
if (i < argc && *argv[i] == '+')
|
|
{
|
|
if (argv[i][1])
|
|
{
|
|
cmd = argv[i++] + 1;
|
|
}
|
|
else
|
|
{
|
|
cmd = "$"; /* "vi + file" means start at EOF */
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* the remaining args are file names. */
|
|
if (i < argc)
|
|
{
|
|
strcpy(args, argv[i]);
|
|
while (++i < argc && strlen(args) + 1 + strlen(argv[i]) < sizeof args)
|
|
{
|
|
strcat(args, " ");
|
|
strcat(args, argv[i]);
|
|
}
|
|
#if MSDOS || TOS
|
|
/* expand wildcard characters, if necessary */
|
|
if (strchr(args, '*') || strchr(args, '?'))
|
|
{
|
|
strcpy(args, wildcard(args));
|
|
}
|
|
#endif
|
|
strcpy(tmpblk.c, args);
|
|
cmd_args(MARK_UNSET, MARK_UNSET, CMD_ARGS, TRUE, tmpblk.c);
|
|
}
|
|
else
|
|
{
|
|
/* empty args list */
|
|
args[0] = '\0';
|
|
nargs = 1;
|
|
argno = -1;
|
|
}
|
|
|
|
/* perform the .exrc files and EXINIT environment variable */
|
|
#ifdef SYSEXRC
|
|
doexrc(SYSEXRC);
|
|
#endif
|
|
#ifdef HMEXRC
|
|
str = gethome(argv[0]);
|
|
if (str && *str)
|
|
{
|
|
strcpy(tmpblk.c, str);
|
|
str = tmpblk.c + strlen(tmpblk.c);
|
|
#if !VMS
|
|
# if AMIGA /* Don't SLASH a device. "Elvis:.exrc" */
|
|
if (str[-1] != COLON && str[-1] != SLASH)
|
|
# else
|
|
if (str[-1] != SLASH)
|
|
# endif
|
|
{
|
|
*str++ = SLASH;
|
|
}
|
|
#endif
|
|
strcpy(str, HMEXRC);
|
|
doexrc(tmpblk.c);
|
|
}
|
|
#endif
|
|
#ifndef CRUNCH
|
|
if (*o_exrc)
|
|
#endif
|
|
{
|
|
doexrc(EXRC);
|
|
}
|
|
#ifdef EXINIT
|
|
str = getenv(EXINIT);
|
|
if (str)
|
|
{
|
|
exstring(str, strlen(str), ctrl('V'));
|
|
}
|
|
#endif
|
|
|
|
/* search for a tag (or an error) now, if desired */
|
|
blkinit();
|
|
if (tag)
|
|
{
|
|
cmd_tag(MARK_UNSET, MARK_FIRST, CMD_TAG, 0, tag);
|
|
}
|
|
#ifndef NO_ERRLIST
|
|
else if (err)
|
|
{
|
|
cmd_errlist(MARK_FIRST, MARK_FIRST, CMD_ERRLIST, 0, err);
|
|
}
|
|
#endif
|
|
|
|
/* if no tag/err, or tag failed, then start with first arg */
|
|
if (tmpfd < 0)
|
|
{
|
|
/* start with first arg */
|
|
cmd_next(MARK_UNSET, MARK_UNSET, CMD_NEXT, FALSE, "");
|
|
|
|
/* pretend to do something, just to force a recoverable
|
|
* version of the file out to disk
|
|
*/
|
|
ChangeText
|
|
{
|
|
}
|
|
clrflag(file, MODIFIED);
|
|
}
|
|
|
|
/* now we do the immediate ex command that we noticed before */
|
|
if (cmd)
|
|
{
|
|
doexcmd(cmd);
|
|
}
|
|
|
|
/* repeatedly call ex() or vi() (depending on the mode) until the
|
|
* mode is set to MODE_QUIT
|
|
*/
|
|
while (mode != MODE_QUIT)
|
|
{
|
|
if (setjmp(jmpenv))
|
|
{
|
|
/* Maybe we just aborted a change? */
|
|
abortdo();
|
|
}
|
|
signal(SIGINT, trapint);
|
|
|
|
switch (mode)
|
|
{
|
|
case MODE_VI:
|
|
vi();
|
|
break;
|
|
|
|
case MODE_EX:
|
|
ex();
|
|
break;
|
|
#ifdef DEBUG
|
|
default:
|
|
msg("mode = %d?", mode);
|
|
mode = MODE_QUIT;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* free up the cut buffers */
|
|
cutend();
|
|
|
|
/* end curses */
|
|
#ifndef NO_CURSORSHAPE
|
|
if (has_CQ)
|
|
do_CQ();
|
|
#endif
|
|
endmsgs();
|
|
move(LINES - 1, 0);
|
|
clrtoeol();
|
|
refresh();
|
|
endwin();
|
|
|
|
exit(exitcode);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
|
|
/*ARGSUSED*/
|
|
SIGTYPE trapint(signo)
|
|
int signo;
|
|
{
|
|
beep();
|
|
resume_curses(FALSE);
|
|
abortdo();
|
|
#if OSK
|
|
sigmask(-1);
|
|
#endif
|
|
signal(signo, trapint);
|
|
doingglobal = FALSE;
|
|
|
|
longjmp(jmpenv, 1);
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_DIGRAPH
|
|
|
|
/* This stuff us used to build the default digraphs table. */
|
|
static char digtable[][4] =
|
|
{
|
|
# ifdef CS_IBMPC
|
|
"C,\200", "u\"\1", "e'\2", "a^\3",
|
|
"a\"\4", "a`\5", "a@\6", "c,\7",
|
|
"e^\10", "e\"\211", "e`\12", "i\"\13",
|
|
"i^\14", "i`\15", "A\"\16", "A@\17",
|
|
"E'\20", "ae\21", "AE\22", "o^\23",
|
|
"o\"\24", "o`\25", "u^\26", "u`\27",
|
|
"y\"\30", "O\"\31", "U\"\32", "a'\240",
|
|
"i'!", "o'\"", "u'#", "n~$",
|
|
"N~%", "a-&", "o-'", "~?(",
|
|
"~!-", "\"<.", "\">/",
|
|
# ifdef CS_SPECIAL
|
|
"2/+", "4/,", "^+;", "^q<",
|
|
"^c=", "^r>", "^t?", "pp]",
|
|
"^^^", "oo_", "*a`", "*ba",
|
|
"*pc", "*Sd", "*se", "*uf",
|
|
"*tg", "*Ph", "*Ti", "*Oj",
|
|
"*dk", "*Hl", "*hm", "*En",
|
|
"*No", "eqp", "pmq", "ger",
|
|
"les", "*It", "*iu", "*/v",
|
|
"*=w", "sq{", "^n|", "^2}",
|
|
"^3~", "^_\377",
|
|
# endif /* CS_SPECIAL */
|
|
# endif /* CS_IBMPC */
|
|
# ifdef CS_LATIN1
|
|
"~!!", "a-*", "\">+", "o-:",
|
|
"\"<>", "~??",
|
|
|
|
"A`@", "A'A", "A^B", "A~C",
|
|
"A\"D", "A@E", "AEF", "C,G",
|
|
"E`H", "E'I", "E^J", "E\"K",
|
|
"I`L", "I'M", "I^N", "I\"O",
|
|
"-DP", "N~Q", "O`R", "O'S",
|
|
"O^T", "O~U", "O\"V", "O/X",
|
|
"U`Y", "U'Z", "U^[", "U\"\\",
|
|
"Y'_",
|
|
|
|
"a``", "a'a", "a^b", "a~c",
|
|
"a\"d", "a@e", "aef", "c,g",
|
|
"e`h", "e'i", "e^j", "e\"k",
|
|
"i`l", "i'm", "i^n", "i\"o",
|
|
"-dp", "n~q", "o`r", "o's",
|
|
"o^t", "o~u", "o\"v", "o/x",
|
|
"u`y", "u'z", "u^{", "u\"|",
|
|
"y'~",
|
|
# endif /* CS_LATIN1 */
|
|
""
|
|
};
|
|
|
|
static int init_digraphs()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; *digtable[i]; i++)
|
|
{
|
|
do_digraph(FALSE, digtable[i]);
|
|
}
|
|
do_digraph(FALSE, (char *)0);
|
|
return 0;
|
|
}
|
|
#endif /* NO_DIGRAPH */
|