/* $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); } _CRTAPI1 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(p2-p1+1); strncpy(Appname, p1, 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); } } }