415 lines
12 KiB
C
415 lines
12 KiB
C
/* $Header: /nw/tony/src/stevie/src/RCS/main.c,v 1.12 89/08/02 19:53:27 tony Exp $
|
|
*
|
|
* The main routine and routines to deal with the input buffer.
|
|
*/
|
|
|
|
#include "stevie.h"
|
|
|
|
int Rows; /* Number of Rows and Columns */
|
|
int Columns; /* in the current window. */
|
|
|
|
char INITFILENAME[] = "ntvi.ini"; /* file that's source'd at startup */
|
|
|
|
char *Realscreen = NULL; /* What's currently on the screen, a single */
|
|
/* array of size Rows*Columns. */
|
|
char *Nextscreen = NULL; /* What's to be put on the screen. */
|
|
|
|
char *Filename = NULL; /* Current file name */
|
|
|
|
char *Appname = NULL; /* Name of program (vi, for instance) */
|
|
|
|
LNPTR *Filemem; /* Pointer to the first line of the file */
|
|
|
|
LNPTR *Filetop; /* Line 'above' the start of the file */
|
|
|
|
LNPTR *Fileend; /* Pointer to the end of the file in Filemem. */
|
|
/* (It points to the byte AFTER the last byte.) */
|
|
|
|
LNPTR *Topchar; /* Pointer to the byte in Filemem which is */
|
|
/* in the upper left corner of the screen. */
|
|
|
|
LNPTR *Botchar; /* Pointer to the byte in Filemem which is */
|
|
/* just off the bottom of the screen. */
|
|
|
|
LNPTR *Curschar; /* Pointer to byte in Filemem at which the */
|
|
/* cursor is currently placed. */
|
|
|
|
int Cursrow, Curscol; /* Current position of cursor */
|
|
|
|
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. */
|
|
int namedbuff = -1; /* the (optional) named buffer before a command */
|
|
|
|
LNPTR *Insstart; /* This is where the latest insert/append */
|
|
/* mode started. */
|
|
|
|
bool_t Changed = 0; /* Set to 1 if something in the file has been */
|
|
/* changed and not written out. */
|
|
|
|
char *Redobuff; /* Each command should stuff characters into this */
|
|
/* buffer that will re-execute itself. */
|
|
|
|
char *Insbuff; /* Each insertion gets stuffed into this buffer. */
|
|
int InsbuffSize;
|
|
|
|
int Ninsert = 0; /* Number of characters in the current insertion. */
|
|
char *Insptr = NULL;
|
|
|
|
bool_t got_int=FALSE; /* set to TRUE when an interrupt occurs (if possible) */
|
|
|
|
bool_t interactive = FALSE; /* set TRUE when main() is ready to roll */
|
|
|
|
char **files; /* list of input files */
|
|
int numfiles; /* number of input files */
|
|
int curfile; /* number of the current file */
|
|
|
|
static char *getcbuff;
|
|
static char *getcnext = NULL;
|
|
|
|
static void chk_mline();
|
|
|
|
static void
|
|
usage()
|
|
{
|
|
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);
|
|
}
|
|
|
|
__cdecl main(argc,argv)
|
|
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 */
|
|
char *p1, *p2;
|
|
|
|
p1 = strrchr(argv[0], '\\');
|
|
if (!p1)
|
|
p1 = strrchr(argv[0], ':');
|
|
if (p1)
|
|
p1++;
|
|
else
|
|
p1 = argv[0];
|
|
p2 = strrchr(p1, '.');
|
|
if (!p2)
|
|
Appname = strsave(p1);
|
|
else {
|
|
Appname = malloc((size_t)(p2-p1+1));
|
|
strncpy(Appname, p1, (size_t)(p2-p1));
|
|
Appname[p2-p1] = '\0';
|
|
}
|
|
|
|
/*
|
|
* 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();
|
|
|
|
Filename = NULL;
|
|
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 */
|
|
Filename = strsave(argv[1]);
|
|
files = &(argv[1]);
|
|
numfiles = argc - 1;
|
|
break;
|
|
}
|
|
} else {
|
|
Filename = NULL;
|
|
numfiles = 1;
|
|
}
|
|
curfile = 0;
|
|
|
|
if (numfiles > 1)
|
|
fprintf(stderr, "%d files to edit\n", numfiles);
|
|
|
|
windinit();
|
|
|
|
/*
|
|
* Allocate LNPTR structures for all the various position pointers
|
|
*/
|
|
if ((Filemem = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ||
|
|
(Filetop = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ||
|
|
(Fileend = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ||
|
|
(Topchar = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ||
|
|
(Botchar = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ||
|
|
(Curschar = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ||
|
|
(Insstart = (LNPTR *) malloc(sizeof(LNPTR))) == NULL ) {
|
|
fprintf(stderr, "Can't allocate data structures\n");
|
|
windexit(0);
|
|
}
|
|
|
|
screenalloc();
|
|
filealloc(); /* Initialize Filemem, Filetop, and Fileend */
|
|
inityank();
|
|
|
|
getcbuff = malloc(1);
|
|
if(((getcbuff = malloc(1 )) == NULL)
|
|
|| ((Redobuff = malloc(REDOBUFFMIN)) == NULL)
|
|
|| ((Insbuff = malloc(INSERTSLOP )) == NULL))
|
|
{
|
|
fprintf(stderr,"Can't allocate buffers\n");
|
|
windexit(1);
|
|
}
|
|
*getcbuff = 0;
|
|
InsbuffSize = INSERTSLOP;
|
|
|
|
screenclear();
|
|
|
|
|
|
{
|
|
char *srcinitname,*initvar;
|
|
bool_t unmalloc;
|
|
unsigned x;
|
|
|
|
if((initvar = getenv("INIT")) == NULL) {
|
|
srcinitname = INITFILENAME;
|
|
unmalloc = FALSE;
|
|
} else {
|
|
srcinitname = malloc((x = strlen(initvar))+strlen(INITFILENAME)+2);
|
|
if(srcinitname == NULL) {
|
|
fprintf(stderr,"Can't allocate initial source buffer\n");
|
|
windexit(1);
|
|
}
|
|
unmalloc = TRUE;
|
|
strcpy(srcinitname,initvar);
|
|
if(srcinitname[x-1] != '\\') { // not NLS-aware!!
|
|
srcinitname[x] = '\\';
|
|
srcinitname[x+1] = '\0';
|
|
}
|
|
strcat(srcinitname,INITFILENAME);
|
|
}
|
|
dosource(srcinitname,FALSE);
|
|
if(unmalloc) {
|
|
free(srcinitname);
|
|
}
|
|
}
|
|
|
|
|
|
if ((initstr = getenv("EXINIT")) != NULL) {
|
|
char *lp, buf[128];
|
|
|
|
if ((lp = getenv("LINES")) != NULL) {
|
|
sprintf(buf, "%s lines=%s", initstr, lp);
|
|
docmdln(buf);
|
|
} else
|
|
docmdln(initstr);
|
|
}
|
|
|
|
if (Filename != NULL) {
|
|
if (readfile(Filename, Filemem, FALSE))
|
|
filemess("[New File]");
|
|
} else if (tag == NULL)
|
|
msg("Empty Buffer");
|
|
|
|
setpcmark();
|
|
|
|
if (tag) {
|
|
stuffin(":ta ");
|
|
stuffin(tag);
|
|
stuffin("\n");
|
|
|
|
} else if (pat) {
|
|
stuffin(pat);
|
|
stuffin("\n");
|
|
|
|
} else if (line >= 0) {
|
|
if (line > 0)
|
|
stuffnum(line);
|
|
stuffin("G");
|
|
}
|
|
|
|
interactive = TRUE;
|
|
|
|
edit();
|
|
|
|
windexit(0);
|
|
|
|
return 1; /* shouldn't be reached */
|
|
}
|
|
|
|
void
|
|
stuffin(s)
|
|
char *s;
|
|
{
|
|
char *p;
|
|
|
|
if (s == NULL) { /* clear the stuff buffer */
|
|
getcnext = NULL;
|
|
return;
|
|
}
|
|
|
|
if (getcnext == NULL) {
|
|
p = ralloc(getcbuff,strlen(s)+1);
|
|
if(p) {
|
|
getcbuff = p;
|
|
strcpy(getcbuff,s);
|
|
getcnext = getcbuff;
|
|
} else {
|
|
getcnext = NULL;
|
|
}
|
|
} else {
|
|
p = ralloc(getcbuff,strlen(getcbuff)+strlen(s)+1);
|
|
if(p) {
|
|
getcnext += p - getcbuff;
|
|
getcbuff = p;
|
|
strcat(getcbuff,s);
|
|
} else {
|
|
getcnext = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
stuffnum(n)
|
|
int n;
|
|
{
|
|
char buf[32];
|
|
|
|
sprintf(buf, "%d", n);
|
|
stuffin(buf);
|
|
}
|
|
|
|
int
|
|
vgetc()
|
|
{
|
|
register int c;
|
|
|
|
/*
|
|
* inchar() may map special keys by using stuffin(). If it does
|
|
* so, it returns -1 so we know to loop here to get a real char.
|
|
*/
|
|
do {
|
|
if ( getcnext != NULL ) {
|
|
int nextc = *getcnext++;
|
|
if ( *getcnext == NUL ) {
|
|
*getcbuff = NUL;
|
|
getcnext = NULL;
|
|
}
|
|
return(nextc);
|
|
}
|
|
c = inchar();
|
|
} while (c == -1);
|
|
|
|
return c;
|
|
}
|
|
|
|
/*
|
|
* anyinput
|
|
*
|
|
* Return non-zero if input is pending.
|
|
*/
|
|
|
|
bool_t
|
|
anyinput()
|
|
{
|
|
return (getcnext != NULL);
|
|
}
|
|
|
|
/*
|
|
* do_mlines() - process mode lines for the current file
|
|
*
|
|
* Returns immediately if the "ml" parameter isn't set.
|
|
*/
|
|
#define NMLINES 5 /* no. of lines at start/end to check for modelines */
|
|
|
|
void
|
|
do_mlines()
|
|
{
|
|
int i;
|
|
register LNPTR *p;
|
|
|
|
if (!P(P_ML))
|
|
return;
|
|
|
|
p = Filemem;
|
|
for (i=0; i < NMLINES ;i++) {
|
|
chk_mline(p->linep->s);
|
|
if ((p = nextline(p)) == NULL)
|
|
break;
|
|
}
|
|
|
|
if ((p = prevline(Fileend)) == NULL)
|
|
return;
|
|
|
|
for (i=0; i < NMLINES ;i++) {
|
|
chk_mline(p->linep->s);
|
|
if ((p = prevline(p)) == NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* chk_mline() - check a single line for a mode string
|
|
*/
|
|
static void
|
|
chk_mline(s)
|
|
register char *s;
|
|
{
|
|
register char *cs; /* local copy of any modeline found */
|
|
register char *e;
|
|
|
|
for (; *s != NUL ;s++) {
|
|
if (strncmp(s, "vi:", 3) == 0 || strncmp(s, "ex:", 3) == 0) {
|
|
cs = strsave(s+3);
|
|
if ((e = strchr(cs, ':')) != NULL) {
|
|
*e = NUL;
|
|
stuffin(mkstr(CTRL('o')));
|
|
docmdln(cs);
|
|
}
|
|
free(cs);
|
|
}
|
|
}
|
|
}
|