gno/bin/vi/main.c

376 lines
9.3 KiB
C

/*
* STEVIE - Simply Try this Editor for VI Enthusiasts
*
* Code Contributions By : Tim Thompson twitch!tjt
* Tony Andrews onecom!wldrdg!tony
* G. R. (Fred) Walter watmath!grwalter
*/
#ifdef __ORCAC__
#pragma stacksize 2048
#define MAINSEG
#include <stdio.h>
#include <gno/gno.h>
#include <gno/signal.h>
#endif
#ifdef AMIGA
# include <proto/exec.h>
#endif
#include "stevie.h"
#ifdef AMIGA
int Aux_Device = FALSE;
#endif
int Rows; /* Number of Rows and Columns */
int Columns; /* in the current window. */
int CheckTopcharAndBotchar = FALSE;
int MustUpdateBotchar = FALSE;
int ValidToCurschar = FALSE;
int LineNotValid = FALSE;
int NumLineSizes = -1; /* # of active LineSizes */
LINE **LinePointers = NULL; /* Pointer to the line for LineSizes */
char *LineSizes = NULL; /* Size of a line (pline output) */
char *Filename = NULL;/* Current file name */
LPtr *Filemem; /* The contents of the file, as a single
* array. */
LPtr *Filetop; /* Line 'above' the start of the file */
LPtr *Fileend; /* Pointer to the end of the file in Filemem.
* (It points to the byte AFTER the last
* byte.) */
LPtr *Topchar; /* Pointer to the byte in Filemem which is in
* the upper left corner of the screen. */
LPtr *Botchar; /* Pointer to the byte in Filemem which is
* just off the bottom of the screen. */
LPtr *Curschar; /* Pointer to byte in Filemem at which the
* cursor is currently placed. */
int Curscol; /* Current position of cursor (column) */
int Cursrow; /* Current position of cursor (row) */
int Cursvcol; /* Current virtual column, the column number
* of the file's actual line, as opposed to
* the column number we're at on the screen.
* This makes a difference on lines that span
* more than one screen line. */
int Curswant = 0; /* The column we'd like to be at. This is
* used try to stay in the same column
* through up/down cursor motions. */
bool_t set_want_col; /* If set, then update Curswant the next time
* through cursupdate() to the current
* virtual column. */
int State = NORMAL; /* This is the current state of the command
* interpreter. */
int Prenum = 0; /* The (optional) number before a command. */
LPtr *Insstart; /* This is where the latest insert/append
* mode started. */
bool_t Changed = FALSE;/* Set to TRUE if something in the file has
* been changed and not written out. */
char *IObuff; /* file reads are done, one line at a time,
* into this buffer; as well as sprintf's */
char *Insbuffptr = NULL;
char *Insbuff; /* Each insertion gets stuffed into this
* buffer. */
char *Readbuffptr = NULL;
char *Readbuff; /* Having this buffer allows STEVIE to easily
* make itself do commands */
char *Redobuffptr = NULL;
char *Redobuff; /* Each command should stuff characters into
* this buffer that will re-execute itself. */
bool_t UndoInProgress = FALSE; /* Set to TRUE if undo'ing */
char *Undobuffptr = NULL;
char *Undobuff; /* Each command should stuff characters into
* this buffer that will undo its effects. */
char *UndoUndobuffptr = NULL;
char *UndoUndobuff; /* Each command should stuff characters into
* this buffer that will undo its undo. */
char *Yankbuffptr = NULL;
char *Yankbuff; /* Yank buffer */
char last_command = NUL; /* last command */
char last_command_char = NUL; /* character needed to undo
* last command */
bool_t RedrawingDisabled = FALSE; /* Set to TRUE if undo'ing or
* put'ing */
char **files = NULL; /* list of input files */
int numfiles = 0; /* number of input files */
int curfile; /* number of the current file */
static void
usage(void)
{
fprintf(stderr, "usage: stevie [file ...]\n");
fprintf(stderr, " stevie -t tag\n");
fprintf(stderr, " stevie +[num] file\n");
fprintf(stderr, " stevie +/pat file\n");
exit(1);
}
#ifdef AMIGA
void
#else
int
#endif
main(int argc, char **argv)
{
char *initstr; /* init string from the environment */
char *tag = NULL; /* tag from command line */
char *pat = NULL; /* pattern from command line */
int line = -1; /* line number from command line */
int atoi(char *);
char *getenv(char *);
#ifdef __ORCAC__
{
extern void stopHandler(int,int);
signal(SIGINT, SIG_IGN); /* vi should ignore ^C requests */
signal(SIGTSTP, stopHandler); /* handle ^Z with a message */
}
#endif
#ifdef AMIGA
{
struct Library *DosBase;/* Used for checking version */
DosBase = OpenLibrary("dos.library", 33);
if (!DosBase) {
fprintf(stderr,
"\nSTEVIE requires Version 33 or later of dos.library.\n");
exit(2);
} else {
CloseLibrary(DosBase);
}
/*
* I don't think STEVIE should be exited with a break.
*/
(void) signal(SIGINT, SIG_IGN);
}
#endif
/*
* Process the command line arguments.
*/
if (argc > 1) {
switch (argv[1][0]) {
case '-': /* -t tag */
if (argv[1][1] != 't')
usage();
if (argv[2] == NULL)
usage();
tag = argv[2];
numfiles = 1;
break;
case '+': /* +n or +/pat */
if (argv[1][1] == '/') {
if (argv[2] == NULL)
usage();
Filename = strsave(argv[2]);
pat = &(argv[1][1]);
numfiles = 1;
} else if (isdigit(argv[1][1]) || argv[1][1] == NUL) {
if (argv[2] == NULL)
usage();
Filename = strsave(argv[2]);
numfiles = 1;
line = (isdigit(argv[1][1])) ?
atoi(&(argv[1][1])) : 0;
} else
usage();
break;
default: /* must be a file name */
#ifdef WILD_CARDS
ExpandWildCards(argc - 1, &(argv[1]), &numfiles, &files);
if (numfiles == 0)
numfiles = 1;
else
Filename = strsave(files[0]);
#else
Filename = strsave(argv[1]);
files = &(argv[1]);
numfiles = argc - 1;
#endif
if (numfiles > 1)
printf("%d files to edit\n", numfiles);
break;
}
} else {
numfiles = 1;
}
curfile = 0;
windinit();
/*
* Allocate LPtr structures for all the various position pointers and for
* the many buffers.
*/
Filetop = (LPtr *) alloc((unsigned) sizeof(LPtr));
Filemem = (LPtr *) alloc((unsigned) sizeof(LPtr));
Fileend = (LPtr *) alloc((unsigned) sizeof(LPtr));
Topchar = (LPtr *) alloc((unsigned) sizeof(LPtr));
Curschar = (LPtr *) alloc((unsigned) sizeof(LPtr));
Botchar = (LPtr *) alloc((unsigned) sizeof(LPtr));
Insstart = (LPtr *) alloc((unsigned) sizeof(LPtr));
IObuff = alloc(IOSIZE);
Insbuff = alloc(INSERT_SIZE);
Readbuff = alloc(READSIZE);
Redobuff = alloc(REDO_UNDO_SIZE);
Undobuff = alloc(REDO_UNDO_SIZE);
UndoUndobuff = alloc(REDO_UNDO_SIZE);
Yankbuff = alloc(YANKSIZE);
if (Filetop == NULL ||
Filemem == NULL ||
Fileend == NULL ||
Topchar == NULL ||
Curschar == NULL ||
Botchar == NULL ||
Insstart == NULL ||
IObuff == NULL ||
Insbuff == NULL ||
Readbuff == NULL ||
Redobuff == NULL ||
Undobuff == NULL ||
UndoUndobuff == NULL ||
Yankbuff == NULL) {
fprintf(stderr, "Can't allocate data structures\n");
windexit(0);
}
screenalloc();
filealloc(); /* Initialize Filemem, Filetop & Fileend */
s_clear();
initstr = getenv("EXINIT");
if (initstr != NULL) {
char *lp, buf[128];
lp = getenv("LINES");
if (lp != NULL) {
sprintf(buf, "%s lines=%s", initstr, lp);
readcmdline(':', buf);
} else
readcmdline(':', initstr);
}
if (Filename != NULL) {
if (readfile(Filename, Filemem, FALSE))
filemess("[New File]");
} else {
s_refresh(NOT_VALID);
msg("Empty Buffer");
}
setpcmark();
if (tag) {
stuffReadbuff(":ta ");
stuffReadbuff(tag);
stuffReadbuff("\n");
} else if (pat) {
stuffReadbuff(pat);
stuffReadbuff("\n");
} else if (line >= 0) {
if (line > 0)
stuffnumReadbuff(line);
stuffReadbuff("G");
}
edit();
/* NOTREACHED */
/* windexit(0); */
}
void
stuffReadbuff(char *s)
{
if (Readbuffptr == NULL) {
if ((strlen(s) + 1) < READSIZE) {
strcpy(Readbuff, s);
Readbuffptr = Readbuff;
return;
}
} else if ((strlen(Readbuff) + (strlen(s) + 1)) < READSIZE) {
strcat(Readbuff, s);
return;
}
emsg("Couldn't stuffReadbuff() - clearing Readbuff\n");
*Readbuff = NUL;
Readbuffptr = NULL;
}
void
stuffnumReadbuff(int n)
{
char buf[32];
sprintf(buf, "%d", n);
stuffReadbuff(buf);
}
/* OPTRESULT */
char
vgetc(void)
{
int c;
/*
* inchar() may map special keys by using stuffReadbuff(). If it does so,
* it returns -1 so we know to loop here to get a real char.
*/
do {
if (Readbuffptr != NULL) {
char nextc = *Readbuffptr++;
if (*Readbuffptr == NUL) {
*Readbuff = NUL;
Readbuffptr = NULL;
}
return (nextc);
}
c = inchar();
} while (c == -1);
return (char) c;
}
char
vpeekc(void)
{
if (Readbuffptr != NULL)
return (*Readbuffptr);
return (NUL);
}