Path: utzoo!attcan!uunet!mcvax!unido!fauern!faui44!immd3.informatik.uni-erlangen.de!rtregn From: rtregn@immd3.informatik.uni-erlangen.de (Robert Regn) Newsgroups: comp.os.minix Subject: Sources of new version of Stevie (vi clone) 2 of 5 Keywords: vi stevie Message-ID: <768@faui10.informatik.uni-erlangen.de> Date: 14 Dec 88 16:08:30 GMT Organization: IMMD I, University of Erlangen, W-Erlangen Lines: 3054 Files not used for Minix are renamed from *.c to *_c Robert Regn\ rtregn@faui32.uucp\ rtregn@immd3.informatik.uni-erlangen.de #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'alloc.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: alloc.c,v 1.2 88/08/26 08:44:18 tony Exp $"; X X/* X * Various allocation routines and routines returning information about X * allocated objects. X * X * $Log: alloc.c,v $ X * Revision 1.2 88/08/26 08:44:18 tony X * Misc. changes to make lint happy. X * X * Revision 1.1 88/03/20 21:06:06 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xchar * Xalloc(size) Xunsigned size; X{ X char *p; /* pointer to new storage space */ X X p = malloc(size); X if ( p == (char *)NULL ) { /* if there is no more room... */ X emsg("alloc() is unable to find memory!"); X } X return(p); X} X Xchar * Xstrsave(string) Xchar *string; X{ X return(strcpy(alloc((unsigned)(strlen(string)+1)),string)); X} X Xvoid Xscreenalloc() X{ X /* X * If we're changing the size of the screen, free the old arrays X */ X if (Realscreen != NULL) X free(Realscreen); X if (Nextscreen != NULL) X free(Nextscreen); X X Realscreen = malloc((unsigned)(Rows*Columns)); X Nextscreen = malloc((unsigned)(Rows*Columns)); X} X X/* X * Allocate and initialize a new line structure with room for X * 'nchars' characters. X */ XLINE * Xnewline(nchars) Xint nchars; X{ X register LINE *l; X X if ((l = (LINE *) alloc(sizeof(LINE))) == NULL) X return (LINE *) NULL; X X l->s = alloc((unsigned) nchars); /* the line is empty */ X l->s[0] = NUL; X l->size = nchars; X X l->prev = (LINE *) NULL; /* should be initialized by caller */ X l->next = (LINE *) NULL; X X return l; X} X X/* X * filealloc() - construct an initial empty file buffer X */ Xvoid Xfilealloc() X{ X if ((Filemem->linep = newline(1)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X if ((Filetop->linep = newline(1)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X if ((Fileend->linep = newline(1)) == NULL) { X fprintf(stderr,"Unable to allocate file memory!\n"); X exit(1); X } X Filemem->index = 0; X Filetop->index = 0; X Fileend->index = 0; X X Filetop->linep->next = Filemem->linep; /* connect Filetop to Filemem */ X Filemem->linep->prev = Filetop->linep; X X Filemem->linep->next = Fileend->linep; /* connect Filemem to Fileend */ X Fileend->linep->prev = Filemem->linep; X X *Curschar = *Filemem; X *Topchar = *Filemem; X X Filemem->linep->num = 0; X Fileend->linep->num = 0xffff; X X clrall(); /* clear all marks */ X u_clear(); /* clear the undo buffer */ X} X X/* X * freeall() - free the current buffer X * X * Free all lines in the current buffer. X */ Xvoid Xfreeall() X{ X LINE *lp, *xlp; X X for (lp = Filetop->linep; lp != NULL ;lp = xlp) { X if (lp->s != NULL) X free(lp->s); X xlp = lp->next; X free(lp); X } X X Curschar->linep = NULL; /* clear pointers */ X Filetop->linep = NULL; X Filemem->linep = NULL; X Fileend->linep = NULL; X X u_clear(); X} X X/* X * bufempty() - return TRUE if the buffer is empty X */ Xbool_t Xbufempty() X{ X return (buf1line() && Filemem->linep->s[0] == NUL); X} X X/* X * buf1line() - return TRUE if there is only one line X */ Xbool_t Xbuf1line() X{ X return (Filemem->linep->next == Fileend->linep); X} X X/* X * lineempty() - return TRUE if the current line is empty X */ Xbool_t Xlineempty() X{ X return (Curschar->linep->s[0] == NUL); X} X X/* X * endofline() - return TRUE if the given position is at end of line X * X * This routine will probably never be called with a position resting X * on the NUL byte, but handle it correctly in case it happens. X */ Xbool_t Xendofline(p) Xregister LPTR *p; X{ X return (p->linep->s[p->index] == NUL || p->linep->s[p->index+1] == NUL); X} X/* X * canincrease(n) - returns TRUE if the current line can be increased 'n' bytes X * X * This routine returns immediately if the requested space is available. X * If not, it attempts to allocate the space and adjust the data structures X * accordingly. If everything fails it returns FALSE. X */ Xbool_t Xcanincrease(n) Xregister int n; X{ X register int nsize; X register char *s; /* pointer to new space */ X X nsize = strlen(Curschar->linep->s) + 1 + n; /* size required */ X X if (nsize <= Curschar->linep->size) X return TRUE; X X /* X * Need to allocate more space for the string. Allow some extra X * space on the assumption that we may need it soon. This avoids X * excessive numbers of calls to malloc while entering new text. X */ X if ((s = alloc((unsigned) (nsize + SLOP))) == NULL) { X emsg("Can't add anything, file is too big!"); X State = NORMAL; X return FALSE; X } X X Curschar->linep->size = nsize + SLOP; X strcpy(s, Curschar->linep->s); X free(Curschar->linep->s); X Curschar->linep->s = s; X X return TRUE; X} END_OF_FILE if test 4435 -ne `wc -c <'alloc.c'`; then echo shar: \"'alloc.c'\" unpacked with wrong size! fi # end of 'alloc.c' fi if test -f 'ascii.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ascii.h'\" else echo shar: Extracting \"'ascii.h'\" \(350 characters\) sed "s/^X//" >'ascii.h' <<'END_OF_FILE' X/* X * Definitions of various common control characters X * X * $Header: ascii.h,v 1.1 88/03/20 21:03:24 tony Exp $ X * X * $Log: ascii.h,v $ X * Revision 1.1 88/03/20 21:03:24 tony X * Initial revision X * X * X */ X X#define NUL '\0' X#define BS '\010' X#define TAB '\011' X#define NL '\012' X#define CR '\015' X#define ESC '\033' X X#define CTRL(x) ((x) & 0x1f) END_OF_FILE if test 350 -ne `wc -c <'ascii.h'`; then echo shar: \"'ascii.h'\" unpacked with wrong size! fi # end of 'ascii.h' fi if test -f 'cmdline.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cmdline.c'\" else echo shar: Extracting \"'cmdline.c'\" \(14535 characters\) sed "s/^X//" >'cmdline.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: cmdline.c,v 1.9 88/11/10 08:58:04 tony Exp $"; X X/* X * Routines to parse and execute "command line" commands, such as searches X * or colon commands. X * X * further modifications by: Robert Regn rtregn@faui32.uucp X * X * $Log: cmdline.c,v $ X * Revision 1.9 88/11/10 08:58:04 tony X * Added support for modelines when a new file edit is started. X * X * Revision 1.8 88/11/01 21:31:56 tony X * Added a call to flushbuf() in msg() to make sure messages get out X * when they should. X * X * Revision 1.7 88/10/27 08:21:38 tony X * Removed support for Megamax. Added support for ":sh" and ":!", and X * removed doshell() since it needs to be system-dependent. Changed X * ":p" to ":N" to avoid name conflict with the "print" command. The X * address spec "%" is translated to "1,$". The "=" command now works X * to print the line number of the given address. X * X * Revision 1.6 88/08/26 08:44:48 tony X * Misc. changes to make lint happy. X * X * Revision 1.5 88/06/26 14:48:20 tony X * Added a call to doglob() to handle the new ":g" command. X * X * Revision 1.4 88/06/25 21:43:19 tony X * Fixed a problem in the processing of colon commands that caused X * substitutions of patterns containing white space to fail. X * X * Revision 1.3 88/04/24 21:35:09 tony X * Added a new colon command "s" (substitute), which is performed by the X * routine dosub() in search.c. X * X * Revision 1.2 88/03/23 21:25:10 tony X * Fixed a bug involving backspacing out of a colon or search command. X * The fix is a hack until that part of the code can be cleaned up more. X * X * Revision 1.1 88/03/20 21:06:19 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xstatic char *altfile = NULL; /* alternate file */ Xstatic int altline; /* line # in alternate file */ X Xstatic char *nowrtmsg = "No write since last change (use ! to override)"; Xstatic char *nooutfile = "No output file"; Xstatic char *morefiles = "more files to edit"; X Xextern char **files; /* used for "n" and "rew" */ Xextern int numfiles, curfile; X X/* X * The next two variables contain the bounds of any range given in a X * command. If no range was given, both contain null line pointers. X * If only a single line was given, u_pos will contain a null line X * pointer. X */ Xstatic LPTR l_pos, u_pos; X Xstatic bool_t interactive; /* TRUE if we're reading a real command line */ X X#define CMDSZ 100 /* size of the command buffer */ X Xstatic bool_t doecmd(); Xstatic void badcmd(), get_range(); Xstatic LPTR *get_line(); X X/* X * readcmdline() - accept a command line starting with ':', '/', or '?' X * X * readcmdline() accepts and processes colon commands and searches. If X * 'cmdline' is null, the command line is read here. Otherwise, cmdline X * points to a complete command line that should be used. This is used X * in main() to handle initialization commands in the environment variable X * "EXINIT". X */ Xvoid Xreadcmdline(firstc, cmdline) Xint firstc; /* either ':', '/', or '?' */ Xchar *cmdline; /* optional command string */ X{ X int c; X char buff[CMDSZ]; X char cmdbuf[CMDSZ]; X char argbuf[CMDSZ]; X char *p, *q, *cmd, *arg; X X /* X * Clear the range variables. X */ X l_pos.linep = (struct line *) NULL; X u_pos.linep = (struct line *) NULL; X X interactive = (cmdline == NULL); X X if (interactive) X gotocmd(TRUE, firstc); X p = buff; X if ( firstc != ':' ) X *p++ = firstc; X X if (interactive) { X /* collect the command string, handling '\b' and @ */ X for ( ; ; ) { X c = vgetc(); X if ( c=='\n'||c=='\r'||c==EOF ) X break; X if ( c=='\b' ) { X if ( p > buff + (firstc != ':') ) { X p--; X /* this is gross, but it relies X * only on 'gotocmd' X */ X gotocmd(TRUE, firstc==':'?':':0); X for ( q=buff; q CMDSZ-2) /* should really do something */ X return; /* better here... */ X strcpy(p, cmdline); X } X X /* skip any initial white space */ X for ( cmd = buff; *cmd != NUL && isspace(*cmd); cmd++ ) X ; X X /* search commands */ X c = *cmd; X if ( c == '/' || c == '?' ) { X cmd++; X if ( *cmd == c || *cmd == NUL ) { X /* X * The command was just '/' or '?' or possibly X * '//' or '??'. Search in the requested direction X * for the last search string used. The NULL X * parameter to dosearch() tells it to do this. X */ X dosearch((c == '/') ? FORWARD : BACKWARD, NULL); X return; X } X /* If there is a matching '/' or '?' at the end, toss it */ X p = strchr(cmd, NUL); X if ( *(p-1) == c && *(p-2) != '\\' ) X *(p-1) = NUL; X dosearch((c == '/') ? FORWARD : BACKWARD, cmd); X return; X } X X if (*cmd == '%') { /* change '%' to "1,$" */ X strcpy(cmdbuf, "1,$"); /* kind of gross... */ X strcat(cmdbuf, cmd+1); X strcpy(cmd, cmdbuf); X } X X while ( (p=strchr(cmd, '%')) != NULL && *(p-1) != '\\') { X /* change '%' to Filename */ X if (Filename == NULL) { X emsg("No filename"); X return; X } X *p= NUL; X strcpy (cmdbuf, cmd); X strcat (cmdbuf, Filename); X strcat (cmdbuf, p+1); X strcpy(cmd, cmdbuf); X msg(cmd); /*repeat */ X } X X while ( (p=strchr(cmd, '#')) != NULL && *(p-1) != '\\') { X /* change '#' to Altname */ X if (altfile == NULL) { X emsg("No alternate file"); X return; X } X *p= NUL; X strcpy (cmdbuf, cmd); X strcat (cmdbuf, altfile); X strcat (cmdbuf, p+1); X strcpy(cmd, cmdbuf); X msg(cmd); /*repeat */ X } X X /* X * Parse a range, if present (and update the cmd pointer). X */ X get_range(&cmd); X X if (l_pos.linep != NULL) { X if (LINEOF(&l_pos) > LINEOF(&u_pos)) { X emsg("Invalid range"); X return; X } X } X X strcpy(cmdbuf, cmd); /* save the unmodified command */ X X /* isolate the command and find any argument */ X for ( p=cmd; *p != NUL && ! isspace(*p); p++ ) X ; X if ( *p == NUL ) X arg = NULL; X else { X *p = NUL; X for (p++; *p != NUL && isspace(*p) ;p++) X ; X if (*p == NUL) X arg = NULL; X else { X strcpy(argbuf, p); X arg = argbuf; X } X } X if ( strcmp(cmd,"q!")==0 ) X getout(); X if ( strcmp(cmd,"q")==0 ) { X if ( Changed ) X emsg(nowrtmsg); X else X if ( (curfile + 1) < numfiles ) X emsg (morefiles); X else getout(); X return; X } X if ( strcmp(cmd,"w")==0 ) { X if ( arg == NULL ) { X if (Filename != NULL) { X writeit(Filename, &l_pos, &u_pos); X } else X emsg(nooutfile); X } X else X writeit(arg, &l_pos, &u_pos); X return; X } X if ( strcmp(cmd,"wq")==0 ) { X if (Filename != NULL) { X if (writeit(Filename, (LPTR *)NULL, (LPTR *)NULL)) X getout(); X } else X emsg(nooutfile); X return; X } X if ( strcmp(cmd, "x") == 0 ) { X doxit(); X return; X } X X if ( strcmp(cmd,"f")==0 && arg==NULL ) { X fileinfo(); X return; X } X if ( *cmd == 'n' ) { X if ( (curfile + 1) < numfiles ) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[++curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if ( *cmd == 'N' ) { X if ( curfile > 0 ) { X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[1] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[--curfile]); X stuffin("\n"); X } else X emsg("No more files!"); X return; X } X if ( strncmp(cmd, "rew", 3) == 0) { X if (numfiles <= 1) /* nothing to rewind */ X return; X curfile = 0; X /* X * stuff ":e[!] FILE\n" X */ X stuffin(":e"); X if (cmd[3] == '!') X stuffin("!"); X stuffin(" "); X stuffin(files[0]); X stuffin("\n"); X return; X } X if ( strcmp(cmd,"e") == 0 || strcmp(cmd,"e!") == 0 ) { X doecmd(arg, cmd[1] == '!'); X return; X } X if ( strcmp(cmd,"f") == 0 ) { X Filename = strsave(arg); X filemess(""); X return; X } X if ( strcmp(cmd,"r") == 0 ) { X if ( arg == NULL ) { X badcmd(); X return; X } X if (readfile(arg, Curschar, 1)) { X emsg("Can't open file"); X return; X } X updatescreen(); X CHANGED; X return; X } X if ( strcmp(cmd,"=")==0 ) { X smsg("%d", cntllines(Filemem, &l_pos)); X return; X } X if ( strncmp(cmd,"ta", 2) == 0 ) { X dotag(arg, cmd[2] == '!'); X return; X } X if ( strncmp(cmd,"set", 2)==0 ) { X doset(arg, interactive); X return; X } X if ( strcmp(cmd,"help")==0 ) { X if (help()) { X screenclear(); X updatescreen(); X } X return; X } X if ( strncmp(cmd, "ve", 2) == 0) { X extern char *Version; X X msg(Version); X return; X } X if ( strcmp(cmd, "sh") == 0) { X doshell(NULL); X return; X } X if ( *cmd == '!' ) { X doshell(cmdbuf+1); X return; X } X if ( strncmp(cmd, "s/", 2)==0 ) { X dosub(&l_pos, &u_pos, cmdbuf+1); X return; X } X if (strncmp(cmd, "g/", 2) == 0) { X doglob(&l_pos, &u_pos, cmdbuf+1); X return; X } X /* X * If we got a line, but no command, then go to the line. X */ X if (*cmd == NUL && l_pos.linep != NULL) { X *Curschar = l_pos; X cursupdate(); X return; X } X X badcmd(); X} X X Xdoxit() X{ X if (Changed) { X if (Filename != NULL) { X if (!writeit(Filename, (LPTR *)NULL, (LPTR *)NULL)) X return; X } else { X emsg(nooutfile); X return; X } X } X if ( (curfile + 1) < numfiles ) X emsg (morefiles); X else getout(); X} X X/* X * get_range - parse a range specifier X * X * Ranges are of the form: X * X * addr[,addr] X * X * where 'addr' is: X * X * $ [+- NUM] X * 'x [+- NUM] (where x denotes a currently defined mark) X * . [+- NUM] X * NUM X * X * The pointer *cp is updated to point to the first character following X * the range spec. If an initial address is found, but no second, the X * upper bound is equal to the lower. X */ Xstatic void Xget_range(cp) Xchar **cp; X{ X LPTR *l; X char *p; X X if ((l = get_line(cp)) == NULL) X return; X X l_pos = *l; X X for (p = *cp; *p != NUL && isspace(*p) ;p++) X ; X X *cp = p; X X if (*p != ',') { /* is there another line spec ? */ X u_pos = l_pos; X return; X } X X *cp = ++p; X X if ((l = get_line(cp)) == NULL) { X u_pos = l_pos; X return; X } X X u_pos = *l; X} X Xstatic LPTR * Xget_line(cp) Xchar **cp; X{ X static LPTR pos; X LPTR *lp; X char *p, c; X int lnum; X X pos.index = 0; /* shouldn't matter... check back later */ X X p = *cp; X /* X * Determine the basic form, if present. X */ X switch (c = *p++) { X X case '$': X pos.linep = Fileend->linep->prev; X break; X X case '.': X pos.linep = Curschar->linep; X break; X X case '\'': X if ((lp = getmark(*p++)) == NULL) { X emsg("Unknown mark"); X return (LPTR *) NULL; X } X pos = *lp; X break; X X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X for (lnum = c - '0'; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X pos = *gotoline(lnum); X break; X X default: X return (LPTR *) NULL; X } X X while (*p != NUL && isspace(*p)) X p++; X X if (*p == '-' || *p == '+') { X bool_t neg = (*p++ == '-'); X X for (lnum = 0; isdigit(*p) ;p++) X lnum = (lnum * 10) + (*p - '0'); X X if (neg) X lnum = -lnum; X X pos = *gotoline( cntllines(Filemem, &pos) + lnum ); X } X X *cp = p; X return &pos; X} X Xstatic void Xbadcmd() X{ X if (interactive) X emsg("Unrecognized command"); X} X X#define LSIZE 512 /* max. size of a line in the tags file */ X X/* X * dotag(tag, force) - goto tag X */ Xvoid Xdotag(tag, force) Xchar *tag; Xbool_t force; X{ X FILE *tp, *fopen(); X char lbuf[LSIZE]; X char *fname, *str; X X if ((tp = fopen("tags", "r")) == NULL) { X emsg("Can't open tags file"); X return; X } X X while (fgets(lbuf, LSIZE, tp) != NULL) { X X if ((fname = strchr(lbuf, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *fname++ = '\0'; X if ((str = strchr(fname, TAB)) == NULL) { X emsg("Format error in tags file"); X return; X } X *str++ = '\0'; X X if (strcmp(lbuf, tag) == 0) { X if (doecmd(fname, force)) { X stuffin(str); /* str has \n at end */ X stuffin("\007"); /* CTRL('G') */ X fclose(tp); X return; X } X } X } X emsg("tag not found"); X fclose(tp); X} X Xstatic bool_t Xdoecmd(arg, force) Xchar *arg; Xbool_t force; X{ X int line = 1; /* line # to go to in new file */ X X if (!force && Changed) { X emsg(nowrtmsg); X if (altfile) X free(altfile); X altfile = strsave(arg); X return FALSE; X } X if ( arg != NULL ) { X /* X * First detect a ":e" on the current file. This is mainly X * for ":ta" commands where the destination is within the X * current file. X */ X if (Filename != NULL && strcmp(arg, Filename) == 0) { X if (!Changed || (Changed && !force)) X return TRUE; X } X#ifdef OLDSUB X if (strcmp(arg, "#") == 0) { /* alternate */ X char *s = Filename; X X if (altfile == NULL) { X emsg("No alternate file"); X return FALSE; X } X Filename = altfile; X altfile = s; X line = altline; X altline = cntllines(Filemem, Curschar); X } else X if (strchr(arg, '%')) { X char *s, *buf=alloc(strlen(arg)+strlen(Filename)); X if (Filename == NULL) { X emsg("No filename"); X return FALSE; X } X s = strchr(arg, '%'); X *s = 0; X strcpy (buf, arg); X strcat (buf, Filename); X strcat (buf, s+1); X if (altfile) /* I'm not shure if it is ok */ X free(altfile); X altfile = Filename; X altline = cntllines(Filemem, Curschar); X Filename = buf; X } else { X#endif X if (altfile) /* I'm not shure if it is ok */ X { X if (strcmp (arg, altfile) == 0) X line = altline; X free(altfile); X } X altfile = Filename; X altline = cntllines(Filemem, Curschar); X Filename = strsave(arg); X#ifdef OLDSUB X } X#endif X } X if (Filename == NULL) { X emsg("No filename"); X return FALSE; X } X X /* clear mem and read file */ X freeall(); X filealloc(); X UNCHANGED; X X if (readfile(Filename, Filemem, 0)) X filemess("[New File]"); X *Topchar = *Curschar; X if (line != 1) { X stuffnum(line); X stuffin("G"); X } X do_mlines(); X setpcmark(); X updatescreen(); X return TRUE; X} X Xvoid Xgotocmd(clr, firstc) Xbool_t clr; Xchar firstc; X{ X windgoto(Rows-1,0); X if ( clr ) X outstr(T_EL); /* clear the bottom line */ X if ( firstc ) X outchar(firstc); X} X X/* X * msg(s) - displays the string 's' on the status line X */ Xvoid Xmsg(s) Xchar *s; X{ X gotocmd(TRUE, 0); X outstr(s); X flushbuf(); X} X X/*VARARGS1*/ Xvoid Xsmsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9) Xchar *s; Xint a1, a2, a3, a4, a5, a6, a7, a8, a9; X{ X char sbuf[80]; X X sprintf(sbuf, s, a1, a2, a3, a4, a5, a6, a7, a8, a9); X msg(sbuf); X} X X/* X * emsg() - display an error message X * X * Rings the bell, if appropriate, and calls message() to do the real work X */ Xvoid Xemsg(s) Xchar *s; X{ X if (P(P_EB)) X beep(); X msg(s); X} X Xvoid Xwait_return() X{ X char c; X X outstr("Press RETURN to continue"); X do { X c = vgetc(); X } while (c != '\r' && c != '\n' && c != ' ' && c != ':'); X X if ( c == ':') { /* this can vi too */ X outstr("\n"); X readcmdline(c, NULL); X } X else X screenclear(); X updatescreen(); X} END_OF_FILE if test 14535 -ne `wc -c <'cmdline.c'`; then echo shar: \"'cmdline.c'\" unpacked with wrong size! fi # end of 'cmdline.c' fi if test -f 'ctags.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'ctags.c'\" else echo shar: Extracting \"'ctags.c'\" \(3077 characters\) sed "s/^X//" >'ctags.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: ctags.c,v 1.1 88/03/20 21:06:51 tony Exp $"; X X/* X * ctags - first cut at a UNIX ctags re-implementation X * X * $Log: ctags.c,v $ X * Revision 1.1 88/03/20 21:06:51 tony X * Initial revision X * X * X */ X X/* X * Caveats: X * X * Only simple function declarations are recognized, as in: X * X * type X * fname(...) X * X * where "fname" is the name of the function and must come at the beginning X * of a line. This is the form I always use, so the limitation doesn't X * bother me. X * X * Macros (with or without parameters) of the following form are also detected: X * X * "#" [white space] "define" [white space] NAME X * X * No sorting or detection of duplicate functions is done. X * X * If there are no arguments, a list of filenames to be searched is read X * from the standard input. Otherwise, all arguments are assumed to be X * file names. X * X * Tony Andrews X * August 1987 X */ X X#include X#include X#include X X#if 0 X#define index strchr X#endif X Xint ac; Xchar **av; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X char *fname, *nextfile(); X FILE *tp, *fopen(); X X ac = argc; X av = argv; X X if ((tp = fopen("tags", "w")) == NULL) { X fprintf(stderr, "Can't create tags file\n"); X exit(1); X } X X while ((fname = nextfile()) != NULL) X dofile(fname, tp); X X fclose(tp); X exit(0); X} X Xchar * Xnextfile() /* returns ptr to next file to be searched, null at end */ X{ X static char buf[128]; X static int ap = 1; X char *gets(); X X if (ac <= 1) { /* read from stdin */ X if (feof(stdin)) X return (char *) NULL; X return (gets(buf)); X } else { X if (ap < ac) X return av[ap++]; X else X return (char *) NULL; X } X} X X#define LSIZE 512 /* max. size of a line */ X X#define BEGID(c) (isalpha(c) || (c) == '_') X#define MIDID(c) (isalpha(c) || isdigit(c) || (c) == '_') X Xdofile(fn, tp) Xchar *fn; XFILE *tp; X{ X FILE *fp, *fopen(); X char *cp, *index(); X char lbuf[LSIZE]; X char func[LSIZE]; X int i, j; X X if ((fp = fopen(fn, "r")) == NULL) { X fprintf(stderr, "Can't open file '%s' - skipping\n", fn); X return; X } X X while (fgets(lbuf, LSIZE, fp) != NULL) { X X if (BEGID(lbuf[0])) { /* could be a function */ X for (i=0; MIDID(lbuf[i]) ;i++) /* grab the name */ X func[i] = lbuf[i]; X X func[i] = '\0'; /* null terminate the name */ X X /* X * We've skipped to the end of what may be a function X * name. Check to see if the next char is a paren, X * and make sure the closing paren is here too. X */ X if (lbuf[i]=='(' && (((cp = index(lbuf, ')'))!=NULL))) { X *++cp = '\0'; X fprintf(tp, "%s\t%s\t/^%s\\(/\n", func,fn,func); X } X X } else if (lbuf[0] == '#') { /* could be a define */ X for (i=1; isspace(lbuf[i]) ;i++) X ; X if (strncmp(&lbuf[i], "define", 6) != 0) X continue; X X i += 6; /* skip "define" */ X X for (; isspace(lbuf[i]) ;i++) X ; X X if (!BEGID(lbuf[i])) X continue; X X for (j=0; MIDID(lbuf[i]) ;i++, j++) X func[j] = lbuf[i]; X X func[j] = '\0'; /* null terminate the name */ X lbuf[i] = '\0'; /* null terminate the line */ X fprintf(tp, "%s\t%s\t/^%s/\n", func, fn, lbuf); X } X } X fclose(fp); X} END_OF_FILE if test 3077 -ne `wc -c <'ctags.c'`; then echo shar: \"'ctags.c'\" unpacked with wrong size! fi # end of 'ctags.c' fi if test -f 'dos_c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'dos_c'\" else echo shar: Extracting \"'dos_c'\" \(5670 characters\) sed "s/^X//" >'dos_c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: dos.c,v 1.4 88/10/28 14:40:15 tony Exp $"; X X/* X * DOS System-dependent routines. X * X * System-specific code for MS-DOS. This has been tested with X * MSDOS 3.3 on an AT. Also, the console driver "nansi.sys" is X * required. X * X * $Log: dos.c,v $ X * Revision 1.4 88/10/28 14:40:15 tony X * Added doshell() to support ":sh" and ":!". X * X * Revision 1.3 88/10/06 10:13:30 tony X * Added fixname() routine which trims the base and extension parts of X * a file name to 8 and 3 characters, and returns a pointer to the X * resulting string. This makes it easier to deal with UNIX-style names X * on stupid systems. X * X * Revision 1.2 88/08/26 13:39:42 tony X * Added routines to get and set the switch character, and modified the X * init and terminate code to set the switch character to '/' during X * execution. This seems to be needed to make the system() routine happy. X * X * Revision 1.1 88/05/03 14:22:16 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#include X#include X Xstatic char getswitch(); Xstatic void setswitch(); X X/* X * inchar() - get a character from the keyboard X */ Xint Xinchar() X{ X int c; X X for (;;beep()) { /* loop until we get a valid character */ X X flushbuf(); /* flush any pending output */ X X switch (c = getch()) { X case 0x1e: X return K_CGRAVE; X case 0: /* special key */ X if (State != NORMAL) { X c = getch(); /* throw away next char */ X continue; /* and loop for another char */ X } X switch (c = getch()) { X case 0x50: X return K_DARROW; X case 0x48: X return K_UARROW; X case 0x4b: X return K_LARROW; X case 0x4d: X return K_RARROW; X case 0x52: X return K_INSERT; X case 0x47: X stuffin("1G"); X return -1; X case 0x4f: X stuffin("G"); X return -1; X case 0x51: X stuffin(mkstr(CTRL('F'))); X return -1; X case 0x49: X stuffin(mkstr(CTRL('B'))); X return -1; X /* X * Hard-code some useful function key macros. X */ X case 0x3b: /* F1 */ X stuffin(":p\n"); X return -1; X case 0x54: /* SF1 */ X stuffin(":p!\n"); X return -1; X case 0x3c: /* F2 */ X stuffin(":n\n"); X return -1; X case 0x55: /* SF2 */ X stuffin(":n!\n"); X return -1; X case 0x3d: /* F3 */ X stuffin(":e #\n"); X return -1; X case 0x3e: /* F4 */ X stuffin(":rew\n"); X return -1; X case 0x57: /* SF4 */ X stuffin(":rew!\n"); X return -1; X case 0x3f: /* F5 */ X stuffin("[["); X return -1; X case 0x40: /* F6 */ X stuffin("]]"); X return -1; X case 0x41: /* F7 */ X stuffin("<<"); X return -1; X case 0x42: /* F8 */ X stuffin(">>"); X return -1; X case 0x43: /* F9 */ X stuffin(":x\n"); X return -1; X case 0x44: /* F10 */ X stuffin(":help\n"); X return -1; X default: X break; X } X break; X X default: X return c; X } X } X} X X#define BSIZE 2048 Xstatic char outbuf[BSIZE]; Xstatic int bpos = 0; X Xvoid Xflushbuf() X{ X if (bpos != 0) X write(1, outbuf, bpos); X bpos = 0; X} X X/* X * Macro to output a character. Used within this file for speed. X */ X#define outone(c) outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf() X X/* X * Function version for use outside this file. X */ Xvoid Xoutchar(c) Xregister char c; X{ X outbuf[bpos++] = c; X if (bpos >= BSIZE) X flushbuf(); X} X X/* X * outstr(s) - write a string to the console X */ Xvoid Xoutstr(s) Xregister char *s; X{ X while (*s) { X outone(*s++); X } X} X Xvoid Xbeep() X{ X outone('\007'); X} X Xsleep(n) Xint n; X{ X /* X * Should do something reasonable here. X */ X} X Xvoid Xdelay() X{ X long l; X X flushbuf(); X /* X * Should do something better here... X */ X for (l=0; l < 5000 ;l++) X ; X} X Xstatic char schar; /* save original switch character */ X Xvoid Xwindinit() X{ X Columns = 80; X P(P_LI) = Rows = 25; X schar = getswitch(); X setswitch('/'); X} X Xvoid Xwindexit(r) Xint r; X{ X flushbuf(); X setswitch(schar); X exit(r); X} X Xvoid Xwindgoto(r, c) Xregister int r, c; X{ X r += 1; X c += 1; X X /* X * Check for overflow once, to save time. X */ X if (bpos + 8 >= BSIZE) X flushbuf(); X X outbuf[bpos++] = '\033'; X outbuf[bpos++] = '['; X if (r >= 10) X outbuf[bpos++] = r/10 + '0'; X outbuf[bpos++] = r%10 + '0'; X outbuf[bpos++] = ';'; X if (c >= 10) X outbuf[bpos++] = c/10 + '0'; X outbuf[bpos++] = c%10 + '0'; X outbuf[bpos++] = 'H'; X} X XFILE * Xfopenb(fname, mode) Xchar *fname; Xchar *mode; X{ X FILE *fopen(); X char modestr[16]; X X sprintf(modestr, "%sb", mode); X return fopen(fname, modestr); X} X Xstatic char Xgetswitch() X{ X union REGS inregs, outregs; X X inregs.h.ah = 0x37; X inregs.h.al = 0; X X intdos(&inregs, &outregs); X X return outregs.h.dl; X} X Xstatic void Xsetswitch(c) Xchar c; X{ X union REGS inregs, outregs; X X inregs.h.ah = 0x37; X inregs.h.al = 1; X inregs.h.dl = c; X X intdos(&inregs, &outregs); X} X X#define PSIZE 128 X X/* X * fixname(s) - fix up a dos name X * X * Takes a name like: X * X * \x\y\z\base.ext X * X * and trims 'base' to 8 characters, and 'ext' to 3. X */ Xchar * Xfixname(s) Xchar *s; X{ X char *strchr(), *strrchr(); X static char f[PSIZE]; X char base[32]; X char ext[32]; X char *p; X int i; X X strcpy(f, s); X X for (i=0; i < PSIZE ;i++) X if (f[i] == '/') X f[i] = '\\'; X X /* X * Split the name into directory, base, extension. X */ X if ((p = strrchr(f, '\\')) != NULL) { X strcpy(base, p+1); X p[1] = '\0'; X } else { X strcpy(base, f); X f[0] = '\0'; X } X X if ((p = strchr(base, '.')) != NULL) { X strcpy(ext, p+1); X *p = '\0'; X } else X ext[0] = '\0'; X X /* X * Trim the base name if necessary. X */ X if (strlen(base) > 8) X base[8] = '\0'; X X if (strlen(ext) > 3) X ext[3] = '\0'; X X /* X * Paste it all back together X */ X strcat(f, base); X strcat(f, "."); X strcat(f, ext); X X return f; X} X Xvoid Xdoshell(cmd) Xchar *cmd; X{ X if (cmd == NULL) X cmd = "command.com"; X X system(cmd); X wait_return(); X} END_OF_FILE if test 5670 -ne `wc -c <'dos_c'`; then echo shar: \"'dos_c'\" unpacked with wrong size! fi # end of 'dos_c' fi if test -f 'edit.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'edit.c'\" else echo shar: Extracting \"'edit.c'\" \(7989 characters\) sed "s/^X//" >'edit.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: edit.c,v 1.7 88/11/10 13:29:15 tony Exp $"; X X/* X * The main edit loop as well as some other simple cursor movement routines. X * X * $Log: edit.c,v $ X * Revision 1.7 88/11/10 13:29:15 tony X * Added a call to do_mlines() to check for mode lines at initialization. X * X * Revision 1.6 88/10/06 10:11:50 tony X * Fixed a bug in scrolldown() involving the special case of the cursor X * being on the last line, and the line being scrolled onto the screen X * being long. The special case code needs to deal with physical lines, X * not logical. X * X * Revision 1.5 88/08/30 20:35:53 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.4 88/08/26 08:44:55 tony X * Misc. changes to make lint happy. X * X * Revision 1.3 88/05/01 20:08:47 tony X * Fixed some problems with the new auto-indent feature. X * X * Revision 1.2 88/04/30 19:59:43 tony X * Added support for auto-indent option. X * X * Revision 1.1 88/03/20 21:07:10 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * This flag is used to make auto-indent work right on lines where only X * a or is typed. It is set when an auto-indent is done, X * and reset when any other editting is done on the line. If an X * or is received, and did_ai is TRUE, the line is truncated. X */ Xbool_t did_ai = FALSE; X Xvoid Xedit() X{ X int c; X char *p, *q; X X Prenum = 0; X X /* position the display and the cursor at the top of the file. */ X *Topchar = *Filemem; X *Curschar = *Filemem; X Cursrow = Curscol = 0; X X do_mlines(); /* check for mode lines before starting */ X X for ( ;; ) { X X /* Figure out where the cursor is based on Curschar. */ X cursupdate(); X X windgoto(Cursrow,Curscol); X X c = vgetc(); X X if (State == NORMAL) { X X /* We're in the normal (non-insert) mode. */ X X /* Pick up any leading digits and compute 'Prenum' */ X if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){ X Prenum = Prenum*10 + (c-'0'); X continue; X } X /* execute the command */ X normal(c); X Prenum = 0; X X } else { X X /* X * Insert or Replace mode. X */ X switch (c) { X X case ESC: /* an escape ends input mode */ X X /* X * If we just did an auto-indent, truncate the X * line, and put the cursor back. X */ X if (did_ai) { X Curschar->linep->s[0] = NUL; X Curschar->index = 0; X did_ai = FALSE; X } X X set_want_col = TRUE; X X /* Don't end up on a '\n' if you can help it. */ X if (gchar(Curschar) == NUL && Curschar->index != 0) X dec(Curschar); X X /* X * The cursor should end up on the last inserted X * character. This is an attempt to match the real X * 'vi', but it may not be quite right yet. X */ X if (Curschar->index != 0 && !endofline(Curschar)) X dec(Curschar); X X State = NORMAL; X msg(""); X X /* construct the Redo buffer */ X p=Redobuff; X q=Insbuff; X while ( q < Insptr ) X *p++ = *q++; X *p++ = ESC; X *p = NUL; X updatescreen(); X break; X X case CTRL('D'): X /* X * Control-D is treated as a backspace in insert X * mode to make auto-indent easier. This isn't X * completely compatible with vi, but it's a lot X * easier than doing it exactly right, and the X * difference isn't very noticeable. X */ X case BS: X /* can't backup past starting point */ X if (Curschar->linep == Insstart->linep && X Curschar->index <= Insstart->index) { X beep(); X break; X } X X /* can't backup to a previous line */ X if (Curschar->linep != Insstart->linep && X Curschar->index <= 0) { X beep(); X break; X } X X did_ai = FALSE; X dec(Curschar); X if (State == INSERT) X delchar(TRUE); X /* X * It's a little strange to put backspaces into X * the redo buffer, but it makes auto-indent a X * lot easier to deal with. X */ X *Insptr++ = BS; X Ninsert++; X cursupdate(); X updateline(); X break; X X case CR: X case NL: X *Insptr++ = NL; X Ninsert++; X opencmd(FORWARD, TRUE); /* open a new line */ X break; X X default: X did_ai = FALSE; X insertchar(c); X break; X } X } X } X} X X/* X * Special characters in this context are those that need processing other X * than the simple insertion that can be performed here. This includes ESC X * which terminates the insert, and CR/NL which need special processing to X * open up a new line. This routine tries to optimize insertions performed X * by the "redo" command, so it needs to know when it should stop and defer X * processing to the "normal" mechanism. X */ X#define ISSPECIAL(c) ((c) == NL || (c) == CR || (c) == ESC) X Xvoid Xinsertchar(c) Xint c; X{ X#if 0 X char *p; X X if ( ! anyinput() ) { X#endif X inschar(c); X *Insptr++ = c; X Ninsert++; X /* X * The following kludge avoids overflowing the statically X * allocated insert buffer. Just dump the user back into X * command mode, and print a message. X */ X if (Insptr+10 >= &Insbuff[1024]) { X stuffin(mkstr(ESC)); X emsg("No buffer space - returning to command mode"); X sleep(2); X } X#if 0 X } X else { X /* If there's any pending input, grab it all at once. */ X p = Insptr; X *Insptr++ = c; X Ninsert++; X for (c = vpeekc(); !ISSPECIAL(c) ;c = vpeekc()) { X c = vgetc(); X *Insptr++ = c; X Ninsert++; X } X *Insptr = '\0'; X insstr(p); X } X#endif X updateline(); X} X Xvoid Xgetout() X{ X windgoto(Rows-1,0); X putchar('\r'); X putchar('\n'); X windexit(0); X} X Xvoid Xscrolldown(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X X /* Scroll up 'nlines' lines. */ X while (nlines--) { X if ((p = prevline(Topchar)) == NULL) X break; X done += plines(p); X *Topchar = *p; X /* X * If the cursor is on the bottom line, we need to X * make sure it gets moved up the appropriate number X * of lines so it stays on the screen. X */ X if (Curschar->linep == Botchar->linep->prev) { X int i = 0; X while (i < done) { X i += plines(Curschar); X *Curschar = *prevline(Curschar); X } X } X } X s_ins(0, done); X} X Xvoid Xscrollup(nlines) Xint nlines; X{ X register LPTR *p; X register int done = 0; /* total # of physical lines done */ X register int pl; /* # of plines for the current line */ X X /* Scroll down 'nlines' lines. */ X while (nlines--) { X pl = plines(Topchar); X if ((p = nextline(Topchar)) == NULL) X break; X done += pl; X if (Curschar->linep == Topchar->linep) X *Curschar = *p; X *Topchar = *p; X X } X s_del(0, done); X} X X/* X * oneright X * oneleft X * onedown X * oneup X * X * Move one char {right,left,down,up}. Return TRUE when X * sucessful, FALSE when we hit a boundary (of a line, or the file). X */ X Xbool_t Xoneright() X{ X set_want_col = TRUE; X X switch (inc(Curschar)) { X X case 0: X return TRUE; X X case 1: X dec(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xbool_t Xoneleft() X{ X set_want_col = TRUE; X X switch (dec(Curschar)) { X X case 0: X return TRUE; X X case 1: X inc(Curschar); /* crossed a line, so back up */ X /* fall through */ X case -1: X return FALSE; X } X /*NOTREACHED*/ X} X Xvoid Xbeginline(flag) Xbool_t flag; X{ X while ( oneleft() ) X ; X if (flag) { X while (isspace(gchar(Curschar)) && oneright()) X ; X } X set_want_col = TRUE; X} X Xbool_t Xoneup(n) X{ X LPTR p, *np; X int k; X X p = *Curschar; X for ( k=0; k 0 ) X break; /* to update the cursor, etc. */ X else X return FALSE; X } X p = *np; X } X *Curschar = p; X /* This makes sure Topchar gets updated so the complete line */ X /* is one the screen. */ X cursupdate(); X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} X Xbool_t Xonedown(n) X{ X LPTR p, *np; X int k; X X p = *Curschar; X for ( k=0; k 0 ) X break; X else X return FALSE; X } X p = *np; X } X /* try to advance to the column we want to be at */ X *Curschar = *coladvance(&p, Curswant); X return TRUE; X} END_OF_FILE if test 7989 -ne `wc -c <'edit.c'`; then echo shar: \"'edit.c'\" unpacked with wrong size! fi # end of 'edit.c' fi if test -f 'env.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'env.h'\" else echo shar: Extracting \"'env.h'\" \(1686 characters\) sed "s/^X//" >'env.h' <<'END_OF_FILE' X/* X * The defines in this file establish the environment we're compiling X * in. Set these appropriately before compiling the editor. X */ X X/* X * One (and only 1) of the following defines should be uncommented. X * Most of the code is pretty machine-independent. Machine dependent X * code goes in a file like tos.c or unix.c. The only other place X * where machine dependent code goes is term.h for escape sequences. X */ X X/* #define ATARI /* For the Atari ST */ X/* #define UNIX /* System V or BSD */ X/* #define OS2 /* Microsoft OS/2 1.1 */ X/* #define DOS /* MSDOS 3.3 (on AT) */ X X/* X * If UNIX is defined above, then BSD may be defined. X */ X#ifdef UNIX X/* #define BSD /* Berkeley UNIX */ X#endif X X/* X * If ATARI is defined, MINIX may be defined. Otherwise, the editor X * is set up to compile using the Sozobon C compiler under TOS. X */ X#ifdef ATARI X#define MINIX /* Minix for the Atari ST */ X#endif X X/* X * If HELP is defined, the :help command shows a vi command summary. X * Help costs on the PC minix about 900 Bytes text and 5000 Bytes data !! X */ X/* #define HELP /* enable help command */ X X/* X * Use of termcap is optional in some environments. If available, it X * is enabled by the following define. Check the appropriate system- X * dependent source file to see if termcap is supported. X */ X/* #define TERMCAP /* enable termcap support */ X X/* X * The yank buffer is still static, but its size can be specified X * here to override the default of 4K. X */ X/* #define YBSIZE 8192 /* yank buffer size */ X X/* X * STRCSPN should be defined if the target system doesn't have the X * routine strcspn() available. See regexp.c for details. X */ X X X#ifdef MINIX X#define STRCSPN X#endif X END_OF_FILE if test 1686 -ne `wc -c <'env.h'`; then echo shar: \"'env.h'\" unpacked with wrong size! fi # end of 'env.h' fi if test -f 'fileio.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'fileio.c'\" else echo shar: Extracting \"'fileio.c'\" \(7044 characters\) sed "s/^X//" >'fileio.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: fileio.c,v 1.7 88/10/27 08:15:27 tony Exp $"; X X/* X * Basic file I/O routines. X * X * further modifications by: Robert Regn rtregn@faui32.uucp X * X * $Log: fileio.c,v $ X * Revision 1.7 88/10/27 08:15:27 tony X * Removed support for Megamax, and added a call to flushbuf() for X * versions that buffer output. X * X * Revision 1.6 88/10/06 10:10:45 tony X * File names passed to fopen() are now processed by fixname() to do X * system-dependent hacks on the name (mainly for DOS & OS/2). X * X * Revision 1.5 88/08/26 08:45:00 tony X * Misc. changes to make lint happy. X * X * Revision 1.4 88/06/10 13:43:19 tony X * Fixed a bug involving writing out files with long pathnames. A small X * fixed size buffer was being used. The space for the backup file name X * is now allocated dynamically. X * X * Revision 1.3 88/05/02 21:37:12 tony X * Reworked the readfile() routine to better deal with null characters, X * non-ascii characters, long lines, and incomplete last lines. The status X * messages now match the real vi correctly for all cases. X * X * Revision 1.2 88/03/21 16:46:01 tony X * Changed the line counter in renum() from 'int' to 'long' to correspond X * to the actual type of the pseudo line number in the LINE structure. X * X * Revision 1.1 88/03/20 21:07:19 tony X * Initial revision X * X * X */ X X#include "stevie.h" X#include X Xvoid Xfilemess(s) Xchar *s; X{ X smsg("\"%s\" %s", (Filename == NULL) ? "" : Filename, s); X flushbuf(); X} X Xvoid Xrenum() X{ X LPTR *p; X unsigned long l = 0; X X for (p = Filemem; p != NULL ;p = nextline(p), l += LINEINC) X p->linep->num = l; X X Fileend->linep->num = 0xffffffff; X} X X#define MAXLINE 256 /* maximum size of a line */ X Xstatic char rdonly=0; X Xbool_t Xreadfile(fname,fromp,nochangename) Xchar *fname; XLPTR *fromp; Xbool_t nochangename; /* if TRUE, don't change the Filename */ X{ X FILE *f, *fopen(); X LINE *curr; X char buff[MAXLINE], buf2[80]; X int i, c; X long nchars = 0; X int linecnt = 0; X bool_t wasempty = bufempty(); X int nonascii = 0; /* count garbage characters */ X int nulls = 0; /* count nulls */ X bool_t incomplete = FALSE; /* was the last line incomplete? */ X bool_t toolong = FALSE; /* a line was too long */ X X curr = fromp->linep; X X if ( ! nochangename ) X Filename = strsave(fname); X X if ( (f=fopen(fixname(fname),"r")) == NULL ) X return TRUE; X X rdonly = (access(fname, 2) != 0); X filemess( rdonly ? "[Read only]" : ""); X X i = 0; X do { X c = getc(f); X X if (c == EOF) { X if (i == 0) /* normal loop termination */ X break; X X /* X * If we get EOF in the middle of a line, note the X * fact and complete the line ourselves. X */ X incomplete = TRUE; X c = NL; X } X X if (c >= 0x80) { X c -= 0x80; X nonascii++; X } X X /* X * If we reached the end of the line, OR we ran out of X * space for it, then process the complete line. X */ X if (c == NL || i == (MAXLINE-1)) { X int len; X LINE *lp; X X if (c != NL) X toolong = TRUE; X X buff[i] = '\0'; X len = strlen(buff) + 1; X if ((lp = newline(len)) == NULL) X {msg("Buffer overflow - File is uncomplete !!\n\r"); X break; X } X X strcpy(lp->s, buff); X X curr->next->prev = lp; /* new line to next one */ X lp->next = curr->next; X X curr->next = lp; /* new line to prior one */ X lp->prev = curr; X X curr = lp; /* new line becomes current */ X i = 0; X linecnt++; X X } else if (c == NUL) X nulls++; /* count and ignore nulls */ X else { X buff[i++] = c; /* normal character */ X } X X nchars++; X X } while (!incomplete && !toolong); X X fclose(f); X X /* X * If the buffer was empty when we started, we have to go back X * and remove the "dummy" line at Filemem and patch up the ptrs. X */ X if (wasempty && nchars > 0 /* !!! */) { X LINE *dummy = Filemem->linep; /* dummy line ptr */ X X free(dummy->s); /* free string space */ X Filemem->linep = Filemem->linep->next; X free(dummy); /* free LINE struct */ X Filemem->linep->prev = Filetop->linep; X Filetop->linep->next = Filemem->linep; X X Curschar->linep = Filemem->linep; X Topchar->linep = Filemem->linep; X } X X renum(); X X if (toolong) { X smsg("\"%s\" Line too long", fname); X return FALSE; X } X X sprintf(buff, "\"%s\" %s %s%d line%s, %ld character%s", X fname, X rdonly ? "[Read only]" : "", X incomplete ? "[Incomplete last line] " : "", X linecnt, (linecnt > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X X buf2[0] = NUL; X X if (nonascii || nulls) { X if (nonascii) { X if (nulls) X sprintf(buf2, " (%d null, %d non-ASCII)", X nulls, nonascii); X else X sprintf(buf2, " (%d non-ASCII)", nonascii); X } else X sprintf(buf2, " (%d null)", nulls); X } X strcat(buff, buf2); X msg(buff); X X return FALSE; X} X X X/* X * writeit - write to file 'fname' lines 'start' through 'end' X * X * If either 'start' or 'end' contain null line pointers, the default X * is to use the start or end of the file respectively. X */ Xbool_t Xwriteit(fname, start, end) Xchar *fname; XLPTR *start, *end; X{ X FILE *f, *fopen(); X FILE *fopenb(); /* open in binary mode, where needed */ X char *backup, *s; X long nchars; X int lines; X LPTR *p; X struct stat sbuf; X char newfile=0; X X if (stat(fname, &sbuf)!= 0) /* save mode of file for creating */ X newfile = 1; X X /* X X smsg("\"%s\"", fname); X X /* X * Form the backup file name - change foo.* to foo.bak X */ X backup = alloc((unsigned) (strlen(fname) + 5)); X strcpy(backup, fname); X for (s = backup; *s && *s != '.' ;s++) X ; X *s = NUL; X strcat(backup, ".bak"); X X /* X * Delete any existing backup and move the current version X * to the backup. For safety, we don't remove the backup X * until the write has finished successfully. And if the X * 'backup' option is set, leave it around. X */ X /* skipping rename avoids overwriting R/O files by creating a new */ X /* also save link structure R. Regn*/ X X if (!rdonly && sbuf.st_nlink == 1) X rename(fname, backup); X X X f = P(P_CR) ? fopen(fixname(fname), "w") : fopenb(fixname(fname), "w"); X X if ( f == NULL ) { X if (rdonly) X emsg("File is Read only"); X else emsg("Permission denied"); X free(backup); X return FALSE; X } X X if (!rdonly && !newfile) /* restore mode (and owner) properly */ X {chmod (fname, sbuf.st_mode&04777); X chown (fname, sbuf.st_uid, sbuf.st_gid); X } X X /* X * If we were given a bound, start there. Otherwise just X * start at the beginning of the file. X */ X if (start == NULL || start->linep == NULL) X p = Filemem; X else X p = start; X X lines = nchars = 0; X do { X fprintf(f, "%s\n", p->linep->s); X nchars += strlen(p->linep->s) + 1; X lines++; X X /* X * If we were given an upper bound, and we just did that X * line, then bag it now. X */ X if (end != NULL && end->linep != NULL) { X if (end->linep == p->linep) X break; X } X X } while ((p = nextline(p)) != NULL); X X fclose(f); X smsg("\"%s\" %s %d line%s, %ld character%s", fname, X newfile ? "[New File]" : "", X lines, (lines > 1) ? "s" : "", X nchars, (nchars > 1) ? "s" : ""); X X UNCHANGED; X X /* X * Remove the backup unless they want it left around X */ X if (!P(P_BK)) X remove(backup); X X free(backup); X X return TRUE; X} END_OF_FILE if test 7044 -ne `wc -c <'fileio.c'`; then echo shar: \"'fileio.c'\" unpacked with wrong size! fi # end of 'fileio.c' fi if test -f 'help.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'help.c'\" else echo shar: Extracting \"'help.c'\" \(9234 characters\) sed "s/^X//" >'help.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: help.c,v 1.7 88/10/28 13:59:18 tony Exp $"; X X/* X * Routine to display a command summary. X * X * $Log: help.c,v $ X * Revision 1.7 88/10/28 13:59:18 tony X * Minor changes to the screen. X * X * Revision 1.6 88/10/27 07:55:13 tony X * Rearranged the screens to fit more of the colon commands. X * X * Revision 1.5 88/08/30 20:36:46 tony X * After much prodding from Mark, I finally added support for replace mode. X * X * Revision 1.4 88/08/26 13:41:56 tony X * Added a mention of the '!' operator as that is now supported. X * X * Revision 1.3 88/08/26 08:45:05 tony X * Misc. changes to make lint happy. X * X * Revision 1.2 88/07/09 20:37:46 tony X * Changed the help screen containing 'U' to remove the "not yet" notation. X * X * Revision 1.1 88/03/20 21:07:26 tony X * Initial revision X * X * X */ X X#include "stevie.h" X Xextern char *Version; X Xstatic int helprow; X X#ifdef HELP X Xstatic void longline(); X Xbool_t Xhelp() X{ X X/*********************************************************************** X * First Screen: Positioning within file, Adjusting the Screen X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Positioning within file\n\ X =======================\n\ X ^F Forward screenfull Developed by:\n\ X ^B Backward screenfull Tony Andrews\n"); Xlongline("\ X ^D scroll down half screen\n\ X ^U scroll up half screen Based on a program by:\n"); Xlongline("\ X G Goto line (end default) Tim Thompson\n\ X ]] next function\n\ X [[ previous function\n\ X /re next occurence of regular expression 're'\n"); Xlongline("\ X ?re prior occurence of regular expression 're'\n\ X n repeat last / or ?\n\ X N reverse last / or ?\n\ X % find matching (, ), {, }, [, or ]\n"); Xlongline("\ X\n\ X Adjusting the screen\n\ X ====================\n\ X ^L Redraw the screen\n\ X ^E scroll window down 1 line\n\ X ^Y scroll window up 1 line\n"); Xlongline("\ X z redraw, current line at top\n\ X z- ... at bottom\n\ X z. ... at center\n"); X X windgoto(0, 52); X longline(Version); X X windgoto(helprow = Rows-2, 47); X longline("\n"); X windgoto(helprow = Rows-1, 47); X longline(""); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Second Screen: Character positioning X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Character Positioning\n\ X =====================\n\ X ^ first non-white\n\ X 0 beginning of line\n\ X $ end of line\n\ X h backward\n"); Xlongline("\ X l forward\n\ X ^H same as h\n\ X space same as l\n\ X fx find 'x' forward\n"); Xlongline("\ X Fx find 'x' backward\n\ X tx upto 'x' forward\n\ X Tx upto 'x' backward\n\ X ; Repeat last f, F, t, or T\n"); Xlongline("\ X , inverse of ;\n\ X | to specified column\n\ X % find matching (, ), {, }, [, or ]\n"); X X windgoto(helprow = Rows-2, 47); X longline("\n"); X windgoto(helprow = Rows-1, 47); X longline(""); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Third Screen: Line Positioning, Marking and Returning X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Line Positioning\n\ X ================\n\ X H home window line\n\ X L last window line\n\ X M middle window line\n"); Xlongline("\ X + next line, at first non-white\n\ X - previous line, at first non-white\n\ X CR return, same as +\n\ X j next line, same column\n\ X k previous line, same column\n"); X Xlongline("\ X\n\ X Marking and Returning\n\ X =====================\n\ X `` previous context\n\ X '' ... at first non-white in line\n"); Xlongline("\ X mx mark position with letter 'x'\n\ X `x to mark 'x'\n\ X 'x ... at first non-white in line\n"); X Xlongline("\n\ X Undo & Redo\n\ X =============\n\ X u undo last change\n\ X U restore current line\n\ X . repeat last change\n"); X X windgoto(helprow = Rows-2, 47); X longline("\n"); X windgoto(helprow = Rows-1, 47); X longline(""); X X if ( vgetc() != ' ' ) X return TRUE; X/*********************************************************************** X * Fourth Screen: Insert & Replace, X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Insert and Replace\n\ X ==================\n\ X a append after cursor\n\ X i insert before cursor\n\ X A append at end of line\n\ X I insert before first non-blank\n"); Xlongline("\ X o open line below\n\ X O open line above\n\ X rx replace single char with 'x'\n\ X R replace characters\n"); X Xlongline("\ X\n\ X Words, sentences, paragraphs\n\ X ============================\n\ X w word forward\n\ X b back word\n\ X e end of word\n\ X ) to next sentence (not yet)\n\ X } to next paragraph (not yet)\n"); Xlongline("\ X ( back sentence (not yet)\n\ X { back paragraph (not yet)\n\ X W blank delimited word\n\ X B back W\n\ X E to end of W\n"); X X windgoto(helprow = Rows-2, 47); X longline("\n"); X windgoto(helprow = Rows-1, 47); X longline(""); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Fifth Screen: Misc. operations, X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Miscellaneous Commands\n\ X ======================\n"); Xlongline("\ X :w write back changes\n\ X :wq write and quit\n\ X :x write if modified, and quit\n\ X :q quit\n\ X :q! quit, discard changes\n\ X :e name edit file 'name'\n"); Xlongline("\ X :e! reedit, discard changes\n\ X :e # edit alternate file\n\ X :w name write file 'name'\n"); Xlongline("\ X :n edit next file in arglist\n\ X :N edit prior file in arglist\n\ X :n args specify new arglist (not yet)\n\ X :rew rewind arglist\n\ X :f show current file and lines\n"); Xlongline("\ X :f file change current file name\n\ X :g/pat/p|d global command (print or delete only)\n\ X :s/p1/p2/ text substitution (trailing 'g' optional)\n\ X"); Xlongline("\ X :ta tag to tag file entry 'tag'\n\ X ^] :ta, current word is tag\n\ X :sh run an interactive shell\n\ X :!cmd execute a shell command\n\ X"); X X windgoto(helprow = Rows-2, 47); X longline("\n"); X windgoto(helprow = Rows-1, 47); X longline(""); X X if ( vgetc() != ' ' ) X return TRUE; X X/*********************************************************************** X * Sixth Screen: Operators, Misc. operations, Yank & Put X ***********************************************************************/ X X outstr(T_ED); X windgoto(helprow = 0, 0); X Xlongline("\ X Operators (double to affect lines)\n\ X ==================================\n\ X d delete\n\ X c change\n"); Xlongline("\ X < left shift\n\ X > right shift\n\ X y yank to buffer\n\ X ! filter lines\n"); X Xlongline("\n\ X Miscellaneous operations\n\ X ========================\n\ X C change rest of line\n\ X D delete rest of line\n\ X s substitute chars\n"); Xlongline("\ X S substitute lines (not yet)\n\ X J join lines\n\ X x delete characters\n\ X X ... before cursor\n"); X Xlongline("\n\ X Yank and Put\n\ X ============\n\ X p put back text\n\ X P put before\n\ X Y yank lines"); X X windgoto(helprow = Rows-1, 47); X longline(""); X X vgetc(); X X return TRUE; X} X Xstatic void Xlongline(p) Xchar *p; X{ X char *s; X X for ( s = p; *s ;s++ ) { X if ( *s == '\n' ) X windgoto(++helprow, 0); X else X outchar(*s); X } X} X#else X Xbool_t Xhelp() X{ X msg("Sorry, help not configured"); X return FALSE; X} X#endif END_OF_FILE if test 9234 -ne `wc -c <'help.c'`; then echo shar: \"'help.c'\" unpacked with wrong size! fi # end of 'help.c' fi if test -f 'hexchars.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hexchars.c'\" else echo shar: Extracting \"'hexchars.c'\" \(3413 characters\) sed "s/^X//" >'hexchars.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: hexchars.c,v 1.3 88/08/26 08:45:10 tony Exp $"; X X/* X * Contains information concerning the representation of characters for X * visual output by the editor. X * X * $Log: hexchars.c,v $ X * Revision 1.3 88/08/26 08:45:10 tony X * Misc. changes to make lint happy. X * X * Revision 1.2 88/05/03 14:38:43 tony X * Fixed the representation for the ascii character DELETE to be the X * same as vi. X * X * Revision 1.1 88/03/20 21:07:42 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * This file shows how to display characters on the screen. This is X * approach is something of an overkill. It's a remnant from the X * original code that isn't worth messing with for now. TABS are X * special-cased depending on the value of the "list" parameter. X */ X Xstruct charinfo chars[] = { X /* 000 */ 1, NULL, X /* 001 */ 2, "^A", X /* 002 */ 2, "^B", X /* 003 */ 2, "^C", X /* 004 */ 2, "^D", X /* 005 */ 2, "^E", X /* 006 */ 2, "^F", X /* 007 */ 2, "^G", X /* 010 */ 2, "^H", X /* 011 */ 2, "^I", X /* 012 */ 7, "[ERROR]", /* shouldn't occur */ X /* 013 */ 2, "^K", X /* 014 */ 2, "^L", X /* 015 */ 2, "^M", X /* 016 */ 2, "^N", X /* 017 */ 2, "^O", X /* 020 */ 2, "^P", X /* 021 */ 2, "^Q", X /* 022 */ 2, "^R", X /* 023 */ 2, "^S", X /* 024 */ 2, "^T", X /* 025 */ 2, "^U", X /* 026 */ 2, "^V", X /* 027 */ 2, "^W", X /* 030 */ 2, "^X", X /* 031 */ 2, "^Y", X /* 032 */ 2, "^Z", X /* 033 */ 2, "^[", X /* 034 */ 2, "^\\", X /* 035 */ 2, "^]", X /* 036 */ 2, "^^", X /* 037 */ 2, "^_", X /* 040 */ 1, NULL, X /* 041 */ 1, NULL, X /* 042 */ 1, NULL, X /* 043 */ 1, NULL, X /* 044 */ 1, NULL, X /* 045 */ 1, NULL, X /* 046 */ 1, NULL, X /* 047 */ 1, NULL, X /* 050 */ 1, NULL, X /* 051 */ 1, NULL, X /* 052 */ 1, NULL, X /* 053 */ 1, NULL, X /* 054 */ 1, NULL, X /* 055 */ 1, NULL, X /* 056 */ 1, NULL, X /* 057 */ 1, NULL, X /* 060 */ 1, NULL, X /* 061 */ 1, NULL, X /* 062 */ 1, NULL, X /* 063 */ 1, NULL, X /* 064 */ 1, NULL, X /* 065 */ 1, NULL, X /* 066 */ 1, NULL, X /* 067 */ 1, NULL, X /* 070 */ 1, NULL, X /* 071 */ 1, NULL, X /* 072 */ 1, NULL, X /* 073 */ 1, NULL, X /* 074 */ 1, NULL, X /* 075 */ 1, NULL, X /* 076 */ 1, NULL, X /* 077 */ 1, NULL, X /* 100 */ 1, NULL, X /* 101 */ 1, NULL, X /* 102 */ 1, NULL, X /* 103 */ 1, NULL, X /* 104 */ 1, NULL, X /* 105 */ 1, NULL, X /* 106 */ 1, NULL, X /* 107 */ 1, NULL, X /* 110 */ 1, NULL, X /* 111 */ 1, NULL, X /* 112 */ 1, NULL, X /* 113 */ 1, NULL, X /* 114 */ 1, NULL, X /* 115 */ 1, NULL, X /* 116 */ 1, NULL, X /* 117 */ 1, NULL, X /* 120 */ 1, NULL, X /* 121 */ 1, NULL, X /* 122 */ 1, NULL, X /* 123 */ 1, NULL, X /* 124 */ 1, NULL, X /* 125 */ 1, NULL, X /* 126 */ 1, NULL, X /* 127 */ 1, NULL, X /* 130 */ 1, NULL, X /* 131 */ 1, NULL, X /* 132 */ 1, NULL, X /* 133 */ 1, NULL, X /* 134 */ 1, NULL, X /* 135 */ 1, NULL, X /* 136 */ 1, NULL, X /* 137 */ 1, NULL, X /* 140 */ 1, NULL, X /* 141 */ 1, NULL, X /* 142 */ 1, NULL, X /* 143 */ 1, NULL, X /* 144 */ 1, NULL, X /* 145 */ 1, NULL, X /* 146 */ 1, NULL, X /* 147 */ 1, NULL, X /* 150 */ 1, NULL, X /* 151 */ 1, NULL, X /* 152 */ 1, NULL, X /* 153 */ 1, NULL, X /* 154 */ 1, NULL, X /* 155 */ 1, NULL, X /* 156 */ 1, NULL, X /* 157 */ 1, NULL, X /* 160 */ 1, NULL, X /* 161 */ 1, NULL, X /* 162 */ 1, NULL, X /* 163 */ 1, NULL, X /* 164 */ 1, NULL, X /* 165 */ 1, NULL, X /* 166 */ 1, NULL, X /* 167 */ 1, NULL, X /* 170 */ 1, NULL, X /* 171 */ 1, NULL, X /* 172 */ 1, NULL, X /* 173 */ 1, NULL, X /* 174 */ 1, NULL, X /* 175 */ 1, NULL, X /* 176 */ 1, NULL, X /* 177 */ 2, "^?", X}; END_OF_FILE if test 3413 -ne `wc -c <'hexchars.c'`; then echo shar: \"'hexchars.c'\" unpacked with wrong size! fi # end of 'hexchars.c' fi if test -f 'keymap.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'keymap.h'\" else echo shar: Extracting \"'keymap.h'\" \(1076 characters\) sed "s/^X//" >'keymap.h' <<'END_OF_FILE' X/* X * $Header: keymap.h,v 1.1 88/03/20 21:03:51 tony Exp $ X * X * Keycode definitions for special keys X * X * On systems that have any of these keys, the routine 'inchar' in the X * machine-dependent code should return one of the codes here. X * X * $Log: keymap.h,v $ X * Revision 1.1 88/03/20 21:03:51 tony X * Initial revision X * X * X */ X X#define K_HELP 0x80 X#define K_UNDO 0x81 X#define K_INSERT 0x82 X#define K_HOME 0x83 X#define K_UARROW 0x84 X#define K_DARROW 0x85 X#define K_LARROW 0x86 X#define K_RARROW 0x87 X#ifdef ATARI X#define K_CGRAVE 0x88 /* control grave accent */ X#else X#define K_CGRAVE 036 /* control grave accent */ X#endif X X#define K_F1 0x91 /* function keys */ X#define K_F2 0x92 X#define K_F3 0x93 X#define K_F4 0x94 X#define K_F5 0x95 X#define K_F6 0x96 X#define K_F7 0x97 X#define K_F8 0x98 X#define K_F9 0x99 X#define K_F10 0x9a X X#define K_SF1 0xa1 /* shifted function keys */ X#define K_SF2 0xa2 X#define K_SF3 0xa3 X#define K_SF4 0xa4 X#define K_SF5 0xa5 X#define K_SF6 0xa6 X#define K_SF7 0xa7 X#define K_SF8 0xa8 X#define K_SF9 0xa9 X#define K_SF10 0xaa END_OF_FILE if test 1076 -ne `wc -c <'keymap.h'`; then echo shar: \"'keymap.h'\" unpacked with wrong size! fi # end of 'keymap.h' fi if test -f 'linefunc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'linefunc.c'\" else echo shar: Extracting \"'linefunc.c'\" \(1656 characters\) sed "s/^X//" >'linefunc.c' <<'END_OF_FILE' Xstatic char RCSid[] = X"$Header: linefunc.c,v 1.1 88/03/20 21:08:07 tony Exp $"; X X/* X * Basic line-oriented motions. X * X * $Log: linefunc.c,v $ X * Revision 1.1 88/03/20 21:08:07 tony X * Initial revision X * X * X */ X X#include "stevie.h" X X/* X * nextline(curr) X * X * Return a pointer to the beginning of the next line after the one X * referenced by 'curr'. Return NULL if there is no next line (at EOF). X */ X XLPTR * Xnextline(curr) XLPTR *curr; X{ X static LPTR next; X X if (curr->linep->next != Fileend->linep) { X next.index = 0; X next.linep = curr->linep->next; X return &next; X } X return (LPTR *) NULL; X} X X/* X * prevline(curr) X * X * Return a pointer to the beginning of the line before the one X * referenced by 'curr'. Return NULL if there is no prior line. X */ X XLPTR * Xprevline(curr) XLPTR *curr; X{ X static LPTR prev; X X if (curr->linep->prev != Filetop->linep) { X prev.index = 0; X prev.linep = curr->linep->prev; X return &prev; X } X return (LPTR *) NULL; X} X X/* X * coladvance(p,col) X * X * Try to advance to the specified column, starting at p. X */ X XLPTR * Xcoladvance(p, col) XLPTR *p; Xint col; X{ X static LPTR lp; X int c, in; X X lp.linep = p->linep; X lp.index = p->index; X X /* If we're on a blank ('\n' only) line, we can't do anything */ X if (lp.linep->s[lp.index] == '\0') X return &lp; X /* try to advance to the specified column */ X for ( c=0; col-- > 0; c++ ) { X /* Count a tab for what it's worth (if list mode not on) */ X if ( gchar(&lp) == TAB && !P(P_LS) ) { X in = ((P(P_TS)-1) - c%P(P_TS)); X col -= in; X c += in; X } X /* Don't go past the end of */ X /* the file or the line. */ X if (inc(&lp)) { X dec(&lp); X break; X } X } X return &lp; X} END_OF_FILE if test 1656 -ne `wc -c <'linefunc.c'`; then echo shar: \"'linefunc.c'\" unpacked with wrong size! fi # end of 'linefunc.c' fi echo shar: End of shell archive. exit 0