diff --git a/libexec/elvispreserve/Makefile b/libexec/elvispreserve/Makefile index 67e1ab03eedd..b3e824b05b61 100644 --- a/libexec/elvispreserve/Makefile +++ b/libexec/elvispreserve/Makefile @@ -1,6 +1,8 @@ PROG= elvispreserve CFLAGS= -I${.CURDIR}/../../usr.bin/elvis +BINOWN= root +BINMODE=4755 MAN8=elvispreserve.0 .include diff --git a/libexec/elvispreserve/elvispreserve.8 b/libexec/elvispreserve/elvispreserve.8 index 9c7e74f97435..065fb2b12093 100644 --- a/libexec/elvispreserve/elvispreserve.8 +++ b/libexec/elvispreserve/elvispreserve.8 @@ -1,15 +1,15 @@ -.TH ELVISPRESERVE 8 +.TH ELVPRSV 1 .SH NAME -elvispreserve - Preserve the the modified version of a file after a crash. +elvprsv - Preserve the the modified version of a file after a crash. .SH SYNOPSIS .nf -\fB\fBelvispreserve\fP ["-\fIwhy elvis died\fP"] /tmp/\fIfilename\fP... -\fB\fBelvispreserve\fP -R /tmp/\fIfilename\fP... +\fB\fBelvprsv\fP ["-\fIwhy elvis died\fP"] /tmp/\fIfilename\fP... +\fB\fBelvprsv\fP -R /tmp/\fIfilename\fP... .fi .SH DESCRIPTION .PP -\fIelvispreserve\fP preserves your edited text after \fIelvis\fP dies. -The text can be recovered later, via the \fIelvispreserve\fP program. +\fIelvprsv\fP preserves your edited text after \fIelvis\fP dies. +The text can be recovered later, via the \fIelvprsv\fP program. .PP For UNIX-like systems, you should never need to run this program from the command line. @@ -17,35 +17,35 @@ It is run automatically when \fIelvis\fP is about to die, and it should be run (via /etc/rc) when the computer is booted. THAT'S ALL! .PP -For non-UNIX systems such as MS-DOS, you can either use \fIelvispreserve\fP +For non-UNIX systems such as MS-DOS, you can either use \fIelvprsv\fP the same way as under UNIX systems (by running it from your AUTOEXEC.BAT file), or you can run it separately with the "-R" flag to recover the files in one step. .PP If you're editing a file when \fIelvis\fP dies (due to a bug, system crash, power failure, etc.) -then \fIelvispreserve\fP will preserve the most recent version of your text. +then \fIelvprsv\fP will preserve the most recent version of your text. The preserved text is stored in a special directory; it does NOT overwrite your text file automatically. .PP -\fIelvispreserve\fP will send mail to any user whose work it preserves, +\fIelvprsv\fP will send mail to any user whose work it preserves, if your operating system normally supports mail. .SH FILES .IP /tmp/elv* The temporary file that \fIelvis\fP was using when it died. .IP /usr/preserve/p* -The text that is preserved by \fIelvispreserve\fP. +The text that is preserved by \fIelvprsv\fP. .IP /usr/preserve/Index A text file which lists the names of all preserved files, and the names of the /usr/preserve/p* files which contain their preserved text. .SH BUGS .PP Due to the permissions on the /usr/preserve directory, on UNIX systems -\fIelvispreserve\fP must be run as superuser. -This is accomplished by making the \fIelvispreserve\fP executable be owned by "root" +\fIelvprsv\fP must be run as superuser. +This is accomplished by making the \fIelvprsv\fP executable be owned by "root" and turning on its "set user id" bit. .PP -If you're editing a nameless buffer when \fIelvis\fP dies, then \fIelvispreserve\fP will pretend +If you're editing a nameless buffer when \fIelvis\fP dies, then \fIelvprsv\fP will pretend that the file was named "foo". .SH AUTHOR .nf diff --git a/libexec/elvispreserve/elvispreserve.c b/libexec/elvispreserve/elvispreserve.c index b9e72725e133..f5a76e40b6ee 100644 --- a/libexec/elvispreserve/elvispreserve.c +++ b/libexec/elvispreserve/elvispreserve.c @@ -53,6 +53,17 @@ #include "config.h" #include "vi.h" +/* We include ctype.c here (instead of including just ctype.h and linking + * with ctype.o) because on some systems ctype.o will have been compiled in + * "large model" and the elvprsv program is to be compiled in "small model" + * You can't mix models. By including ctype.c here, we can avoid linking + * with ctype.o. + */ +#include "ctype.c" + +void preserve P_((char *, char *)); +void main P_((int, char **)); + #if AMIGA BLK tmpblk; # include "amiwild.c" @@ -121,7 +132,7 @@ void preserve(tname, when) || read(infd, name.c, BLKSIZE) != BLKSIZE) { /* something wrong with the file - sorry */ - fprintf(stderr, "%s: trucated header blocks\n", tname); + fprintf(stderr, "%s: truncated header blocks\n", tname); close(infd); return; } @@ -138,6 +149,16 @@ void preserve(tname, when) return; } + /* If there are no text blocks in the file, then we must've never + * really started editing. Discard the file. + */ + if (hdr.n[1] == 0) + { + close(infd); + unlink(tname); + return; + } + if (rewrite_now) { /* we don't need to open the index file */ @@ -147,7 +168,8 @@ void preserve(tname, when) for (i = 1; i < MAXBLKS && hdr.n[i]; i++) { lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0); - if (read(infd, buf.c, BLKSIZE) != BLKSIZE) + if (read(infd, buf.c, BLKSIZE) != BLKSIZE + || buf.c[0] == '\0') { /* messed up header */ fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c); @@ -172,9 +194,12 @@ void preserve(tname, when) if (!index) { perror(PRSVINDEX); - exit(1); + exit(2); } + /* should be at the end of the file already, but MAKE SURE */ + fseek(index, 0L, 2); + /* create the recovery file in the PRESVDIR directory */ #if AMIGA prsvdir = &PRSVDIR[strlen(PRSVDIR) - 1]; @@ -199,7 +224,8 @@ void preserve(tname, when) for (i = 1; i < MAXBLKS && hdr.n[i]; i++) { lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0); - if (read(infd, buf.c, BLKSIZE) != BLKSIZE) + if (read(infd, buf.c, BLKSIZE) != BLKSIZE + || buf.c[0] == '\0') { /* messed up header */ fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c); @@ -242,7 +268,7 @@ void preserve(tname, when) } } -main(argc, argv) +void main(argc, argv) int argc; char **argv; { @@ -251,10 +277,11 @@ main(argc, argv) #if MSDOS || TOS /* expand any wildcards in the command line */ + _ct_init(""); argv = wildexpand(&argc, argv); #endif - /* do we have a "when" argument? */ + /* do we have a "-c", "-R", or "-when elvis died" argument? */ i = 1; if (argc >= i + 1 && !strcmp(argv[i], "-R")) { diff --git a/usr.bin/Makefile b/usr.bin/Makefile index 1c386784922c..82ed0e5311d6 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -1,6 +1,6 @@ # @(#)Makefile 5.8.1.1 (Berkeley) 5/8/91 # -# $Header: /cvsroot/src/usr.bin/Makefile,v 1.7 1993/04/04 20:14:43 cgd Exp $ +# $Header: /cvsroot/src/usr.bin/Makefile,v 1.8 1993/04/08 02:22:57 cgd Exp $ # BROKEN: tn3270 rcs @@ -13,7 +13,7 @@ SUBDIR= ar awk biff basename cal calendar \ login logname lorder m4 machine mail make man mesg mkdep mkfifo \ mkstr more netstat nfsstat nice nm nohup pagesize \ passwd paste pr printenv printf ranlib \ - rdist renice rlogin rpcgen rpcinfo rsh ruptime rwall rwho \ + rdist ref renice rlogin rpcgen rpcinfo rsh ruptime rwall rwho \ script sed shar showmount size soelim sort split strings \ strip su symorder tail talk tar tee telnet tftp time \ tip touch tput tr true tsort tty ul unexpand unifdef uniq \ diff --git a/usr.bin/elvis/blk.c b/usr.bin/elvis/blk.c index db41d9320e2b..091962dab7ae 100644 --- a/usr.bin/elvis/blk.c +++ b/usr.bin/elvis/blk.c @@ -38,6 +38,9 @@ static struct _blkbuf +void blkflush P_((REG struct _blkbuf *this)); + + /* This function wipes out all buffers */ @@ -72,7 +75,7 @@ BLK *blkget(logical) /* see if we have that block in mem already */ for (this = blk; this < &blk[NBUFS]; this++) { - if (this->logical == logical) + if (this->logical == (unsigned)logical) { newtoo = toonew; toonew = this; @@ -162,6 +165,7 @@ void blkflush(this) if (write(tmpfd, this->buf.c, (unsigned)BLKSIZE) != BLKSIZE) { msg("Trouble writing to tmp file"); + deathtrap(0); } this->dirty = FALSE; @@ -243,7 +247,7 @@ void blkdirty(bp) k = blk[i].logical; for (j = 0; j < NBUFS; j++) { - if (blk[j].logical >= k) + if (blk[j].logical >= (unsigned)k) { blk[j].logical--; } @@ -268,8 +272,21 @@ void blkdirty(bp) BLK *blkadd(logical) int logical; /* where to insert the new block */ { + static long chg; REG int i; + /* if we're approaching the limit, then give a warning */ + if (hdr.n[MAXBLKS - 10] && chg != changes) + { + chg = changes; + msg("WARNING: The edit buffer will overflow soon."); + } + if (hdr.n[MAXBLKS - 2]) + { + msg("BAD NEWS: edit buffer overflow -- GOOD NEWS: text preserved"); + deathtrap(0); + } + /* adjust hdr and lnum[] */ for (i = MAXBLKS - 1; i > logical; i--) { @@ -282,7 +299,7 @@ BLK *blkadd(logical) /* adjust the cache */ for (i = 0; i < NBUFS; i++) { - if (blk[i].logical >= logical) + if (blk[i].logical >= (unsigned)logical) { blk[i].logical++; } @@ -343,7 +360,8 @@ void beforedo(forundo) lseek(tmpfd, 0L, 0); if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) != BLKSIZE) { - msg("Trouble writing header to tmp file "); + msg("Trouble writing header to tmp file"); + deathtrap(0); } /* copy or swap oldnlines <--> nlines, oldlnum <--> lnum */ diff --git a/usr.bin/elvis/cmd1.c b/usr.bin/elvis/cmd1.c index b322ec41226d..406cd7fe45cc 100644 --- a/usr.bin/elvis/cmd1.c +++ b/usr.bin/elvis/cmd1.c @@ -17,6 +17,19 @@ #include "vi.h" #include "regexp.h" +#ifndef NO_TAGSTACK +/* These describe the current state of the tag related commands */ +#define MAXTAGS 15 + +struct Tag_item { + MARK tag_mark; + char *tag_file; +}; + +static struct Tag_item tag_stack[MAXTAGS]; +static int curr_tag = -1; +#endif /* !NO_TAGSTACK */ + #ifdef DEBUG /* print the selected lines with info on the blocks */ /*ARGSUSED*/ @@ -197,7 +210,7 @@ void cmd_write(frommark, tomark, cmd, bang, extra) } /* either the file must not exist, or we must have a ! or be appending */ - if (access(extra, 0) == 0 && !bang && !append) + if (*extra && access(extra, 0) == 0 && !bang && !append) { msg("File already exists - Use :w! to overwrite"); return; @@ -337,7 +350,7 @@ void cmd_global(frommark, tomark, cmd, bang, extra) } /* make sure we got a search pattern */ - if (*extra != '/' && *extra != '?') + if (*extra == ' ' || *extra == '\n') { msg("Usage: %c /regular expression/ command", cmd == CMD_GLOBAL ? 'g' : 'v'); return; @@ -395,7 +408,7 @@ void cmd_global(frommark, tomark, cmd, bang, extra) doingglobal = FALSE; /* free the regexp */ - free(re); + _free_(re); /* Reporting...*/ rptlines = nchanged; @@ -421,9 +434,9 @@ void cmd_file(frommark, tomark, cmd, bang, extra) if (cmd == CMD_FILE) { #ifndef CRUNCH - msg("\"%s\" %s%s%s %ld lines, line %ld [%ld%%]", + msg("\"%s\" %s%s%s line %ld of %ld [%ld%%]", #else - msg("\"%s\" %s%s %ld lines, line %ld [%ld%%]", + msg("\"%s\" %s%s line %ld of %ld [%ld%%]", #endif *origname ? origname : "[NO FILE]", tstflag(file, MODIFIED) ? "[MODIFIED]" : "", @@ -431,8 +444,8 @@ void cmd_file(frommark, tomark, cmd, bang, extra) tstflag(file, NOTEDITED) ?"[NOT EDITED]":"", #endif tstflag(file, READONLY) ? "[READONLY]" : "", - nlines, markline(frommark), + nlines, markline(frommark) * 100 / nlines); } #ifndef CRUNCH @@ -590,8 +603,8 @@ void cmd_next(frommark, tomark, cmd, bang, extra) } } -/* also called from :wq -- always writes back in this case */ - +/* also called for :wq -- always writes back in this case */ +/* also called for :q -- never writes back in that case */ /*ARGSUSED*/ void cmd_xit(frommark, tomark, cmd, bang, extra) MARK frommark, tomark; @@ -602,45 +615,40 @@ void cmd_xit(frommark, tomark, cmd, bang, extra) static long whenwarned; /* when the user was last warned of extra files */ int oldflag; - /* if there are more files to edit, then warn user */ - if (argno >= 0 && argno + 1 < nargs && whenwarned != changes && (!bang || cmd != CMD_QUIT)) + /* Unless the command is ":q", save the file if it has been modified */ + if (cmd != CMD_QUIT + && (cmd == CMD_WQUIT || tstflag(file, MODIFIED)) + && !tmpsave((char *)0, FALSE) && !bang) + { + msg("Could not save file -- use quit! to abort changes, or w filename"); + return; + } + + /* If there are more files to edit, then warn user */ + if (argno >= 0 && argno + 1 < nargs /* more args */ + && whenwarned != changes /* user not already warned */ + && (!bang || cmd != CMD_QUIT)) /* command not ":q!" */ { msg("More files to edit -- Use \":n\" to go to next file"); whenwarned = changes; return; } - if (cmd == CMD_QUIT) + /* Discard the temp file. Note that we should already have saved the + * the file, unless the command is ":q", so the only way that tmpabort + * could fail would be if you did a ":q" on a modified file. + */ + oldflag = *o_autowrite; + *o_autowrite = FALSE; + if (tmpabort(bang)) { - oldflag = *o_autowrite; - *o_autowrite = FALSE; - if (tmpabort(bang)) - { - mode = MODE_QUIT; - } - else - { - msg("Use q! to abort changes, or wq to save changes"); - } - *o_autowrite = oldflag; + mode = MODE_QUIT; } else { - /* else try to save this file */ - oldflag = tstflag(file, MODIFIED); - if (cmd == CMD_WQUIT) - setflag(file, MODIFIED); - if (tmpend(bang)) - { - mode = MODE_QUIT; - } - else - { - msg("Could not save file -- use quit! to abort changes, or w filename"); - } - if (!oldflag) - clrflag(file, MODIFIED); + msg("Use q! to abort changes, or wq to save changes"); } + *o_autowrite = oldflag; } @@ -746,8 +754,6 @@ void cmd_cd(frommark, tomark, cmd, bang, extra) int bang; char *extra; { - char *getenv(); - #ifndef CRUNCH /* if current file is modified, and no '!' was given, then error */ if (tstflag(file, MODIFIED) && !bang) @@ -759,7 +765,7 @@ void cmd_cd(frommark, tomark, cmd, bang, extra) /* default directory name is $HOME */ if (!*extra) { - extra = getenv("HOME"); + extra = gethome((char *)0); if (!extra) { msg("environment variable $HOME not set"); @@ -928,7 +934,14 @@ void cmd_tag(frommark, tomark, cmd, bang, extra) #ifdef INTERNAL_TAGS char *cmp; /* char of tag name we're comparing, or NULL */ char *end; /* marks the end of chars in tmpblk.c */ + char file[128]; /* name of file containing tag */ + int found; /* whether the tag has been found */ + int file_exists; /* whether any tag file exists */ + char *s, *t; #else +# ifndef NO_TAGSTACK + char *s; +# endif int i; #endif #ifndef NO_MAGIC @@ -971,66 +984,96 @@ void cmd_tag(frommark, tomark, cmd, bang, extra) *scan = '\0'; /* close the pipe. abort if error */ - if (rpclose(fd) != 0 || scan < tmpblk.c + 3) + if (rpclose(fd) != 0) + { + msg("Trouble running \"ref\" -- Can't do tag lookup"); + return; + } + else if (scan < tmpblk.c + 3) { msg("tag \"%s\" not found", extra); return; } #else /* use internal code to look up the tag */ - /* open the tags file */ - fd = open(TAGS, O_RDONLY); - if (fd < 0) - { + found = 0; + file_exists = 0; + s = o_tags; + while (!found && *s != 0) { + while (isspace(*s)) s++; + for(t = file; s && *s && !isspace(*s); s++) + *t++ = *s; + *t = '\0'; + + /* open the next tags file */ + fd = open(file, O_RDONLY); + if (fd < 0) + continue; + else + file_exists = 1; + + /* Hmmm... this would have been a lot easier with */ + + /* find the line with our tag in it */ + for(scan = end = tmpblk.c, cmp = extra; ; scan++) + { + /* read a block, if necessary */ + if (scan >= end) + { + end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE); + scan = tmpblk.c; + if (scan >= end) + { + close(fd); + break; + } + } + + /* if we're comparing, compare... */ + if (cmp) + { + /* matched??? wow! */ + if (!*cmp && *scan == '\t') + { + if ((s = strrchr(file, '/')) != 0 || + (s = strrchr(file, '\\')) != 0) + ++s; + else + s = file; + *s = '\0'; + found = 1; + break; + } + if (*cmp++ != *scan) + { + /* failed! skip to newline */ + cmp = (char *)0; + } + } + + /* if we're skipping to newline, do it fast! */ + if (!cmp) + { + while (scan < end && *scan != '\n') + { + scan++; + } + if (scan < end) + { + cmp = extra; + } + } + } + } + + if (!file_exists) { msg("No tags file"); return; } - /* Hmmm... this would have been a lot easier with */ - - /* find the line with our tag in it */ - for(scan = end = tmpblk.c, cmp = extra; ; scan++) - { - /* read a block, if necessary */ - if (scan >= end) - { - end = tmpblk.c + tread(fd, tmpblk.c, BLKSIZE); - scan = tmpblk.c; - if (scan >= end) - { - msg("tag \"%s\" not found", extra); - close(fd); - return; - } - } - - /* if we're comparing, compare... */ - if (cmp) - { - /* matched??? wow! */ - if (!*cmp && *scan == '\t') - { - break; - } - if (*cmp++ != *scan) - { - /* failed! skip to newline */ - cmp = (char *)0; - } - } - - /* if we're skipping to newline, do it fast! */ - if (!cmp) - { - while (scan < end && *scan != '\n') - { - scan++; - } - if (scan < end) - { - cmp = extra; - } - } + if (!found) { + msg("tag \"%s\" not found", extra); + return; } /* found it! get the rest of the line into memory */ @@ -1062,7 +1105,32 @@ void cmd_tag(frommark, tomark, cmd, bang, extra) return; } tmpstart(tmpblk.c); +#ifdef NO_TAGSTACK } +#else /* tagstack enabled */ + s = prevorig; + } + else + s = origname; + + if (frommark != MARK_UNSET && *s && *o_tagstack) + { + curr_tag++; + if (curr_tag >= MAXTAGS) + { + /* discard the oldest tag position */ + free(tag_stack[0].tag_file); + for (curr_tag = 0; curr_tag < MAXTAGS - 1; curr_tag++) + { + tag_stack[curr_tag] = tag_stack[curr_tag + 1]; + } + /* at this point, curr_tag = MAXTAGS-1 */ + } + tag_stack[curr_tag].tag_file = (char *) malloc(strlen(s) + 1); + strcpy(tag_stack[curr_tag].tag_file, s); + tag_stack[curr_tag].tag_mark = frommark; + } +#endif /* move to the desired line (or to line 1 if that fails) */ #ifndef NO_MAGIC @@ -1082,6 +1150,44 @@ void cmd_tag(frommark, tomark, cmd, bang, extra) } +#ifndef NO_TAGSTACK +/*ARGSUSED*/ +void cmd_pop(frommark, tomark, cmd, bang, extra) + MARK frommark, tomark; + CMD cmd; + int bang; + char *extra; +{ + char buf[8]; + + if (!*o_tagstack) + { + msg("Tagstack not enabled"); + return; + } + + if (curr_tag < 0) + msg("Tagstack empty"); + else + { + if (strcmp(origname, tag_stack[curr_tag].tag_file) != 0) + { + if (!tmpabort(bang)) + { + msg("Use :pop! to abort changes, or :w to save changes"); + return; + } + tmpstart(tag_stack[curr_tag].tag_file); + } + cursor = tag_stack[curr_tag].tag_mark; + if (cursor < MARK_FIRST || cursor > MARK_LAST + BLKSIZE) + { + cursor = MARK_FIRST; + } + free(tag_stack[curr_tag--].tag_file); + } +} +#endif @@ -1247,7 +1353,7 @@ static char *parse_errmsg(text) } /* if the number is part of a larger word, then ignore this line */ - if (*text && isalpha(text[-1])) + if (*text && (isalpha(text[-1]) || text[-1] == '_')) { return (char *)0; } @@ -1451,15 +1557,38 @@ void cmd_make(frommark, tomark, cmd, bang, extra) errfd = -3; } +#if MINT + /* I guess MiNT can't depend on the shell for redirection? */ + close(creat(ERRLIST, 0666)); + if ((fd = open(ERRLIST, O_RDWR)) == -1) + { + unlink(ERRLIST); + return; + } + suspend_curses(); + old2 = dup(2); + dup2(fd, 2); + system(buf.c); + dup2(old2, 2); + close(old2); + close(fd); +#else /* run the command, with curses temporarily disabled */ suspend_curses(); system(buf.c); +#endif resume_curses(mode == MODE_EX); if (mode == MODE_COLON) - mode = MODE_VI; + /* ':' hit instead of CR, so let him escape... -nox */ + return; /* run the "errlist" command */ cmd_errlist(MARK_UNSET, MARK_UNSET, cmd, bang, ERRLIST); + + /* avoid spurious `Hit ' after 1st error message -nox */ + /* (which happened when cmd_errlist didn't have to change files...) */ + if (mode == MODE_VI) + refresh(); } #endif @@ -1738,9 +1867,9 @@ void cmd_suspend(frommark, tomark, cmd, bang, extra) int bang; char *extra; { - void (*func)(); /* stores the previous setting of SIGTSTP */ + SIGTYPE (*func)(); /* stores the previous setting of SIGTSTP */ -#if !defined(__386BSD__) && defined(ANY_UNIX) +#if ANY_UNIX /* the Bourne shell can't handle ^Z */ if (!strcmp(o_shell, "/bin/sh")) { @@ -1749,11 +1878,6 @@ void cmd_suspend(frommark, tomark, cmd, bang, extra) } #endif - func = signal(SIGTSTP, SIG_DFL); - if ( func == SIG_IGN ) { - msg("SIGTSTP is being ignored, you may not suspend the editor", func); - return; - } move(LINES - 1, 0); if (tstflag(file, MODIFIED)) { @@ -1764,7 +1888,7 @@ void cmd_suspend(frommark, tomark, cmd, bang, extra) } refresh(); suspend_curses(); - /* was here func = signal(SIGTSTP, SIG_DFL); /* races ??? */ + func = signal(SIGTSTP, SIG_DFL); kill (0, SIGTSTP); /* the process stops and resumes here */ diff --git a/usr.bin/elvis/cmd2.c b/usr.bin/elvis/cmd2.c index 5d88acc1f107..25bf69a8e507 100644 --- a/usr.bin/elvis/cmd2.c +++ b/usr.bin/elvis/cmd2.c @@ -76,7 +76,7 @@ void cmd_substitute(frommark, tomark, cmd, bang, extra) else /* CMD_SUBSTITUTE */ { /* make sure we got a search pattern */ - if (*extra != '/' && *extra != '?') + if (*extra == ' ' || *extra == '\n') { msg("Usage: s/regular expression/new text/"); return; @@ -253,7 +253,7 @@ Continue: } /* free the regexp */ - free(re); + _free_(re); /* if done from within a ":g" command, then finish silently */ if (doingglobal) @@ -447,7 +447,7 @@ void cmd_join(frommark, tomark, cmd, bang, extra) } /* see if the line will fit */ - if (strlen(scan) + len + 3 > BLKSIZE) + if (strlen(scan) + len + 3 > (unsigned)BLKSIZE) { msg("Can't join -- the resulting line would be too long"); return; @@ -461,10 +461,14 @@ void cmd_join(frommark, tomark, cmd, bang, extra) if (tmpblk.c[len - 1] == '.' || tmpblk.c[len - 1] == '?' || tmpblk.c[len - 1] == '!') + { + tmpblk.c[len++] = ' '; + tmpblk.c[len++] = ' '; + } + else if (tmpblk.c[len - 1] != ' ') { tmpblk.c[len++] = ' '; } - tmpblk.c[len++] = ' '; } } strcpy(tmpblk.c + len, scan); @@ -769,7 +773,7 @@ void cmd_print(frommark, tomark, cmd, bang, extra) col++; } while (col % *o_tabstop != 0); } - else if (*scan > 0 && *scan < ' ' || *scan == '\177') + else if (*scan >= 1 && *scan < ' ' || *scan == '\177') { qaddch('^'); qaddch(*scan ^ 0x40); @@ -801,6 +805,9 @@ void cmd_print(frommark, tomark, cmd, bang, extra) addch('\n'); exrefresh(); } + + /* leave the cursor on the last line printed */ + cursor = tomark; } diff --git a/usr.bin/elvis/config.h b/usr.bin/elvis/config.h index ef121fd5c2e0..9ad48e80b225 100644 --- a/usr.bin/elvis/config.h +++ b/usr.bin/elvis/config.h @@ -1,28 +1,225 @@ /* * vi configuration file + * We try to automatically configure to various compilers and operating + * systems. Extend the autoconf section as needed. */ -# define BSD 1 +#ifndef _CONFIG_H +# define _CONFIG_H +/*************************** autoconf section ************************/ + +/* Commodore-Amiga */ +#ifdef amiga +# define AMIGA 1 +# define COMPILED_BY "Manx Aztec C 5.2b" +# define TINYSTACK 1 +#endif + +/* standard unix V (?) */ +#ifdef M_SYSV +# define UNIXV 1 +# ifdef M_XENIX +# ifndef M_I386 +# define TINYSTACK 1 +# endif +# endif +# undef COHERENT +#endif + +/* xelos system, University of Ulm */ +#ifdef xelos +# define UNIXV 1 +#endif + +/* BSD UNIX? */ +#ifdef bsd +# define BSD 1 +#else +# ifdef sun +# ifndef M_SYSV +# define BSD 1 +# endif +# endif +#endif + +/* Microsoft C: sorry, Watcom does the same thing */ +#ifdef M_I86 +# ifndef M_SYSV +# define MSDOS 1 +# ifdef IBMC2 +# define COMPILED_BY "IBM C/2 1.00" +# else +# define MICROSOFT 1 +# define COMPILED_BY "Microsoft C 5.10" +# endif +# define TINYSTACK 1 +# endif +#endif + +/* Borland's Turbo C */ +#ifdef __TURBOC__ +# define MSDOS 1 +# define TURBOC 1 +# ifdef __BORLANDC__ +# define COMPILED_BY "Borland C 2.00" +# else +# define COMPILED_BY (__TURBOC__ >= 661 ? "Turbo C++ 1.00" : "Turbo C 2.00") +# endif +# define TINYSTACK 1 +#endif + +/* Tos Mark-Williams */ +#ifdef M68000 +# define TOS 1 +# define COMPILED_BY "Mark Williams C" +# define TINYSTACK 1 +#endif + +/* Tos GNU-C */ +#ifdef __atarist__ +# ifdef __gem__ +# define TOS 1 +# define COMPILED_BY "GNU-C " __VERSION__ +# define TINYSTACK 1 +# endif +#endif + +/* OS9/68000 */ +#ifdef OSK +# define COMPILED_BY "Microware C V2.3 Edition 40" +# define TINYSTACK 1 +#endif + +/* DEC Rainbow, running MS-DOS (handled by earlier MS-DOS tests) */ +/* (would need -DRAINBOW in CFLAGS to compile a Rainbow-compatible .EXE) */ + +#ifdef VMS +# define COMPILED_BY "VAX/VMS VAXC compiler" +# undef VMS +# define VMS 1 +#endif + + +#ifdef COHERENT +# ifdef _I386 +# define COH_386 1 +# define COH_286 0 +# else +# define COH_386 0 +# define COH_286 1 +# endif +# undef COHERENT +# define COHERENT 1 +#endif + +/*************************** end of autoconf section ************************/ /* All undefined symbols are defined to zero here, to allow for older */ /* compilers which dont understand #if defined() or #if UNDEFINED_SYMBOL */ -# define UNIXV 0 /* UNIX - AT&T SYSV */ -# define UNIX7 0 /* UNIX - version 7 */ -# define MSDOS 0 /* PC */ -# define TOS 0 /* Atari ST */ -# define AMIGA 0 /* Commodore Amiga */ -# define OSK 0 /* OS-9 / 68k */ -# define COHERENT 0 /* Coherent */ -# define MINIX 0 +/*************************** operating systems *****************************/ + +#ifndef BSD +# define BSD 0 /* UNIX - Berkeley 4.x */ +#endif +#ifndef UNIXV +# define UNIXV 0 /* UNIX - AT&T SYSV */ +#endif + +#ifndef UNIX7 +# define UNIX7 0 /* UNIX - version 7 */ +#endif + +#ifndef MSDOS +# define MSDOS 0 /* PC */ +#endif + +#ifndef TOS +# define TOS 0 /* Atari ST */ +#endif + +#ifndef AMIGA +# define AMIGA 0 /* Commodore Amiga */ +#endif + +#ifndef OSK +# define OSK 0 /* OS-9 / 68k */ +#endif + +#ifndef COHERENT +# define COHERENT 0 /* Coherent */ +#endif + +#ifndef RAINBOW /* DEC Rainbow support, under MS-DOS */ +# define RAINBOW 0 +#endif + +#ifndef VMS +# define VMS 0 /* VAX/VMS */ +#endif + + /* Minix has no predefines */ +#if !BSD && !UNIXV && !UNIX7 && !MSDOS && !TOS && !AMIGA && !OSK && !COHERENT && !VMS +# define MINIX 1 +#else +# define MINIX 0 +#endif + + /* generic combination of Unices */ +#if UNIXV || UNIX7 || BSD || MINIX || COHERENT # define ANY_UNIX 1 +#else +# define ANY_UNIX 0 +#endif + +#ifndef TINYSTACK +# define TINYSTACK 0 +#endif + +/*************************** compilers **************************************/ + +#ifndef AZTEC_C +# define AZTEC_C 0 +#endif + +#ifndef MICROSOFT +# define MICROSOFT 0 +#endif + +#ifndef TURBOC +# define TURBOC 0 +#endif + +/* Should we use "new style" ANSI C prototypes? */ +#ifdef __STDC__ +# define NEWSTYLE 1 +#endif +#ifdef __cplusplus +# define NEWSTYLE 1 +#endif +#ifndef NEWSTYLE +# define NEWSTYLE 0 +#endif + +#if NEWSTYLE +# define P_(s) s +#else +# define P_(s) () +#endif /******************************* Credit ************************************/ #if MSDOS # define CREDIT "Ported to MS-DOS by Guntram Blohm & Martin Patzel" +# if RAINBOW +# define CREDIT2 "Rainbow support added by Willett Kempton" +# endif +#endif + +#if AMIGA +# define CREDIT "Ported to AmigaDOS 2.04 by Mike Rieser & Dale Rahn" #endif #if TOS @@ -37,39 +234,130 @@ # define CREDIT "Ported to Coherent by Esa Ahola" #endif +#if VMS +# define CREDIT "Ported to VAX/VMS by John Campbell" +#endif /*************************** functions depending on OS *********************/ -extern char *strchr(); - -#define tread(fd,buf,n) read(fd,buf,(unsigned)(n)) -#define twrite(fd,buf,n) write(fd,buf,(unsigned)(n)) - -#define ttywrite(buf, len) write(1, buf, (unsigned)(len)) /* raw write */ - -extern void *malloc(); - -/* Most compilers could benefit from using the "register" storage class */ -#if 1 -# define REG register +/* There are two terminal-related functions that we need: ttyread() and + * ttywrite(). The ttyread() function implements read-with-timeout and is + * a true function on all systems. The ttywrite() function is almost always + * just a macro... + */ +#if !TOS && !AMIGA +# define ttywrite(buf, len) write(1, buf, (unsigned)(len)) /* raw write */ #endif -typedef unsigned char uchar; -#define UCHAR(s) ((unsigned char) (s)) +/* The strchr() function is an official standard now, so everybody has it + * except Unix version 7 (which is old) and BSD Unix (which is academic). + * Those guys use something called index() to do the same thing. + */ +#if BSD || UNIX7 || OSK +# define strchr index +# define strrchr rindex +#endif +#if !NEWSTYLE +extern char *strchr(); +#endif + +/* BSD uses bcopy() instead of memcpy() */ +#if BSD +# define memcpy(dest, src, siz) bcopy(src, dest, siz) +#endif + +/* BSD uses getwd() instead of getcwd(). The arguments are a little different, + * but we'll ignore that and hope for the best; adding arguments to the macro + * would mess up an "extern" declaration of the function. + * + * Also, the Coherent-286 uses getwd(), but Coherent-386 uses getcwd() + */ +#if BSD +#ifndef __386BSD__ +# define getcwd getwd +#endif +#endif +#if COH_286 +# define getcwd getwd +#endif +extern char *getcwd(); + +/* text versa binary mode for read/write */ +#if !TOS +#define tread(fd,buf,n) read(fd,buf,(unsigned)(n)) +#define twrite(fd,buf,n) write(fd,buf,(unsigned)(n)) +#endif + +/**************************** Compiler quirks *********************************/ + +/* the UNIX version 7 and (some) TOS compilers, don't allow "void" */ +#if UNIX7 || TOS +# define void int +#endif + +/* as far as I know, all compilers except version 7 support unsigned char */ +/* NEWFLASH: the Minix-ST compiler has subtle problems with unsigned char */ +#if UNIX7 || MINIX +# define UCHAR(c) ((c) & 0xff) +# define uchar char +#else +# define UCHAR(c) ((unsigned char)(c)) +# define uchar unsigned char +#endif + +/* Some compilers prefer to have malloc declared as returning a (void *) */ +/* ANSI, on the other hand, needs the arguments to free() to be cast */ +#ifndef __STDC__ +# if BSD || AMIGA || MINIX +extern void *malloc(); +# define _free_(ptr) free((void *)ptr) +# else +extern char *malloc(); +# define _free_(ptr) free((char *)ptr) +# endif +#else +# define _free_(ptr) free((void *)ptr) +#endif /* __STDC__ */ + +/* everybody but Amiga wants lseek declared here */ +#if !AMIGA +extern long lseek(); +#endif + +/* ANSI C has getenv() declared in stdlib.h, which we've already included. + * Other compilers will need it declared here, though. + */ +#ifndef __STDC__ +extern char *getenv(); +#endif + +/* Signal handler functions used to return an int value, which was ignored. + * On newer systems, signal handlers are void functions. Here, we try to + * guess the proper return type for this system. + */ +#ifdef __STDC__ +# define SIGTYPE void +#else +# if MSDOS +# define SIGTYPE void +# else +# if UNIXV +# define SIGTYPE void /* Note: This is wrong for SCO Xenix. */ +# endif +# endif +#endif +#ifndef SIGTYPE +# define SIGTYPE int +#endif /******************* Names of files and environment vars **********************/ -#define TMPDIR "/var/tmp" -#define TMPNAME "%s/elvis%04x%03x" /* temp file */ -#define CUTNAME "%s/elvis_%04x%03x" /* cut buffer's temp file */ -# ifndef EXRC -# define EXRC ".exrc" /* init file in current directory */ -# endif -# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */ -# ifndef EXINIT -# define EXINIT "EXINIT" -# endif -# ifndef SHELL -# define SHELL "/bin/sh" /* default shell */ +#if ANY_UNIX +# ifndef TMPDIR +# if MINIX +# define TMPDIR "/usr/tmp" /* Keep elvis' temp files off RAM disk! */ +# else +# define TMPDIR "/var/tmp" /* directory where temp files live */ +# endif # endif # ifndef PRSVDIR # define PRSVDIR "/var/preserve" /* directory where preserved file live */ @@ -77,9 +365,200 @@ typedef unsigned char uchar; # ifndef PRSVINDEX # define PRSVINDEX "/var/preserve/Index" /* index of files in PRSVDIR */ # endif +# ifndef EXRC +# define EXRC ".exrc" /* init file in current directory */ +# endif +# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */ +# ifndef SHELL +# define SHELL "/bin/sh" /* default shell */ +# endif +# if COHERENT +# ifndef REDIRECT +# define REDIRECT ">" /* Coherent CC writes errors to stdout */ +# endif +# endif +# define gethome(x) getenv("HOME") +#endif + +#if AMIGA /* Specify AMIGA environment */ +# ifndef CC_COMMAND +# define CC_COMMAND "cc" /* generic C compiler */ +# endif +# ifndef COLON +# define COLON ':' /* Amiga files can also end in `:' */ +# endif +# ifndef SYSEXRC +# define SYSEXRC "S:" EXRC /* name of ".exrc" file in system dir */ +# endif +# ifndef MAXRCLEN +# define MAXRCLEN 2048 /* max size of a .exrc file */ +# endif +# ifndef NBUFS +# define NBUFS 10 /* must be at least 3 -- more is better */ +# endif +# ifndef NEEDSYNC +# define NEEDSYNC TRUE /* assume ":se sync" by default */ +# endif +# ifndef PRSVDIR +# define PRSVDIR "Elvis:" /* directory where preserved file live */ +# endif +# ifndef PRSVINDEX +# define PRSVINDEX "Elvis:Index" /* index of files in PRSVDIR */ +# endif +# ifndef REDIRECT +# define REDIRECT ">" /* Amiga writes errors to stdout */ +# endif +# ifndef SCRATCHIN +# define SCRATCHIN "%sSIXXXXXX" +# endif +# ifndef SCRATCHOUT +# define SCRATCHOUT "%sSOXXXXXX" +# endif +# ifndef SHELL +# define SHELL "newshell" /* default shell */ +# endif +# ifndef TERMTYPE +# define TERMTYPE "amiga" /* default termtype */ +# endif +# ifndef TMPDIR /* for AMIGA should end in `:' or `/' */ +# define TMPDIR "T:" /* directory where temp files live */ +# endif +# ifndef TMPNAME +# define TMPNAME "%selv_%x.%x" /* format of names for temp files */ +# endif +# define gethome(x) getenv("HOME") +#endif + +#if MSDOS || TOS +/* do not change TMPNAME and SCRATCH*: they MUST begin with '%s\\'! */ +# ifndef TMPDIR +# define TMPDIR "C:\\tmp" /* directory where temp files live */ +# endif +# ifndef PRSVDIR +# define PRSVDIR "C:\\preserve" /* directory where preserved file live */ +# endif +# ifndef PRSVINDEX +# define PRSVINDEX "C:\\preserve\\Index" /* index of files in PRSVDIR */ +# endif +# define TMPNAME "%s\\elv_%x.%x" /* temp file */ +# if MSDOS +# if MICROSOFT +# define CC_COMMAND "cl -c" /* C compiler */ +# else +# if __BORLANDC__ /* Borland C */ +# define CC_COMMAND "bcc" /* C compiler */ +# else +# if TURBOC /* Turbo C */ +# define CC_COMMAND "tcc" /* C compiler */ +# endif /* TURBOC */ +# endif /* BORLANDC */ +# endif /* MICROSOFT */ +# endif /* MSDOS */ +# define SCRATCHIN "%s\\siXXXXXX" /* DOS ONLY - output of filter program */ +# define SCRATCHOUT "%s\\soXXXXXX" /* temp file used as input to filter */ +# define SLASH '\\' +# ifndef SHELL +# if TOS +# define SHELL "shell.ttp" /* default shell */ +# else +# define SHELL "command.com" /* default shell */ +# endif +# endif +# define NEEDSYNC TRUE /* assume ":se sync" by default */ +# if TOS && __GNUC__ /* probably on other systems, too */ +# define REDIRECT "2>" /* GNUC reports on 2, others on 1 */ +# define CC_COMMAND "gcc -c" +# else +# define REDIRECT ">" /* shell's redirection of stderr */ +# endif +#endif + +#if VMS +/* do not change TMPNAME, and SCRATCH*: they MUST begin with '%s\\'! */ +# ifndef TMPDIR +# define TMPDIR "sys$scratch:" /* directory where temp files live */ +# endif +# define TMPNAME "%selv_%x.%x;1" /* temp file */ +# define SCRATCHIN "%ssiXXXXXX" /* DOS ONLY - output of filter program */ +# define SCRATCHOUT "%ssoXXXXXX" /* temp file used as input to filter */ +# define SLASH '\:' /* Worry point... jdc */ +# ifndef SHELL +# define SHELL "" /* default shell */ +# endif +# define REDIRECT ">" /* shell's redirection of stderr */ +# define tread(fd,buf,n) vms_read(fd,buf,(unsigned)(n)) +# define close vms_close +# define lseek vms_lseek +# define unlink vms_delete +# define delete __delete /* local routine conflicts w/VMS rtl routine. */ +# define rpipe vms_rpipe +# define rpclose vms_rpclose +# define ttyread vms_ttyread +# define gethome(x) getenv("HOME") +/* There is no sync() on vms */ +# define sync() +/* jdc -- seems VMS external symbols are case insensitive */ +# define m_fWord m_fw_ord +# define m_bWord m_bw_ord +# define m_eWord m_ew_ord +# define m_Nsrch m_n_srch +# define m_Fch m_f_ch +# define m_Tch m_t_ch +# define v_Xchar v_x_char +/* jdc -- also, braindead vms curses always found by linker. */ +# define LINES elvis_LINES +# define COLS elvis_COLS +# define curscr elvis_curscr +# define stdscr elvis_stdscr +# define initscr elvis_initscr +# define endwin elvis_endwin +# define wrefresh elvis_wrefresh +#endif + +#if OSK +# ifndef TMPDIR +# define TMPDIR "/dd/tmp" /* directory where temp files live */ +# endif +# ifndef PRSVDIR +# define PRSVDIR "/dd/usr/preserve" /* directory where preserved file live */ +# endif +# ifndef PRSVINDEX +# define PRSVINDEX "/dd/usr/preserve/Index" /* index of files in PRSVDIR */ +# endif +# ifndef CC_COMMAND +# define CC_COMMAND "cc -r" /* name of the compiler */ +# endif +# ifndef EXRC +# define EXRC ".exrc" /* init file in current directory */ +# endif +# define SCRATCHOUT "%s/soXXXXXX" /* temp file used as input to filter */ +# ifndef SHELL +# define SHELL "shell" /* default shell */ +# endif +# define FILEPERMS (S_IREAD|S_IWRITE) /* file permissions used for creat() */ +# define REDIRECT ">>-" /* shell's redirection of stderr */ +# define sync() /* OS9 doesn't need a sync() */ +# define gethome(x) getenv("HOME") +#endif #ifndef TAGS -# define TAGS "tags" /* tags file */ +# define TAGS "tags" /* name of the tags file */ +#endif + +#ifndef TMPNAME +# define TMPNAME "%s/elv_%x.%x" /* format of names for temp files */ +#endif + +#ifndef EXINIT +# define EXINIT "EXINIT" /* name of EXINIT environment variable */ +#endif + +#ifndef EXRC +# define EXRC "elvis.rc" /* name of ".exrc" file in current dir */ +#endif + +#ifndef HMEXRC +# define HMEXRC EXRC /* name of ".exrc" file in home dir */ #endif #ifndef KEYWORDPRG @@ -92,7 +571,7 @@ typedef unsigned char uchar; #endif #ifndef ERRLIST -# define ERRLIST "errlist" +# define ERRLIST "errs" #endif #ifndef SLASH @@ -104,7 +583,7 @@ typedef unsigned char uchar; #endif #ifndef REG -# define REG +# define REG register #endif #ifndef NEEDSYNC @@ -115,6 +594,10 @@ typedef unsigned char uchar; # define FILEPERMS 0666 #endif +#ifndef PRESERVE +# define PRESERVE "/usr/libexec/elvispreserve" /* name of the "preserve" program */ +#endif + #ifndef CC_COMMAND # define CC_COMMAND "cc -c" #endif @@ -127,18 +610,6 @@ typedef unsigned char uchar; # define REDIRECT "2>" #endif -#ifndef PRESERVE -# define PRESERVE "/usr/libexec/elvispreserve" /* name of the "preserve" program */ -#endif - -#if !defined(CRUNCH) && defined(LETS_GET_SMALL) -#define CRUNCH -#endif - -#if defined(CRUNCH) && !defined(LETS_GET_SMALL) -#define LETS_GET_SMALL -#endif - #ifndef BLKSIZE # ifdef CRUNCH # define BLKSIZE 1024 @@ -151,16 +622,12 @@ typedef unsigned char uchar; # define KEYBUFSIZE 1000 #endif -#ifdef LETS_GET_SMALL -#define NO_CHARATTR -#define NO_DIGRAPH -#define NO_SENTENCE -#define NO_EXTENSIONS -#define NO_MAGIC -#define NO_ERRLIST -#define NO_MODELINE -#define NO_SHOWMATCH -#define NO_SHOWMODE -#define NO_OPTCOLS -#define NO_MKEXRC +#ifndef MAILER +# define MAILER "mail" #endif + +#ifndef gethome +extern char *gethome(); +#endif + +#endif /* ndef _CONFIG_H */ diff --git a/usr.bin/elvis/ctype.c b/usr.bin/elvis/ctype.c index ac6118307f3e..fa0a7ba23ad3 100644 --- a/usr.bin/elvis/ctype.c +++ b/usr.bin/elvis/ctype.c @@ -7,6 +7,8 @@ #include "config.h" #include "ctype.h" +void _ct_init P_((uchar *)); + uchar _ct_toupper[256]; uchar _ct_tolower[256]; uchar _ct_ctypes[256]; diff --git a/usr.bin/elvis/curses.c b/usr.bin/elvis/curses.c index 58ebaed335fd..063b0914b3dc 100644 --- a/usr.bin/elvis/curses.c +++ b/usr.bin/elvis/curses.c @@ -18,15 +18,17 @@ #include "vi.h" #if ANY_UNIX -# if UNIXV +# if UNIXV || COH_386 # ifdef TERMIOS # include # else # include # endif -# ifdef S5WINSIZE -# include /* winsize struct defined in one of these? */ -# include +# ifndef NO_S5WINSIZE +# ifndef _SEQUENT_ +# include /* winsize struct defined in one of these? */ +# include +# endif # else # undef TIOCGWINSZ /* we can't handle it correctly yet */ # endif @@ -48,7 +50,6 @@ extern int VMS_read_raw; /* Set in initscr() */ #endif -extern char *getenv(); static void starttcap(); /* variables, publicly available & used in the macros */ @@ -89,8 +90,8 @@ char *SR_; /* :sr=: scroll reverse */ #else char *SR; /* :sr=: scroll reverse */ #endif -char *KS = ""; /* :ks=: init string for cursor */ -char *KE = ""; /* :ke=: restore string for cursor */ +char *KS = ""; /* :ks=: switch keypad to application mode */ +char *KE = ""; /* :ke=: switch keypad to system mode */ char *KU; /* :ku=: key sequence sent by up arrow */ char *KD; /* :kd=: key sequence sent by down arrow */ char *KL; /* :kl=: key sequence sent by left arrow */ @@ -127,25 +128,25 @@ char *CR = ""; /* :cR=: cursor used for VI replace mode */ char *aend = ""; /* end an attribute -- either UE or ME */ char ERASEKEY; /* backspace key taken from ioctl structure */ #ifndef NO_COLOR -char normalcolor[16]; -char SOcolor[16]; -char SEcolor[16]; -char UScolor[16]; -char UEcolor[16]; -char MDcolor[16]; -char MEcolor[16]; -char AScolor[16]; -char AEcolor[16]; +char normalcolor[24]; +char SOcolor[24]; +char SEcolor[24]; +char UScolor[24]; +char UEcolor[24]; +char MDcolor[24]; +char MEcolor[24]; +char AScolor[24]; +char AEcolor[24]; # ifndef NO_POPUP -char POPUPcolor[16]; +char POPUPcolor[24]; # endif # ifndef NO_VISIBLE -char VISIBLEcolor[16]; +char VISIBLEcolor[24]; # endif #endif #if ANY_UNIX -# if UNIXV +# if UNIXV || COH_386 # ifdef TERMIOS static struct termios oldtermio; /* original tty mode */ static struct termios newtermio; /* cbreak/noecho tty mode */ @@ -210,11 +211,11 @@ void initscr() { #if ANY_UNIX write(2, "Environment variable TERM must be set\n", (unsigned)38); - exit(1); + exit(2); #endif #if OSK writeln(2, "Environment variable TERM must be set\n", (unsigned)38); - exit(1); + exit(2); #endif #if AMIGA termtype = TERMTYPE; @@ -229,7 +230,7 @@ void initscr() #endif #if VMS write(2, "UNKNOWN terminal: define ELVIS_TERM\n", (unsigned)36); - exit(1); + exit(2); #endif } else @@ -246,7 +247,7 @@ void initscr() /* change the terminal mode to cbreak/noecho */ #if ANY_UNIX -# if UNIXV +# if UNIXV || COH_386 # ifdef TERMIOS tcgetattr(2, &oldtermio); # else @@ -281,10 +282,12 @@ void endwin() static int curses_active = FALSE; +extern int oldcurs; + /* Send any required termination strings. Turn off "raw" mode. */ void suspend_curses() { -#if ANY_UNIX && !UNIXV +#if ANY_UNIX && !(UNIXV || COH_386) struct tchars tbuf; # ifdef TIOCSLTC struct ltchars ltbuf; @@ -294,6 +297,7 @@ void suspend_curses() if (has_CQ) { do_CQ(); + oldcurs = 0; } #endif if (has_TE) /* GB */ @@ -311,8 +315,8 @@ void suspend_curses() /* change the terminal mode back the way it was */ #if ANY_UNIX -# if UNIXV -# if TERMIOS +# if (UNIXV || COH_386) +# ifdef TERMIOS tcsetattr(2, TCSADRAIN, &oldtermio); # else ioctl(2, TCSETAW, &oldtermio); @@ -360,7 +364,7 @@ void resume_curses(quietly) { /* change the terminal mode to cbreak/noecho */ #if ANY_UNIX -# if UNIXV +# if UNIXV || COH_386 ospeed = (oldtermio.c_cflag & CBAUD); ERASEKEY = oldtermio.c_cc[VERASE]; newtermio = oldtermio; @@ -381,7 +385,7 @@ void resume_curses(quietly) # else ioctl(2, TCSETAW, &newtermio); # endif -# else /* BSD or V7 or Coherent or Minix */ +# else /* BSD, V7, Coherent-286, or Minix */ struct tchars tbuf; # ifdef TIOCSLTC struct ltchars ltbuf; @@ -438,6 +442,12 @@ void resume_curses(quietly) ERASEKEY = '\177'; /* Accept as <^H> for VMS */ #endif + curses_active = TRUE; + } + + /* If we're supposed to quit quietly, then we're done */ + if (quietly) + { if (has_TI) /* GB */ { do_TI(); @@ -447,12 +457,6 @@ void resume_curses(quietly) do_KS(); } - curses_active = TRUE; - } - - /* If we're supposed to quit quietly, then we're done */ - if (quietly) - { return; } @@ -468,6 +472,10 @@ void resume_curses(quietly) do_SE(); refresh(); ttyread(kbuf, 20, 0); /* in RAW mode, so <20 is very likely */ + if (has_TI) + { + do_TI(); + } if (kbuf[0] == ':') { mode = MODE_COLON; @@ -481,11 +489,7 @@ void resume_curses(quietly) } exwrote = FALSE; -#if TURBOC || __GNUC__ - signal(SIGINT, (void(*)()) trapint); -#else signal(SIGINT, trapint); -#endif } /* This function fetches an optional string from termcap */ @@ -517,7 +521,7 @@ static void musthave(T, s) #if OSK write(2, "\l", 1); #endif - exit(1); + exit(2); } } @@ -615,11 +619,16 @@ static void starttcap(term) getsize(0); /* Key sequences */ - pair(&KS, &KE, "ks", "ke"); + pair(&KS, &KE, "ks", "ke"); /* keypad enable/disable */ mayhave(&KU, "ku"); /* up */ mayhave(&KD, "kd"); /* down */ - mayhave(&KL, "kl"); /* left */ mayhave(&KR, "kr"); /* right */ + mayhave(&KL, "kl"); /* left */ + if (KL && KL[0]=='\b' && !KL[1]) + { + /* never use '\b' as a left arrow! */ + KL = (char *)0; + } mayhave(&PU, "kP"); /* PgUp */ mayhave(&PD, "kN"); /* PgDn */ mayhave(&HM, "kh"); /* Home */ @@ -913,8 +922,8 @@ void wqrefresh() /* This function is called during termination. It resets color modes */ int ansiquit() { - /* if ANSI color terminal, then reset the colors */ - if (!strcmp(UP, "\033[A")) + /* if ANSI terminal & colors were set, then reset the colors */ + if (!strcmp(UP, "\033[A") && strcmp(SOcolor, SO)) { tputs("\033[37;40m\033[m", 1, faddch); clrtoeol(); @@ -931,21 +940,33 @@ int ansicolor(cmode, attrbyte) int cmode; /* mode to set, e.g. A_NORMAL */ int attrbyte; /* IBM PC attribute byte */ { - char temp[16]; /* hold the new mode string */ + char temp[24]; /* hold the new mode string */ /* if not ANSI-ish, then fail */ if (strcmp(UP, "\033[A") && strcmp(UP, "\033OA")) { - msg("Don't know how to set colors for this terminal"); - return 0; + /* Only give an error message if we're editing a file. + * (I.e., if we're *NOT* currently doing a ".exrc") + */ + if (tmpfd >= 0) + msg("Don't know how to set colors for this terminal"); + return FALSE; } /* construct the color string */ +#ifdef MWC /* either Coherent-286 ("COHERENT"), or Coherent-386 ("M_SYSV") */ + sprintf(temp, "\033[m\033[3%cm\033[4%cm%s%s", + "04261537"[attrbyte & 0x07], + "04261537"[(attrbyte >> 4) & 0x07], + (attrbyte & 0x08) ? "\033[1m" : "", + (attrbyte & 0x80) ? "\033[5m" : ""); +#else sprintf(temp, "\033[m\033[3%c;4%c%s%sm", "04261537"[attrbyte & 0x07], "04261537"[(attrbyte >> 4) & 0x07], (attrbyte & 0x08) ? ";1" : "", (attrbyte & 0x80) ? ";5" : ""); +#endif /* stick it in the right place */ switch (cmode) @@ -997,7 +1018,7 @@ int ansicolor(cmode, attrbyte) #endif } - return 1; + return TRUE; } @@ -1006,6 +1027,7 @@ int ansicolor(cmode, attrbyte) * yet, this is one of the termcap strings; for color terminals that really * have had colors defined, we just the "normal color" escape sequence. */ +int endcolor() { if (aend == ME) diff --git a/usr.bin/elvis/cut.c b/usr.bin/elvis/cut.c index 0e0bb393f593..cfa032160c33 100644 --- a/usr.bin/elvis/cut.c +++ b/usr.bin/elvis/cut.c @@ -150,7 +150,7 @@ static void cutfree(buf) msg("cutfree() tried to free a NULL buf->phys pointer."); else #endif - free((char *)buf->phys); + _free_((char *)buf->phys); /* maybe delete the temp file */ maybezap(num); @@ -666,7 +666,7 @@ int cb2str(name, buf, size) } /* if too big, return the size now, without doing anything */ - if (cb->end - cb->start >= size) + if ((unsigned)(cb->end - cb->start) >= size) { return cb->end - cb->start; } diff --git a/usr.bin/elvis/elvis.1 b/usr.bin/elvis/elvis.1 index 495bcea2cb4a..8d10b78a44db 100644 --- a/usr.bin/elvis/elvis.1 +++ b/usr.bin/elvis/elvis.1 @@ -72,6 +72,58 @@ is executed as a series of \fIex\fR commands. A file by the same name may be executed in the current directory, too. On non-UNIX systems, ".exrc" is usually an invalid file name; there, the initialization file is called "elvis.rc" instead. +.SH ENVIRONMENT +.IP TERM +This is the name of your terminal's entry in the termcap or terminfo +database. +The list of legal values varies from one system to another. +.IP TERMCAP +Optional. +If your system uses termcap, and the TERMCAP variable is unset, then +\*E will read your terminal's definition from \fB/etc/termcap\fR. +If TERMCAP is set to the full pathname of a file (starting with a '/') +then \*E will look in the named file instead of \fB/etc/termcap\fR. +If TERMCAP is set to a value which doesn't start with a '/', +then its value is assumed to be the full termcap entry for your terminal. +.IP TERMINFO +Optional. +If your system uses terminfo, and the TERMINFO variable is unset, then +\*E will read your terminal's definition from the database in the +\fB/usr/lib/terminfo\fR database. +If TERMINFO is set, then its value is used as the database name to use +instead of \fB/usr/lib/terminfo\fR. +.IP "LINES, COLUMNS" +Optional. +These variables, if set, will override the screen size values given in +the termcap/terminfo for your terminal. +On windowing systems such as X, \*E has other ways of determining the +screen size, so you should probably leave these variables unset. +.IP EXINIT +Optional. +This variable can hold EX commands which will be executed before any .exrc +files. +.IP SHELL +Optional. +The SHELL variable sets the default value for the "shell" option, +which determines which shell program is used to perform wildcard +expansion in file names, and also which is used to execute filters +or external programs. +The default value on UNIX systems is "/bin/sh". +.IP +Note: Under MS-DOS, this variable is called COMSPEC instead of SHELL. +.IP HOME +This variable should be set to the name of your home directory. +\*E looks for its initialization file there; +if HOME is unset then the initialization file will not be executed. +.IP TAGPATH +Optional. +This variable is used by the "ref" program, which is invoked by the shift-K, +control-], and :tag commands. +See "ref" for more information. +.IP "TMP, TEMP" +These optional environment variables are only used in non-UNIX versions +of \*E. +They allow you to supply a directory name to be used for storing temporary files. .SH "SEE ALSO" ctags(1), ref(1), virec(1) .PP diff --git a/usr.bin/elvis/ex.c b/usr.bin/elvis/ex.c index a0e6d34e2e51..eda5f1139f20 100644 --- a/usr.bin/elvis/ex.c +++ b/usr.bin/elvis/ex.c @@ -5,14 +5,6 @@ * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00043 - * -------------------- ----- ---------------------- - * - * 27 Nov 1992 Felix Gaehtgens Fixed :wq! - * */ @@ -60,6 +52,8 @@ static struct } cmdnames[] = { /* cmd name cmd code function arguments */ + {"print", CMD_PRINT, cmd_print, RANGE+NL }, + {"append", CMD_APPEND, cmd_append, FROM+ZERO+BANG }, #ifdef DEBUG {"bug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL}, @@ -76,7 +70,6 @@ static struct {"move", CMD_MOVE, cmd_move, RANGE+EXTRA }, {"next", CMD_NEXT, cmd_next, BANG+NAMEDFS }, {"Next", CMD_PREVIOUS, cmd_next, BANG }, - {"print", CMD_PRINT, cmd_print, RANGE+NL }, {"quit", CMD_QUIT, cmd_xit, BANG }, {"read", CMD_READ, cmd_read, FROM+ZERO+NAMEDF}, {"substitute", CMD_SUBSTITUTE, cmd_substitute, RANGE+EXTRA }, @@ -118,6 +111,9 @@ static struct {"mkexrc", CMD_MKEXRC, cmd_mkexrc, NAMEDF }, #endif {"number", CMD_NUMBER, cmd_print, RANGE+NL }, +#ifndef NO_TAGSTACK + {"pop", CMD_POP, cmd_pop, BANG+WORD1 }, +#endif {"put", CMD_PUT, cmd_put, FROM+ZERO+WORD1 }, {"set", CMD_SET, cmd_set, EXRCOK+EXTRA }, {"shell", CMD_SHELL, cmd_shell, NL }, @@ -128,7 +124,7 @@ static struct {"tag", CMD_TAG, cmd_tag, BANG+WORD1 }, {"version", CMD_VERSION, cmd_version, EXRCOK+NONE }, {"visual", CMD_VISUAL, cmd_edit, BANG+NAMEDF }, - {"wq", CMD_WQUIT, cmd_xit, BANG+NL }, + {"wq", CMD_WQUIT, cmd_xit, NL }, #ifdef DEBUG {"debug", CMD_DEBUG, cmd_debug, RANGE+BANG+EXTRA+NL}, @@ -392,8 +388,8 @@ void doexcmd(cmdbuf) } else if (*scan == '0') { - frommark = tomark = MARK_UNSET; scan++; + frommark = tomark = (*scan ? MARK_UNSET : MARK_FIRST); } else { @@ -424,16 +420,23 @@ void doexcmd(cmdbuf) scan++; } - /* if no command, then just move the cursor to the mark */ + /* Figure out how long the command name is. If no command, then the + * length is 0, which will match the "print" command. + */ if (!*scan) { - if (tomark != MARK_UNSET) - cursor = tomark; - return; + /* if not in ex mode, and both endpoints are at the line, + * then just move to the start of that line without printing + */ + if (mode != MODE_EX && frommark == tomark) + { + if (tomark != MARK_UNSET) + cursor = tomark; + return; + } + cmdlen = 0; } - - /* figure out how long the command name is */ - if (!isalpha(*scan)) + else if (!isalpha(*scan)) { cmdlen = 1; } @@ -672,23 +675,60 @@ int doexrc(filename) int fd; /* file descriptor */ int len; /* length of the ".exrc" file */ +#ifdef CRUNCH + /* small address space - we need to conserve space */ + /* !!! kludge: we use U_text as the buffer. This has the side-effect * of interfering with the shift-U visual command. Disable shift-U. */ U_line = 0L; +#else +# if TINYSTACK +# if TOS || MINT + /* small stack, but big heap. Allocate buffer from heap */ + char *U_text = (char *)malloc(4096); + if (!U_text) + { + return 0; + } +# else + /* small stack - we need to conserve space */ + + /* !!! kludge: we use U_text as the buffer. This has the side-effect + * of interfering with the shift-U visual command. Disable shift-U. + */ + U_line = 0L; +# endif +# else + /* This is how we would *like* to do it -- with a large buffer on the + * stack, so we can handle large .exrc files and also recursion. + */ + char U_text[4096]; +# endif +#endif /* open the file, read it, and close */ fd = open(filename, O_RDONLY); if (fd < 0) { +#if TINYSTACK && (TOS || MINT) + free(U_text); +#endif return 0; } - len = tread(fd, U_text, BLKSIZE); +#if TINYSTACK && (TOS || MINT) + len = tread(fd, U_text, 4096); +#else + len = tread(fd, U_text, sizeof U_text); +#endif close(fd); /* execute the string */ exstring(U_text, len, ctrl('V')); +#if TINYSTACK && (TOS || MINT) + free(U_text); +#endif return 1; } diff --git a/usr.bin/elvis/input.c b/usr.bin/elvis/input.c index 563f64351aba..ca5b11581b91 100644 --- a/usr.bin/elvis/input.c +++ b/usr.bin/elvis/input.c @@ -28,8 +28,8 @@ static struct _DIG } *digs; char digraph(key1, key2) - char key1; /* the underlying character */ - char key2; /* the second character */ + int key1; /* the underlying character */ + int key2; /* the second character */ { int newkey; REG struct _DIG *dp; @@ -158,7 +158,7 @@ void do_digraph(bang, extra) prev->next = dp->next; else digs = dp->next; - free(dp); + _free_(dp); return; } @@ -211,11 +211,11 @@ void savedigs(fd) * chunk of text with typed-in text. It returns the MARK of the last character * that the user typed in. */ -MARK input(from, to, when, above) +MARK input(from, to, when, delta) MARK from; /* where to start inserting text */ MARK to; /* extent of text to delete */ int when; /* either WHEN_VIINP or WHEN_VIREP */ - int above; /* boolean: take indentation from lower line? */ + int delta; /* 1 to take indent from lower line, -1 for upper, 0 for none */ { char key[2]; /* key char followed by '\0' char */ char *build; /* used in building a newline+indent string */ @@ -287,8 +287,8 @@ MARK input(from, to, when, above) /* handle autoindent of the first line, maybe */ cursor = from; - m = (above ? (cursor + BLKSIZE) : (cursor - BLKSIZE)); - if (*o_autoindent && markidx(m) == 0 + m = cursor + MARK_AT_LINE(delta); + if (delta != 0 && *o_autoindent && markidx(m) == 0 && markline(m) >= 1L && markline(m) <= nlines) { /* Only autoindent blank lines. */ @@ -307,7 +307,7 @@ MARK input(from, to, when, above) { *build = '\0'; add(cursor, tmpblk.c); - cursor += (build - tmpblk.c); + cursor += (int)(build - tmpblk.c); if (cursor > to) to = cursor; } @@ -329,7 +329,7 @@ MARK input(from, to, when, above) build = ptext; if (pline == markline(from)) build += markidx(from); - for (scan = ptext + markidx(cursor); --scan >= build && isalnum(*scan); ) + for (scan = ptext + markidx(cursor); --scan >= build && !isspace(*scan); ) { } scan++; @@ -338,7 +338,7 @@ MARK input(from, to, when, above) key[0] = getkey(when); #endif #ifndef NO_VISIBLE - if (key[0] != '\0' && V_from != MARK_UNSET) + if (key[0] != ctrl('O') && V_from != MARK_UNSET) { msg("Can't modify text during a selection"); beep(); @@ -375,10 +375,11 @@ MARK input(from, to, when, above) * warpmargin, then change the last whitespace * characters on line into a newline */ - if (*o_wrapmargin != 0) + if (*o_wrapmargin) { pfetch(markline(cursor)); - if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff)) + if (plen == idx2col(cursor, ptext, TRUE) + && plen > COLS - (*o_wrapmargin & 0xff)) { build = tmpblk.c; *build++ = '\n'; @@ -401,11 +402,15 @@ MARK input(from, to, when, above) continue; /*break up line, and we do autoindent if needed*/ - change(m + (scan - ptext), m + (scan - ptext) + 1, tmpblk.c); - cursor = (cursor & ~(BLKSIZE - 1)) - + BLKSIZE - + strlen(tmpblk.c) - 1 - + plen - (scan - ptext) - 1; + change(m + (int)(scan - ptext), m + (int)(scan - ptext) + 1, tmpblk.c); + + /* NOTE: for some reason, MSC 5.10 doesn't + * like for these lines to be combined!!! + */ + cursor = (cursor & ~(BLKSIZE - 1)); + cursor += BLKSIZE; + cursor += strlen(tmpblk.c) - 1; + cursor += plen - (int)(scan - ptext) - 1; /*remove trailing spaces on previous line*/ pfetch(markline(m)); @@ -416,7 +421,7 @@ MARK input(from, to, when, above) if (*scan != ' ' && *scan != '\t') break; } - delete(m + (scan-ptext) + 1, m + plen); + delete(m + (int)(scan - ptext) + 1, m + plen); break; } @@ -559,7 +564,7 @@ MARK input(from, to, when, above) V_from = MARK_UNSET; ChangeText { - m = from = to = cursor = paste(cursor, (*key == 'p'), FALSE); + m = paste(cursor, (*key == 'p'), FALSE); } break; # endif /* !NO_VISIBLE */ @@ -569,8 +574,8 @@ MARK input(from, to, when, above) /* adjust the moved cursor */ if (m != cursor) { - m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0)); - if (*key == '$' || (*key == 'l' && m <= cursor)) + m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? NCOL|FINL : FINL)); + if (plen && (*key == '$' || (*key == 'l' && m <= cursor))) { m++; } @@ -696,11 +701,21 @@ MARK input(from, to, when, above) } /* remove indent from this line, if blank */ - if ((scan - ptext) >= markidx(cursor) && plen > 0) + if ((int)(scan - ptext) >= markidx(cursor) && plen > 0) { to = cursor &= ~(BLKSIZE - 1); - delete(cursor, cursor + plen); + delete(cursor, cursor + (int)(scan - ptext)); } + +#if 0 + /* advance "to" past whitespace at the cursor */ + if (to >= cursor) + { + for (scan = ptext + markidx(cursor), to = cursor; *scan == ' ' || *scan == '\t'; scan++, to++) + { + } + } +#endif } *build = 0; if (cursor >= to && when != WHEN_VIREP) @@ -727,7 +742,11 @@ MARK input(from, to, when, above) { cutname('.'); } - to = cursor = paste(cursor, FALSE, TRUE) + 1L; + m = paste(cursor, FALSE, TRUE); + if (m != MARK_UNSET) + { + to = cursor = m + 1L; + } break; case ctrl('V'): diff --git a/usr.bin/elvis/main.c b/usr.bin/elvis/main.c index 2192a2efec33..f93f780225c4 100644 --- a/usr.bin/elvis/main.c +++ b/usr.bin/elvis/main.c @@ -20,8 +20,7 @@ #include #include "vi.h" -extern trapint(); /* defined below */ -extern char *getenv(); +extern SIGTYPE trapint(); /* defined below */ jmp_buf jmpenv; #ifndef NO_DIGRAPH @@ -89,33 +88,33 @@ void main(argc, argv) /* arrange for deadly signals to be caught */ # ifdef SIGHUP - signal(SIGHUP, (void(*)()) deathtrap); + signal(SIGHUP, deathtrap); # endif # ifndef DEBUG # ifdef SIGILL - signal(SIGILL, (void(*)()) deathtrap); + signal(SIGILL, deathtrap); # endif # ifdef SIGBUS - signal(SIGBUS, (void(*)()) deathtrap); + signal(SIGBUS, deathtrap); # endif # ifdef SIGSEGV - signal(SIGSEGV, (void(*)()) deathtrap); + signal(SIGSEGV, deathtrap); # endif # ifdef SIGSYS - signal(SIGSYS, (void(*)()) deathtrap); + signal(SIGSYS, deathtrap); # endif # endif /* !DEBUG */ # ifdef SIGPIPE - signal(SIGPIPE, (void(*)()) deathtrap); + signal(SIGPIPE, deathtrap); # endif # ifdef SIGTERM - signal(SIGTERM, (void(*)()) deathtrap); + signal(SIGTERM, deathtrap); # endif # ifdef SIGUSR1 - signal(SIGUSR1, (void(*)()) deathtrap); + signal(SIGUSR1, deathtrap); # endif # ifdef SIGUSR2 - signal(SIGUSR2, (void(*)()) deathtrap); + signal(SIGUSR2, deathtrap); # endif /* initialize the options - must be done after initscr(), so that @@ -187,11 +186,11 @@ void main(argc, argv) case 'L': case 'r': /* recover */ - msg("Use the `elvisrecover` program to recover lost files"); + msg("Use the `elvrec` program to recover lost files"); endmsgs(); refresh(); endwin(); - exit(0); + exit(1); break; case 't': /* tag */ @@ -309,7 +308,7 @@ void main(argc, argv) doexrc(SYSEXRC); #endif #ifdef HMEXRC - str = getenv("HOME"); + str = gethome(argv[0]); if (str && *str) { strcpy(tmpblk.c, str); @@ -346,7 +345,7 @@ void main(argc, argv) blkinit(); if (tag) { - cmd_tag(MARK_FIRST, MARK_FIRST, CMD_TAG, 0, tag); + cmd_tag(MARK_UNSET, MARK_FIRST, CMD_TAG, 0, tag); } #ifndef NO_ERRLIST else if (err) @@ -386,7 +385,7 @@ void main(argc, argv) /* Maybe we just aborted a change? */ abortdo(); } - signal(SIGINT, (void(*)()) trapint); + signal(SIGINT, trapint); switch (mode) { @@ -419,13 +418,13 @@ void main(argc, argv) refresh(); endwin(); - exit(0); + exit(exitcode); /*NOTREACHED*/ } /*ARGSUSED*/ -int trapint(signo) +SIGTYPE trapint(signo) int signo; { beep(); @@ -434,16 +433,11 @@ int trapint(signo) #if OSK sigmask(-1); #endif -#if TURBOC || __GNUC__ - signal(signo, (void (*)())trapint); -#else signal(signo, trapint); -#endif doingglobal = FALSE; longjmp(jmpenv, 1); - - return 0; + /*NOTREACHED*/ } @@ -502,7 +496,7 @@ static char digtable[][4] = "" }; -static init_digraphs() +static int init_digraphs() { int i; diff --git a/usr.bin/elvis/modify.c b/usr.bin/elvis/modify.c index af7914601018..79b910366e93 100644 --- a/usr.bin/elvis/modify.c +++ b/usr.bin/elvis/modify.c @@ -378,7 +378,7 @@ void add(atmark, newtext) { /* hey, we probably can! Get the following block & see... */ following = blkget(blkno + 1); - if (strlen(following->c) + (build - blk->c) < BLKSIZE - 1) + if (strlen(following->c) + (build - blk->c) < (unsigned)(BLKSIZE - 1)) { /* we can! Copy text from following to blk */ for (scan = following->c; *scan; ) diff --git a/usr.bin/elvis/move1.c b/usr.bin/elvis/move1.c index f57ab9a0a7ce..604b83d963d4 100644 --- a/usr.bin/elvis/move1.c +++ b/usr.bin/elvis/move1.c @@ -17,7 +17,7 @@ MARK m_updnto(m, cnt, cmd) MARK m; /* movement is relative to this mark */ long cnt; /* a numeric argument */ - char cmd; /* the command character */ + int cmd; /* the command character */ { DEFAULT(cmd == 'G' ? nlines : 1L); @@ -245,6 +245,10 @@ MARK m_sentence(m, cnt, cmd) { REG char *text; REG long l; +#ifndef CRUNCH + /* figure out where the paragraph boundary is */ + MARK pp = m_paragraph(m, 1L, cmd=='(' ? '{' : '}'); +#endif DEFAULT(1); @@ -277,9 +281,9 @@ MARK m_sentence(m, cnt, cmd) /* move forward, wrap at end of line */ if (!text[0]) { - if (l >= nlines) + if (l == nlines) { - return MARK_UNSET; + goto BreakBreak; } l++; pfetch(l); @@ -297,9 +301,9 @@ MARK m_sentence(m, cnt, cmd) { do { - if (l <= 1) + if (l == 1L) { - return MARK_FIRST; + goto BreakBreak; } l--; pfetch(l); @@ -313,12 +317,25 @@ MARK m_sentence(m, cnt, cmd) } } while (!isperiod(text)); } +BreakBreak: /* construct a mark for this location */ m = buildmark(text); /* move forward to the first word of the next sentence */ m = m_fword(m, 1L, 'w', '\0'); + if (m == MARK_UNSET) + { + m = MARK_EOF; + } + +#ifndef CRUNCH + /* don't cross the paragraph boundary */ + if (pp && ((cmd=='(') ? (mpp))) + { + m = pp; + } +#endif return m; } @@ -334,11 +351,15 @@ MARK m_paragraph(m, cnt, cmd) long l, ol; /* current line number, original line number */ int dir; /* -1 if we're moving up, or 1 if down */ char col0; /* character to expect in column 0 */ + long limit; /* line where searching must stop */ #ifndef NO_SENTENCE # define SENTENCE(x) (x) char *list; /* either o_sections or o_paragraph */ #else # define SENTENCE(x) +#endif +#ifndef CRUNCH + MARK ss; #endif DEFAULT(1); @@ -350,12 +371,26 @@ MARK m_paragraph(m, cnt, cmd) dir = -1; col0 = '\0'; SENTENCE(list = o_paragraphs); +#ifndef CRUNCH + ss = m_paragraph(m, 1L, '<'); + if (ss) + limit = markline(ss); + else +#endif + limit = 1L; break; case '}': dir = 1; col0 = '\0'; SENTENCE(list = o_paragraphs); +#ifndef CRUNCH + ss = m_paragraph(m, 1L, '>'); + if (ss) + limit = markline(ss); + else +#endif + limit = nlines; break; case '[': @@ -363,9 +398,12 @@ MARK m_paragraph(m, cnt, cmd) { return MARK_UNSET; } + /* fall through... */ + case '<': dir = -1; col0 = '{'; SENTENCE(list = o_sections); + limit = 1L; break; case ']': @@ -373,18 +411,21 @@ MARK m_paragraph(m, cnt, cmd) { return MARK_UNSET; } + /* fall through... */ + case '>': dir = 1; col0 = '{'; SENTENCE(list = o_sections); + limit = nlines; break; } ol = l = markline(m); /* for each paragraph that we want to travel through... */ - while (l > 0 && l <= nlines && cnt-- > 0) + while (l != limit && cnt-- > 0) { /* skip blank lines between paragraphs */ - while (l > 0 && l <= nlines && col0 == *(text = fetchline(l))) + while (l != limit && col0 == *(text = fetchline(l))) { l += dir; } @@ -407,22 +448,14 @@ MARK m_paragraph(m, cnt, cmd) } #endif l += dir; - } while (l > 0 && l <= nlines && col0 != *(text = fetchline(l))); + } while (l != limit && col0 != *(text = fetchline(l))); BreakBreak: ; } - if (l > nlines) - { - m = MARK_LAST; - } - else if (l <= 0) - { - m = MARK_FIRST; - } - else - { - m = MARK_AT_LINE(l); - } + m = MARK_AT_LINE(l); +#ifdef DEBUG2 + debout("m_paragraph() returning %ld.%d\n", markline(m), markidx(m)); +#endif return m; } diff --git a/usr.bin/elvis/move2.c b/usr.bin/elvis/move2.c index b664153cb26b..999274e4b5a5 100644 --- a/usr.bin/elvis/move2.c +++ b/usr.bin/elvis/move2.c @@ -44,37 +44,50 @@ MARK m_wsrch(word, m, cnt) } #endif -MARK m_nsrch(m) +MARK m_nsrch(m, cnt, cmd) MARK m; /* where to start searching */ + long cnt; /* number of searches to do */ + int cmd; /* command character -- 'n' or 'N' */ { - if (prevsf) + int oldprevsf; /* original value of prevsf, so we can fix any changes */ + + DEFAULT(1L); + + /* clear the bottom line. In particular, we want to loose any + * "(wrapped)" notice. + */ + move(LINES - 1, 0); + clrtoeol(); + + /* if 'N' command, then invert the "prevsf" variable */ + oldprevsf = prevsf; + if (cmd == 'N') { - m = m_fsrch(m, (char *)0); - prevsf = TRUE; + prevsf = !prevsf; } - else + + /* search forward if prevsf -- i.e., if previous search was forward */ + while (--cnt >= 0L && m != MARK_UNSET) { - m = m_bsrch(m, (char *)0); - prevsf = FALSE; + if (prevsf) + { + m = m_fsrch(m, (char *)0); + } + else + { + m = m_bsrch(m, (char *)0); + } } + + /* restore the old value of prevsf -- if cmd=='N' then it was inverted, + * and the m_fsrch() and m_bsrch() functions force it to a (possibly + * incorrect) value. The value of prevsf isn't supposed to be changed + * at all here! + */ + prevsf = oldprevsf; return m; } -MARK m_Nsrch(m) - MARK m; /* where to start searching */ -{ - if (prevsf) - { - m = m_bsrch(m, (char *)0); - prevsf = TRUE; - } - else - { - m = m_fsrch(m, (char *)0); - prevsf = FALSE; - } - return m; -} MARK m_fsrch(m, ptrn) MARK m; /* where to start searching */ @@ -104,7 +117,7 @@ MARK m_fsrch(m, ptrn) ptrn++; /* free the previous pattern */ - if (re) free(re); + if (re) _free_(re); /* compile the pattern */ re = regcomp(ptrn); @@ -214,7 +227,7 @@ MARK m_bsrch(m, ptrn) ptrn++; /* free the previous pattern, if any */ - if (re) free(re); + if (re) _free_(re); /* compile the pattern */ re = regcomp(ptrn); diff --git a/usr.bin/elvis/move3.c b/usr.bin/elvis/move3.c index a9e46ea8a949..69949eed3612 100644 --- a/usr.bin/elvis/move3.c +++ b/usr.bin/elvis/move3.c @@ -21,7 +21,7 @@ static char prev_key; /* sought cvhar from previous [fFtT] */ MARK m__ch(m, cnt, cmd) MARK m; /* current position */ long cnt; - char cmd; /* command: either ',' or ';' */ + int cmd; /* command: either ',' or ';' */ { MARK (*tmp)(); @@ -52,7 +52,7 @@ MARK m__ch(m, cnt, cmd) MARK m_fch(m, cnt, key) MARK m; /* where to search from */ long cnt; - char key; /* what to search for */ + int key; /* what to search for */ { REG char *text; @@ -83,7 +83,7 @@ MARK m_fch(m, cnt, key) MARK m_Fch(m, cnt, key) MARK m; /* where to search from */ long cnt; - char key; /* what to search for */ + int key; /* what to search for */ { REG char *text; @@ -114,50 +114,32 @@ MARK m_Fch(m, cnt, key) MARK m_tch(m, cnt, key) MARK m; /* where to search from */ long cnt; - char key; /* what to search for */ + int key; /* what to search for */ { - /* skip the adjacent char */ - pfetch(markline(m)); - if (plen <= markidx(m)) - { - return MARK_UNSET; - } - m++; - m = m_fch(m, cnt, key); - if (m == MARK_UNSET) + if (m != MARK_UNSET) { - return MARK_UNSET; + prevfwdfn = m_tch; + prevrevfn = m_Tch; + m--; } - - prevfwdfn = m_tch; - prevrevfn = m_Tch; - - return m - 1; + return m; } /* move backward within this line almost to previous occurrence of key */ MARK m_Tch(m, cnt, key) MARK m; /* where to search from */ long cnt; - char key; /* what to search for */ + int key; /* what to search for */ { - /* skip the adjacent char */ - if (markidx(m) == 0) - { - return MARK_UNSET; - } - m--; - m = m_Fch(m, cnt, key); if (m == MARK_UNSET) { - return MARK_UNSET; + prevfwdfn = m_Tch; + prevrevfn = m_tch; + m++; } - prevfwdfn = m_Tch; - prevrevfn = m_tch; - - return m + 1; + return m; } #endif diff --git a/usr.bin/elvis/move4.c b/usr.bin/elvis/move4.c index a31ef881f347..d42082d653af 100644 --- a/usr.bin/elvis/move4.c +++ b/usr.bin/elvis/move4.c @@ -136,6 +136,12 @@ MARK m_scroll(m, cnt, key) int key; /* keystroke that causes this movement */ { MARK tmp; /* a temporary mark, used as arg to redraw() */ +#ifndef CRUNCH + int savenearscroll; + + savenearscroll = *o_nearscroll; + *o_nearscroll = LINES; +#endif /* adjust cnt, and maybe *o_scroll, depending of key */ switch (key) @@ -207,5 +213,8 @@ MARK m_scroll(m, cnt, key) break; } +#ifndef CRUNCH + *o_nearscroll = savenearscroll; +#endif return m; } diff --git a/usr.bin/elvis/move5.c b/usr.bin/elvis/move5.c index aec5e785b008..408bac379cd9 100644 --- a/usr.bin/elvis/move5.c +++ b/usr.bin/elvis/move5.c @@ -36,7 +36,7 @@ MARK m_fword(m, cnt, cmd, prevkey) */ if (cnt == 1L && prevkey == 'c' && isspace(*text)) { - return m + 1L; + return m; } #endif diff --git a/usr.bin/elvis/opts.c b/usr.bin/elvis/opts.c index c9c32c0faaa6..0d2d8d63f6f8 100644 --- a/usr.bin/elvis/opts.c +++ b/usr.bin/elvis/opts.c @@ -18,7 +18,6 @@ #ifndef NULL #define NULL (char *)0 #endif -extern char *getenv(); /* maximum width to permit for strings, including ="" */ #define MAXWIDTH 20 @@ -28,7 +27,7 @@ char o_autoindent[1] = {FALSE}; char o_autoprint[1] = {TRUE}; char o_autotab[1] = {TRUE}; char o_autowrite[1] = {FALSE}; -char o_columns[3] = {80, 32, 255}; +char o_columns[3] = {80, 32, ~0}; char o_directory[30] = TMPDIR; char o_edcompatible[1] = {FALSE}; char o_equalprg[80] = {"fmt"}; @@ -45,7 +44,7 @@ char o_remap[1] = {TRUE}; char o_report[3] = {5, 1, 127}; char o_scroll[3] = {12, 1, 127}; char o_shell[60] = SHELL; -char o_shiftwidth[3] = {8, 1, 255}; +char o_shiftwidth[3] = {8, 1, ~0}; char o_sidescroll[3] = {8, 1, 40}; char o_sync[1] = {NEEDSYNC}; char o_tabstop[3] = {8, 1, 40}; @@ -59,12 +58,14 @@ char o_beautify[1] = {FALSE}; char o_exrc[1] = {FALSE}; char o_mesg[1] = {TRUE}; char o_more[1] = {TRUE}; +char o_nearscroll[3] = {15, 0, ~0}; char o_novice[1] = {FALSE}; char o_prompt[1] = {TRUE}; char o_taglength[3] = {0, 0, 30}; +char o_tags[256] = {"tags"}; char o_terse[1] = {FALSE}; char o_window[3] = {0, 1, 24}; -char o_wrapmargin[3] = {0, 0, 255}; +char o_wrapmargin[3] = {0, 0, ~0}; char o_writeany[1] = {FALSE}; #endif @@ -123,6 +124,11 @@ char o_showmatch[1] = {FALSE}; char o_smd[1] = {FALSE}; #endif +#ifndef NO_TAGSTACK +char o_tagstack[1] = {TRUE}; +#endif + + /* The following describes the names & types of all options */ #define BOOL 0 @@ -199,6 +205,7 @@ struct #endif #ifndef CRUNCH { "more", "mo", BOOL, CANSET, o_more }, + { "nearscroll", "ns", NUM, CANSET, o_nearscroll }, { "novice", "nov", BOOL, CANSET, o_novice }, #endif { "number", "nu", BOOL, CANSET|MR, o_number }, @@ -234,6 +241,10 @@ struct { "tabstop", "ts", NUM, CANSET|MR, o_tabstop }, #ifndef CRUNCH { "taglength", "tl", NUM, CANSET, o_taglength }, + { "tags", "tag", STR, CANSET, o_tags }, +#endif +#ifndef NO_TAGSTACK + { "tagstack", "tgs", BOOL, CANSET, o_tagstack }, #endif { "term", "te", STR, SET, o_term }, #ifndef CRUNCH @@ -304,6 +315,7 @@ void initopts() { o_window[0] = o_window[2] = *o_lines; } + *o_nearscroll = *o_lines; #endif /* disable the flash option if we don't know how to do a flash */ @@ -685,7 +697,11 @@ void setopts(assignments) /* change the variable */ if (!opts[i].name) { - msg("invalid option name \"%s\"", name); + /* only complain about unknown options if we're editing + * a file; i.e., if we're not executing the .exrc now. + */ + if (tmpfd >= 0) + msg("invalid option name \"%s\"", name); } else if ((opts[i].flags & CANSET) != CANSET) { diff --git a/usr.bin/elvis/recycle.c b/usr.bin/elvis/recycle.c index 421603610a54..c3a2a8fa4ad1 100644 --- a/usr.bin/elvis/recycle.c +++ b/usr.bin/elvis/recycle.c @@ -180,4 +180,31 @@ dbfree(ptr, file, line) } free(ptr - sizeof(long)); } + +dbcheckmem(file, line) + char *file; + int line; +{ + int i, j; + + for (i = j = 0; i < MAXALLOC && allocated[i]; i++) + { + if (((long *)allocated[i])[-1] != MEMMAGIC) + { + if (!j) endwin(); + fprintf(stderr, "\r\n%s(%d): underflowed malloc space, allocated at %s(%d)\n", file, line, fromfile[i], fromline[i]); + j++; + } + if (((long *)allocated[i])[sizes[i]] != MEMMAGIC) + { + if (!j) endwin(); + fprintf(stderr, "\r\n%s(%d): overflowed malloc space, allocated at %s(%d)\n", file, line, fromfile[i], fromline[i]); + j++; + } + } + if (j) + { + abort(); + } +} #endif diff --git a/usr.bin/elvis/redraw.c b/usr.bin/elvis/redraw.c index ae923cf60a30..358eaec7fcf2 100644 --- a/usr.bin/elvis/redraw.c +++ b/usr.bin/elvis/redraw.c @@ -19,6 +19,11 @@ #include "config.h" #include "vi.h" +#ifdef CRUNCH +# define NEAR LINES +#else +# define NEAR (*o_nearscroll&0xff) +#endif /* This variable contains the line number that smartdrawtext() knows best */ static long smartlno; @@ -367,7 +372,7 @@ static void drawtext(text, lno, clr) /* show the line number, if necessary */ if (*o_number) { - sprintf(numstr, "%6ld |", lno); + sprintf(numstr, "%6ld ", lno); qaddstr(numstr); } @@ -494,7 +499,7 @@ static void drawtext(text, lno, clr) { qaddch(' '); col++; - } while (col < i); + } while (col < i && col < limitcol); } else #endif /* !NO_VISIBLE */ @@ -522,11 +527,16 @@ static void drawtext(text, lno, clr) { qaddch(' '); col++; - } while (col < i); + } while (col < i && col < limitcol); } } else /* tab ending after screen? next line! */ { +#ifdef CRUNCH + /* needed at least when scrolling the screen right -nox */ + if (clr && col < limitcol) + clrtoeol(); +#endif col = limitcol; if (has_AM) { @@ -798,7 +808,7 @@ static void smartdrawtext(text, lno, showit) /* show the line number, if necessary */ if (*o_number) { - sprintf(numstr, "%6ld |", lno); + sprintf(numstr, "%6ld ", lno); qaddstr(numstr); } @@ -980,7 +990,7 @@ void redraw(curs, inputting) smartdrawtext(text, l, (chgs != changes)); } } - else if (l < topline && l > topline - LINES && (has_SR || has_AL)) + else if (l < topline && l >= topline - NEAR && (has_SR || has_AL)) { /* near top - scroll down */ if (!mustredraw) @@ -1012,7 +1022,7 @@ void redraw(curs, inputting) redrawrange(0L, INFINITY, INFINITY); } } - else if (l > topline && l < botline + LINES) + else if (l > topline && l <= botline + NEAR) { /* near bottom -- scroll up */ if (!mustredraw) @@ -1038,12 +1048,13 @@ void redraw(curs, inputting) else { /* distant line - center it & force a redraw */ - topline = l - (LINES / 2) - 1; + topline = l - (LINES - 1) / 2; if (topline < 1) { topline = 1; } redrawrange(0L, INFINITY, INFINITY); + smartlno = 0L; changes++; } diff --git a/usr.bin/elvis/regexp.c b/usr.bin/elvis/regexp.c index 91db71af854b..96cce7f8b859 100644 --- a/usr.bin/elvis/regexp.c +++ b/usr.bin/elvis/regexp.c @@ -93,6 +93,8 @@ static char *makeclass(text, bmap) int complement = 0; + checkmem(); + /* zero the bitmap */ for (i = 0; bmap && i < 32; i++) { @@ -119,7 +121,7 @@ static char *makeclass(text, bmap) } /* add each character in the span to the bitmap */ - for (i = text[0]; bmap && i <= text[2]; i++) + for (i = UCHAR(text[0]); bmap && (unsigned)i <= UCHAR(text[2]); i++) { bmap[i >> 3] |= (1 << (i & 7)); } @@ -133,7 +135,7 @@ static char *makeclass(text, bmap) i = *text++; if (bmap) { - bmap[i >> 3] |= (1 << (i & 7)); + bmap[UCHAR(i) >> 3] |= (1 << (UCHAR(i) & 7)); } } } @@ -153,6 +155,8 @@ static char *makeclass(text, bmap) } } + checkmem(); + return text; } @@ -171,6 +175,10 @@ static int gettoken(sptr, re) int c; c = **sptr; + if (!c) + { + return c; + } ++*sptr; if (c == '\\') { @@ -353,21 +361,30 @@ regexp *regcomp(exp) int token; int peek; char *build; +#if __STDC__ + volatile +#endif regexp *re; #ifndef CRUNCH int from; int to; int digit; #endif +#ifdef DEBUG + int calced; +#endif + checkmem(); + /* prepare for error handling */ re = (regexp *)0; if (setjmp(errorhandler)) { + checkmem(); if (re) { - free(re); + _free_(re); } return (regexp *)0; } @@ -384,20 +401,26 @@ regexp *regcomp(exp) else /* non-empty regexp given, so remember it */ { if (previous) - free(previous); + _free_(previous); previous = (char *)malloc((unsigned)(strlen(exp) + 1)); if (previous) strcpy(previous, exp); } /* allocate memory */ + checkmem(); class_cnt = 0; start_cnt = 1; end_sp = 0; retext = exp; +#ifdef DEBUG + calced = calcsize(exp); + size = calced + sizeof(regexp); +#else size = calcsize(exp) + sizeof(regexp) + 10; /* !!! 10 bytes for slop */ +#endif #ifdef lint - re = ((regexp *)0) + size; + re = (regexp *)0; #else re = (regexp *)malloc((unsigned)size); #endif @@ -405,6 +428,7 @@ regexp *regcomp(exp) { FAIL("Not enough memory for this RE"); } + checkmem(); /* compile it */ build = &re->program[1 + 32 * class_cnt]; @@ -541,6 +565,7 @@ regexp *regcomp(exp) *build++ = token; } } + checkmem(); /* end it with a \) which MUST MATCH the opening \( */ ADD_META(build, M_END(0)); @@ -549,6 +574,15 @@ regexp *regcomp(exp) FAIL("Not enough \\)s"); } +#ifdef DEBUG + if ((int)(build - re->program) != calced) + { + msg("regcomp error: calced=%d, actual=%d", calced, (int)(build - re->program)); + getkey(0); + } +#endif + + checkmem(); return re; } @@ -577,7 +611,7 @@ int match1(re, ch, token) } else if (IS_CLASS(token)) { - if (re->program[1 + 32 * (token - M_CLASS(0)) + (ch >> 3)] & (1 << (ch & 7))) + if (re->program[1 + 32 * (token - M_CLASS(0)) + (UCHAR(ch) >> 3)] & (1 << (UCHAR(ch) & 7))) return 0; } else if (ch == token || *o_ignorecase && tolower(ch) == tolower(token)) @@ -733,6 +767,8 @@ int regexec(re, str, bol) int len; /* length of the string */ REG char *here; + checkmem(); + /* if must start at the beginning of a line, and this isn't, then fail */ if (re->bol && !bol) { @@ -780,6 +816,7 @@ int regexec(re, str, bol) } /* if we didn't fail, then we must have succeeded */ + checkmem(); return 1; } diff --git a/usr.bin/elvis/regsub.c b/usr.bin/elvis/regsub.c index d9ea1a153c62..65592b30bd3c 100644 --- a/usr.bin/elvis/regsub.c +++ b/usr.bin/elvis/regsub.c @@ -56,6 +56,7 @@ void regsub(re, src, dst) } /* allocate memory for the ~ed version of src */ + checkmem(); start = cpy = (char *)malloc((unsigned)(len + 1)); if (!cpy) { @@ -94,10 +95,11 @@ void regsub(re, src, dst) msg("Bug in regsub.c! Predicted length = %d, Actual length = %d", len, (int)(cpy - start)); } #endif + checkmem(); /* remember this as the "previous" for next time */ if (prev) - free(prev); + _free_(prev); prev = src = start; #endif /* undef CRUNCH */ diff --git a/usr.bin/elvis/system.c b/usr.bin/elvis/system.c index 988cdf795994..1d7b7db62000 100644 --- a/usr.bin/elvis/system.c +++ b/usr.bin/elvis/system.c @@ -22,7 +22,9 @@ #include "config.h" #include "vi.h" +#ifndef XDOS extern char **environ; +#endif #if ANY_UNIX @@ -30,6 +32,9 @@ extern char **environ; * between this one and the library one is: this one uses the o_shell option. */ int system(cmd) +#ifdef __STDC__ + const +#endif char *cmd; /* a command to run */ { int pid; /* process ID of child */ @@ -73,11 +78,7 @@ int system(cmd) { status = -1; } -#if __GNUC__ - signal(SIGINT, (void (*)()) trapint); -#else signal(SIGINT, trapint); -#endif } return status; @@ -168,11 +169,7 @@ int rpclose(fd) close(fd); wait(&status); -#if __GNUC__ - signal(SIGINT, (void (*)()) trapint); -#else signal(SIGINT, trapint); -#endif return status; } @@ -372,13 +369,13 @@ int filter(from, to, cmd, back) } #endif } - } - /* delete old text, if any */ - if (to) - { - cut(from, to); - delete(from, to); + /* delete old text, if any */ + if (to) + { + cut(from, to); + delete(from, to); + } } } else diff --git a/usr.bin/elvis/tio.c b/usr.bin/elvis/tio.c index 66bd2618367e..56b0e9370fbf 100644 --- a/usr.bin/elvis/tio.c +++ b/usr.bin/elvis/tio.c @@ -14,10 +14,11 @@ #include "vi.h" #include "ctype.h" +static int showmsg P_((void)); /* This function reads in a line from the terminal. */ int vgets(prompt, buf, bsize) - char prompt; /* the prompt character, or '\0' for none */ + int prompt; /* the prompt character, or '\0' for none */ char *buf; /* buffer into which the string is read */ int bsize; /* size of the buffer */ { @@ -57,7 +58,7 @@ int vgets(prompt, buf, bsize) else { /* maybe expand an abbreviation while getting key */ - for (word = len; --word >= 0 && isalnum(buf[word]); ) + for (word = len; --word >= 0 && !isspace(buf[word]); ) { } word++; @@ -74,8 +75,10 @@ int vgets(prompt, buf, bsize) #endif /* some special conversions */ +#if 0 if (ch == ctrl('D') && len == 0) ch = ctrl('['); +#endif #ifndef NO_DIGRAPH if (*o_digraph && erased != 0 && ch != '\b') { @@ -99,9 +102,10 @@ int vgets(prompt, buf, bsize) quoted = TRUE; break; - case ctrl('['): + case ctrl('D'): return -1; + case ctrl('['): case '\n': #if OSK case '\l': @@ -111,6 +115,21 @@ int vgets(prompt, buf, bsize) clrtoeol(); goto BreakBreak; +#ifndef CRUNCH + case ctrl('U'): + while (len > 0) + { + len--; + while (widths[len]-- > 0) + { + qaddch('\b'); + qaddch(' '); + qaddch('\b'); + } + } + break; +#endif + case '\b': if (len > 0) { @@ -235,14 +254,24 @@ void endmsgs() * msg("") - clears the message line * msg("%s %d", ...) - does a printf onto the message line */ -/*VARARGS1*/ +#ifdef __STDC__ +void msg (char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); +#else void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) char *fmt; long arg1, arg2, arg3, arg4, arg5, arg6, arg7; { +#endif if (mode != MODE_VI) { +#ifdef __STDC__ + vsprintf (pmsg, fmt, ap); +#else sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7); +#endif qaddstr(pmsg); addch('\n'); exrefresh(); @@ -256,12 +285,19 @@ void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) } /* real message */ +#ifdef __STDC__ + vsprintf (pmsg, fmt, ap); +#else sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7); +#endif if (*fmt) { manymsgs = TRUE; } } +#ifdef __STDC__ + va_end (ap); +#endif } @@ -330,7 +366,7 @@ void beep() } else if (*o_errorbells) { - ttywrite("\007", 1); + tputs("\007", 1, faddch); } /* discard any buffered input, and abort macros */ @@ -426,6 +462,10 @@ void execmap(rawlen, cookedstr, visual) #endif } +#ifndef NO_CURSORSHAPE +/* made global so that suspend_curses() can reset it. -nox */ +int oldcurs; +#endif /* This function calls ttyread(). If necessary, it will also redraw the screen, * change the cursor shape, display the mode, and update the ruler. If the * number of characters read is 0, and we didn't time-out, then it exits because @@ -443,9 +483,6 @@ static int fillkeybuf(when, timeout) static long oldnlines; char *str; #endif -#ifndef NO_CURSORSHAPE - static int oldcurs; -#endif #ifdef DEBUG watch(); @@ -480,7 +517,10 @@ static int fillkeybuf(when, timeout) redraw(cursor, !(when & WHEN_VICMD)); /* now the "topline" test should be valid */ - if (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines) + if (when != oldwhen + || topline != oldtop + || leftcol != oldleft + || nlines != oldnlines) { oldwhen = when; oldtop = topline; @@ -490,9 +530,9 @@ static int fillkeybuf(when, timeout) if (when & WHEN_VICMD) str = "Command"; else if (when & WHEN_VIINP) str = " Input "; else if (when & WHEN_VIREP) str = "Replace"; - else if (when & WHEN_REP1) str = " Rep 1 "; - else if (when & WHEN_CUT) str = "BufName"; - else if (when & WHEN_MARK) str = "Mark AZ"; + else if (when & WHEN_REP1) str = "Replc 1"; + else if (when & WHEN_CUT) str = "Buffer "; + else if (when & WHEN_MARK) str = " Mark "; else if (when & WHEN_CHAR) str = "Dest Ch"; else str = (char *)0; @@ -539,7 +579,7 @@ static int fillkeybuf(when, timeout) clrtoeol(); refresh(); endwin(); - exit(1); + exit(exitcode); } cend += nkeys; @@ -592,7 +632,12 @@ static int countmatch(when) /* No, it wouldn't. But check for partial match */ if (!strncmp(map->rawin, &keybuf[next], cend - next)) { - count++; + /* increment by 2 instead of 1 so that, in the + * event that we have a partial match with a + * single map, we don't mistakenly assume we + * have resolved the map yet. + */ + count += 2; } } } @@ -612,7 +657,7 @@ static void expandabbr(word, wlen) MAP *abbr; /* if the next character wouldn't end the word, then don't expand */ - if (isalnum(keybuf[next]) || keybuf[next] == ctrl('V')) + if (isalnum(keybuf[next]) || keybuf[next] == ctrl('V') || keybuf[next] == '\b') { return; } @@ -696,7 +741,7 @@ int getabkey(when, word, wlen) } /* try to map the key, unless already mapped and not ":set noremap" */ - if (next >= user || *o_remap) + if (next <= user || *o_remap) { do { @@ -713,6 +758,12 @@ int getabkey(when, word, wlen) } while (*o_remap && matches == 1); } + /* ERASEKEY should always be mapped to '\b'. */ + if (keybuf[next] == ERASEKEY) + { + keybuf[next] = '\b'; + } + #ifndef NO_ABBR /* try to expand an abbreviation, except in visual command mode */ if (wlen > 0 && (mode & (WHEN_EX|WHEN_VIINP|WHEN_VIREP)) != 0) @@ -721,12 +772,6 @@ int getabkey(when, word, wlen) } #endif - /* ERASEKEY should always be mapped to '\b'. */ - if (keybuf[next] == ERASEKEY) - { - keybuf[next] = '\b'; - } - /* return the next key */ return keybuf[next++]; } @@ -735,7 +780,7 @@ int getabkey(when, word, wlen) void mapkey(rawin, cooked, when, name) char *rawin; /* the input key sequence, before mapping */ char *cooked;/* after mapping -- or NULL to remove map */ - short when; /* bitmap of when mapping should happen */ + int when; /* bitmap of when mapping should happen */ char *name; /* name of the key, NULL for no name, "abbr" for abbr */ { MAP **head; /* head of list of maps or abbreviations */ @@ -751,7 +796,7 @@ void mapkey(rawin, cooked, when, name) /* try to find the map in the list */ for (scan = *head, prev = (MAP *)0; - scan && (strcmp(rawin, scan->rawin) || + scan && (strcmp(rawin, scan->rawin) && strcmp(rawin, scan->cooked) || !(scan->flags & when & (WHEN_EX|WHEN_VICMD|WHEN_VIINP|WHEN_VIREP))); prev = scan, scan = scan->next) { @@ -778,7 +823,7 @@ void mapkey(rawin, cooked, when, name) { scan = (MAP *)malloc(sizeof(MAP)); scan->len = strlen(rawin); - scan->rawin = malloc(scan->len + 1); + scan->rawin = malloc((unsigned)(scan->len + 1)); strcpy(scan->rawin, rawin); scan->flags = when; scan->label = name; @@ -794,9 +839,9 @@ void mapkey(rawin, cooked, when, name) } else /* recycle old structure */ { - free(scan->cooked); + _free_(scan->cooked); } - scan->cooked = malloc(strlen(cooked) + 1); + scan->cooked = malloc((unsigned)(strlen(cooked) + 1)); strcpy(scan->cooked, cooked); } else /* unmapping */ @@ -818,9 +863,9 @@ void mapkey(rawin, cooked, when, name) } /* free it, and the strings that it refers to */ - free(scan->rawin); - free(scan->cooked); - free(scan); + _free_(scan->rawin); + _free_(scan->cooked); + _free_(scan); } } @@ -924,7 +969,7 @@ void dumpkey(when, abbr) #ifndef NO_MKEXRC -static safequote(str) +static void safequote(str) char *str; { char *build; @@ -949,15 +994,14 @@ static safequote(str) * :abbr dumpkey(WHEN_VIINP|WHEN_VIREP, TRUE); * :abbr! dumpkey(WHEN_EX|WHEN_VIINP|WHEN_VIREP, TRUE); */ +void savemaps(fd, abbr) int fd; /* file descriptor of an open file to write to */ int abbr; /* boolean: do abbr table? (else do map table) */ { MAP *scan; - char *str; int bang; int when; - int len; # ifndef NO_ABBR for (scan = (abbr ? abbrs : maps); scan; scan = scan->next) diff --git a/usr.bin/elvis/tmp.c b/usr.bin/elvis/tmp.c index 23c80fedb476..46d29ec81daa 100644 --- a/usr.bin/elvis/tmp.c +++ b/usr.bin/elvis/tmp.c @@ -5,13 +5,6 @@ * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu - * - * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE - * -------------------- ----- ---------------------- - * CURRENT PATCH LEVEL: 1 00041 - * -------------------- ----- ---------------------- - * - * 12 Aug 92 Bob Wilcox Fixed named yank buffer problem */ @@ -153,11 +146,15 @@ int tmpstart(filename) ((getuid() >> 16) == 0 ? S_IOWRITE | S_IWRITE : ((statb.st_gid != (getuid() >> 16) ? S_IOWRITE : S_IWRITE))))) #endif -#if AMIGA || MSDOS || (TOS && defined(__GNUC__)) +#if AMIGA || MSDOS if (*o_readonly || !(statb.st_mode & S_IWRITE)) #endif -#if TOS && !defined(__GNUC__) +#if TOS +# ifdef __GNUC__ + if (*o_readonly || !(statb.st_mode & S_IWRITE)) +# else if (*o_readonly || (statb.st_mode & S_IJRON)) +# endif #endif #if ANY_UNIX if (*o_readonly || !(statb.st_mode & @@ -185,25 +182,36 @@ int tmpstart(filename) } /* make a name for the tmp file */ - tmpnum++; -#if MSDOS || TOS - /* MS-Dos doesn't allow multiple slashes, but supports drives - * with current directories. - * This relies on TMPNAME beginning with "%s\\"!!!! - */ - strcpy(tmpname, o_directory); - if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1])) - tmpname[i++]=SLASH; - sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum); -#else - sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum); -#endif - - /* make sure nobody else is editing the same file */ - if (access(tmpname, 0) == 0) + do { - FAIL("Temp file \"%s\" already exists?", tmpname); - } + tmpnum++; +#if MSDOS || TOS + /* MS-Dos doesn't allow multiple slashes, but supports drives + * with current directories. + * This relies on TMPNAME beginning with "%s\\"!!!! + */ + strcpy(tmpname, o_directory); + if ((i = strlen(tmpname)) && !strchr(":/\\", tmpname[i-1])) + tmpname[i++]=SLASH; + sprintf(tmpname+i, TMPNAME+3, getpid(), tmpnum); +#else + sprintf(tmpname, TMPNAME, o_directory, getpid(), tmpnum); +#endif + } while (access(tmpname, 0) == 0); + + /* !!! RACE CONDITION HERE - some other process with the same PID could + * create the temp file between the access() call and the creat() call. + * This could happen in a couple of ways: + * - different workstation may share the same temp dir via NFS. Each + * workstation could have a process with the same number. + * - The DOS version may be running multiple times on the same physical + * machine in different virtual machines. The DOS pid number will + * be the same on all virtual machines. + * + * This race condition could be fixed by replacing access(tmpname, 0) + * with open(tmpname, O_CREAT|O_EXCL, 0600), if we could only be sure + * that open() *always* used modern UNIX semantics. + */ /* create the temp file */ #if ANY_UNIX @@ -219,8 +227,11 @@ int tmpstart(filename) } /* allocate space for the header in the file */ - write(tmpfd, hdr.c, (unsigned)BLKSIZE); - write(tmpfd, tmpblk.c, (unsigned)BLKSIZE); + if (write(tmpfd, hdr.c, (unsigned)BLKSIZE) < BLKSIZE + || write(tmpfd, tmpblk.c, (unsigned)BLKSIZE) < BLKSIZE) + { + FAIL("Error writing headers to \"%s\"", tmpname); + } #ifndef NO_RECYCLE /* initialize the block allocator */ @@ -292,7 +303,7 @@ int tmpstart(filename) this->c[j++] = 0x80; } #ifndef CRUNCH - else if (*o_beautify && this->c[k] < ' ' && this->c[k] > 0) + else if (*o_beautify && this->c[k] < ' ' && this->c[k] >= 1) { if (this->c[k] == '\t' || this->c[k] == '\n' @@ -345,6 +356,10 @@ int tmpstart(filename) } /* allocate next buffer */ + if (i >= MAXBLKS - 2) + { + FAIL("File too big. Limit is approx %ld kbytes.", MAXBLKS * BLKSIZE / 1024L); + } next = blkget(++i); /* move fragmentary last line to next buffer */ @@ -475,11 +490,7 @@ int tmpsave(filename, bang) } /* can't rewrite a READONLY file */ -#if AMIGA if (!strcmp(filename, origname) && tstflag(file, READONLY) && !bang) -#else - if (!strcmp(filename, origname) && *o_readonly && !bang) -#endif { msg("\"%s\" [READONLY] -- NOT WRITTEN", filename); return FALSE; @@ -552,6 +563,10 @@ int tmpsave(filename, bang) /* reset the "modified" flag, but not the "undoable" flag */ clrflag(file, MODIFIED); significant = FALSE; + if (!strcmp(origname, filename)) + { + exitcode &= ~1; + } /* report lines & characters */ #if MSDOS || TOS @@ -601,11 +616,6 @@ int tmpabort(bang) blkinit(); nlines = 0; initflags(); -#ifdef BROKEN_YANK_BUFFERS /* 12 Aug 92*/ - close(tmpfd); - tmpfd = -1; - unlink(tmpname); -#endif /* BROKEN_YANK_BUFFERS*/ return TRUE; } @@ -652,6 +662,7 @@ sync() * to store the arguments to a command, so we can't use it here. Instead, * we'll borrow the buffer that is used for "shift-U". */ +int storename(name) char *name; /* the name of the file - normally origname */ { @@ -669,7 +680,11 @@ storename(name) U_text[1] = 127; } #ifndef CRUNCH +# if TOS || MINT || MSDOS || AMIGA + else if (*name != '/' && *name != '\\' && !(*name && name[1] == ':')) +# else else if (*name != SLASH) +# endif { /* get the directory name */ ptr = getcwd(U_text, BLKSIZE); @@ -696,7 +711,10 @@ storename(name) { /* write the name out to second block of the temp file */ lseek(tmpfd, (long)BLKSIZE, 0); - write(tmpfd, U_text, (unsigned)BLKSIZE); + if (write(tmpfd, U_text, (unsigned)BLKSIZE) < BLKSIZE) + { + FAIL("Error stuffing name \"%s\" into temp file", U_text); + } } return 0; } @@ -706,7 +724,7 @@ storename(name) /* This function handles deadly signals. It restores sanity to the terminal * preserves the current temp file, and deletes any old temp files. */ -int deathtrap(sig) +SIGTYPE deathtrap(sig) int sig; /* the deadly signal that we caught */ { char *why; @@ -730,8 +748,10 @@ int deathtrap(sig) # ifdef SIGBUS case SIGBUS: why = "-Elvis had a bus error"; break; # endif -# if defined(SIGSEGV) && !defined(TOS) +# ifdef SIGSEGV +# if !TOS case SIGSEGV: why = "-Elvis had a segmentation violation"; break; +# endif # endif # ifdef SIGSYS case SIGSYS: why = "-Elvis munged a system call"; break; diff --git a/usr.bin/elvis/unix.c b/usr.bin/elvis/unix.c index e1364845438b..f25b60afebf5 100644 --- a/usr.bin/elvis/unix.c +++ b/usr.bin/elvis/unix.c @@ -79,6 +79,9 @@ int ttyread(buf, len, time) case -1: /* assume we got an EINTR because of SIGWINCH */ if (*o_lines != LINES || *o_columns != COLS) { +#ifndef CRUNCH + *o_nearscroll = +#endif *o_lines = LINES; *o_columns = COLS; #ifndef CRUNCH @@ -106,10 +109,10 @@ int ttyread(buf, len, time) } # else -# if M_SYSV -/* For System-V or Coherent, we use VMIN/VTIME to implement the timeout. - * For no timeout, VMIN should be 1 and VTIME should be 0; for timeout, - * VMIN should be 0 and VTIME should be the timeout value. +# if UNIXV || COH_386 +/* For System-V, we use VMIN/VTIME to implement the timeout. For no timeout, + * VMIN should be 1 and VTIME should be 0; for timeout, VMIN should be 0 and + * VTIME should be the timeout value. */ # include int ttyread(buf, len, time) @@ -135,7 +138,7 @@ int ttyread(buf, len, time) ioctl(0, TCSETA, &tio); /* Perform the read. Loop if EINTR error happens */ - while ((bytes = read(0, buf, len)) < 0) + while ((bytes = read(0, buf, (unsigned)len)) < 0) { /* probably EINTR error because a SIGWINCH was received */ if (*o_lines != LINES || *o_columns != COLS) @@ -145,6 +148,7 @@ int ttyread(buf, len, time) #ifndef CRUNCH if (!wset) { + *o_nearscroll = LINES; *o_window = LINES - 1; } #endif @@ -178,7 +182,7 @@ int ttyread(buf, len, time) static jmp_buf env; /*ARGSUSED*/ -int dummy(signo) +SIGTYPE dummy(signo) int signo; { longjmp(env, 1); @@ -189,17 +193,13 @@ int ttyread(buf, len, time) int time; /* maximum time to allow for reading */ { /* arrange for timeout */ -#if __GNUC__ - signal(SIGALRM, (void (*)()) dummy); -#else signal(SIGALRM, dummy); -#endif alarm(time); /* perform the blocking read */ if (setjmp(env) == 0) { - len = read(0, buf, len); + len = read(0, buf, (unsigned)len); } else /* I guess we timed out */ { @@ -216,7 +216,7 @@ int ttyread(buf, len, time) return len; } -# endif /* !(M_SYSV || COHERENT) */ +# endif /* M_SYSV */ # endif /* !BSD */ #endif /* ANY_UNIX */ diff --git a/usr.bin/elvis/vars.c b/usr.bin/elvis/vars.c index 19b5d193ac4b..b009df4a5f5b 100644 --- a/usr.bin/elvis/vars.c +++ b/usr.bin/elvis/vars.c @@ -51,6 +51,7 @@ int bavar; /* used only in BeforeAfter macros */ /* used to detect changes that invalidate cached text/blocks */ long changes; /* incremented when file is changed */ int significant; /* boolean: was a *REAL* change made? */ +int exitcode = 1; /* 0=overwritten, 1=not updated, else error */ /* used to support the pfetch() macro */ int plen; /* length of the line */ diff --git a/usr.bin/elvis/vcmd.c b/usr.bin/elvis/vcmd.c index 494f7e1f722b..4fd09238042c 100644 --- a/usr.bin/elvis/vcmd.c +++ b/usr.bin/elvis/vcmd.c @@ -264,7 +264,7 @@ MARK v_overtype(m) /* Normally, we input starting here, in replace mode */ ChangeText { - end = input(m, m, WHEN_VIREP, FALSE); + end = input(m, m, WHEN_VIREP, 0); } /* if we ended on the same line we started on, then this @@ -361,14 +361,13 @@ MARK v_insert(m, cnt, key) { int wasdot; long reps; - int above; /* boolean: new line going above old line? */ + int delta = 0;/* 1 to take autoindent from line below, -1 for above */ DEFAULT(1); ChangeText { /* tweak the insertion point, based on command key */ - above = FALSE; switch (key) { case 'i': @@ -394,19 +393,20 @@ MARK v_insert(m, cnt, key) case 'O': m &= ~(BLKSIZE - 1); add(m, "\n"); - above = TRUE; + delta = 1; break; case 'o': m = (m & ~(BLKSIZE - 1)) + BLKSIZE; add(m, "\n"); + delta = -1; break; } /* insert the same text once or more */ for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE) { - m = input(m, m, WHEN_VIINP, above) + 1; + m = input(m, m, WHEN_VIINP, delta) + 1; } if (markidx(m) > 0) { @@ -455,7 +455,7 @@ MARK v_change(m, n) ChangeText { cut(m, n); - m = input(m, n, WHEN_VIINP, FALSE); + m = input(m, n, WHEN_VIINP, 0); } return m; @@ -479,7 +479,7 @@ MARK v_subst(m, cnt) ChangeText { cut(m, m + cnt); - m = input(m, m + cnt, WHEN_VIINP, FALSE); + m = input(m, m + cnt, WHEN_VIINP, 0); } return m; } @@ -964,12 +964,24 @@ MARK v_popup(m, n) break; } - /* arrange for the menu to be erased (except that "chg from kbd" - * already erased it, and "save & exit" doesn't care) + /* arrange for the menu to be erased (except "save & exit" doesn't care) */ - if (sel != 5 && sel != 9) + if (mode == MODE_VI) redraw(MARK_UNSET, FALSE); return m; } #endif /* undef NO_POPUP */ + +#ifndef NO_TAGSTACK +MARK v_pop(m, cnt, cmd) + MARK m; /* original cursor position (ignored) */ + long cnt; /* number of levels to pop */ + int cmd; /* command key -- ^T (ignored) */ +{ + DEFAULT(1L); + sprintf(tmpblk.c, "%ld", cnt); + cmd_pop(m, m, CMD_POP, FALSE, tmpblk.c); + return cursor; +} +#endif diff --git a/usr.bin/elvis/vi.c b/usr.bin/elvis/vi.c index 24c46dc3f8eb..2c4648f46193 100644 --- a/usr.bin/elvis/vi.c +++ b/usr.bin/elvis/vi.c @@ -73,7 +73,11 @@ static struct keystru /* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS|VIZ}, /* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, +#ifndef NO_TAGSTACK +/* ^T pop tagstack */ {v_pop, CURSOR, NO_FLAGS}, +#else /* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, +#endif /* ^U scroll up 1/2page*/ {m_scroll, CURSOR, NCOL|VIZ}, /* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, @@ -87,7 +91,7 @@ static struct keystru /* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS}, -/* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS}, +/* ^^ previous file */ {v_switch, CURSOR, FRNT}, /* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, /* SPC move right,like l*/ {m_right, CURSOR, MVMT|INCL|VIZ}, /* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL|VIZ}, @@ -168,7 +172,7 @@ static struct keystru #endif /* L move to last row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL}, /* M move to mid row */ {m_row, CURSOR, MVMT|LNMD|FRNT|VIZ|INCL}, -/* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT|NREL|VIZ}, +/* N reverse prev srch*/ {m_nsrch, CURSOR, MVMT|NREL|VIZ}, /* O insert above line*/ {v_insert, CURSOR, SDOT}, /* P paste before */ {v_paste, CURSOR, SDOT}, /* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS}, @@ -185,7 +189,7 @@ static struct keystru #else /* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif -/* W move forward Word*/ {m_fword, CURSOR, MVMT|INCL|VIZ}, +/* W move forward Word*/ {m_fword, CURSOR, MVMT|INCL|NWRP|VIZ}, /* X delete to left */ {v_xchar, CURSOR, SDOT}, /* Y yank text */ {v_yank, CURSOR_MOVED, NCOL}, /* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS}, @@ -233,13 +237,13 @@ static struct keystru #else /* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, #endif -/* w move fwd word */ {m_fword, CURSOR, MVMT|INCL|VIZ}, +/* w move fwd word */ {m_fword, CURSOR, MVMT|INCL|NWRP|VIZ}, /* x delete character */ {v_xchar, CURSOR, SDOT}, /* y yank text */ {v_yank, CURSOR_MOVED, NCOL|VIZ}, /* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL|VIZ}, -/* { back paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ}, +/* { back paragraph */ {m_paragraph, CURSOR, MVMT|VIZ}, /* | move to column */ {m_tocol, CURSOR, MVMT|NREL|VIZ}, -/* } fwd paragraph */ {m_paragraph, CURSOR, MVMT|LNMD|VIZ}, +/* } fwd paragraph */ {m_paragraph, CURSOR, MVMT|VIZ}, /* ~ upper/lowercase */ {v_ulcase, CURSOR, SDOT}, /* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS} }; @@ -316,6 +320,9 @@ void vi() key = getkey(WHEN_VICMD); } while (key < 0 || key > 127); } +#ifdef DEBUG2 + debout("\nkey='%c'\n", key); +#endif /* Convert a doubled-up operator such as "dd" into "d_" */ if (prevkey && key == prevkey) @@ -551,7 +558,8 @@ void vi() do { text[0] = key; - if (vgets(key, text + 1, sizeof text - 1) >= 0) + text[1] = '\0'; + if (doingdot || vgets(key, text + 1, sizeof text - 1) >= 0) { /* reassure user that was hit */ qaddch('\r'); @@ -583,16 +591,25 @@ void vi() } /* now move the cursor, as appropriate */ - if (keyptr->args == CURSOR_MOVED) + if (prevkey && ((keyptr->flags & MVMT) +#ifndef NO_VISIBLE + || V_from +#endif + ) && count == 0L) + { + /* movements used as targets are less strict */ + tcurs = adjmove(cursor, tcurs, (int)(keyptr->flags | force_flags)); + } + else if (keyptr->args == CURSOR_MOVED) { /* the < and > keys have FRNT, * but it shouldn't be applied yet */ - tcurs = adjmove(cursor, tcurs, 0); + tcurs = adjmove(cursor, tcurs, FINL); } else { - tcurs = adjmove(cursor, tcurs, (int)keyptr->flags | force_flags); + tcurs = adjmove(cursor, tcurs, (int)(keyptr->flags | force_flags | FINL)); } /* was that the end of a d/c/y//! command? */ @@ -629,7 +646,7 @@ void vi() * to the front of a line. Instead, they should take * us only to the end of the preceding line. */ - if ((keyptr->flags & (MVMT|NREL|LNMD|FRNT|INCL)) == MVMT + if ((keyptr->flags & NWRP) == NWRP && markline(range) < markline(tcurs) && (markline(tcurs) > nlines || tcurs == m_front(tcurs, 0L))) { @@ -660,8 +677,8 @@ void vi() tcurs = (*vikeys[prevkey].func)(range, tcurs); if (mode == MODE_VI) { - (void)adjmove(cursor, cursor, 0); - cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags); + (void)adjmove(cursor, cursor, FINL); + cursor = adjmove(cursor, tcurs, (int)(vikeys[prevkey].flags | FINL)); } /* cleanup */ @@ -688,6 +705,9 @@ MARK adjmove(old, new, flags) REG char *text; /* used to scan through the line's text */ REG int i; +#ifdef DEBUG2 + debout("adjmove(%ld.%d, %ld.%d, 0x%x)\n", markline(old), markidx(old), markline(new), markidx(new), flags); +#endif #ifdef DEBUG watch(); #endif @@ -695,8 +715,12 @@ MARK adjmove(old, new, flags) /* if the command failed, bag it! */ if (new == MARK_UNSET) { - beep(); - return old; + if (flags & FINL) + { + beep(); + return old; + } + return new; } /* if this is a non-relative movement, set the '' mark */ @@ -712,6 +736,10 @@ MARK adjmove(old, new, flags) } else if (markline(new) > nlines) { + if (!(flags & FINL)) + { + return MARK_EOF; + } new = MARK_LAST; } diff --git a/usr.bin/elvis/vi.h b/usr.bin/elvis/vi.h index 4c42dd2fc959..ce624a2c6560 100644 --- a/usr.bin/elvis/vi.h +++ b/usr.bin/elvis/vi.h @@ -7,13 +7,14 @@ * kirkenda@cs.pdx.edu */ -#define VERSION "ELVIS 1.5, by Steve Kirkendall (23 March 1992)" +#define VERSION "ELVIS 1.7, by Steve Kirkendall (30 December 1992)" #define COPYING "This version of ELVIS is freely redistributable." #include -extern int errno; -#if TOS && !defined(__GNUC__) -#define ENOENT (-AEFILNF) +#if TOS +# ifndef __GNUC__ +# define ENOENT (-AEFILNF) +# endif #endif #if TOS || VMS @@ -33,8 +34,10 @@ extern int errno; # define ENOENT E_PNNF # define sprintf Sprintf # else -# include -# if COHERENT +# if !AMIGA +# include +# endif +# if COH_286 # include # else # include @@ -49,6 +52,16 @@ extern int errno; #include "curses.h" #include +#ifdef __STDC__ +# include /* for [v]sprintf prototype */ +# include /* for str* prototypes */ +# include /* for atoi, system, malloc, free */ +# include /* for vararg definitions */ +# if ANY_UNIX +# include /* for read, write, ... prototypes */ +# include /* for wait prototype */ +# endif +#endif /*------------------------------------------------------------------------*/ /* Miscellaneous constants. */ @@ -74,8 +87,8 @@ typedef union /* These are used manipulate BLK buffers. */ extern BLK hdr; /* buffer for the header block */ -extern BLK *blkget(); /* given index into hdr.c[], reads block */ -extern BLK *blkadd(); /* inserts a new block into hdr.c[] */ +extern BLK *blkget P_((int)); /* given index into hdr.c[], reads block */ +extern BLK *blkadd P_((int)); /* inserts a new block into hdr.c[] */ /*------------------------------------------------------------------------*/ /* These are used to keep track of various flags */ @@ -138,9 +151,11 @@ extern char o_beautify[1]; extern char o_exrc[1]; extern char o_mesg[1]; extern char o_more[1]; +extern char o_nearscroll[3]; extern char o_novice[1]; extern char o_prompt[1]; extern char o_taglength[3]; +extern char o_tags[256]; extern char o_terse[1]; extern char o_window[3]; extern char o_wrapmargin[3]; @@ -195,6 +210,10 @@ extern char o_showmatch[1]; extern char o_smd[1]; #endif +#ifndef NO_TAGSTACK +extern char o_tagstack[1]; +#endif + /*------------------------------------------------------------------------*/ /* These help support the single-line multi-change "undo" -- shift-U */ @@ -210,6 +229,7 @@ typedef long MARK; #define MARK_UNSET ((MARK)0) #define MARK_FIRST ((MARK)BLKSIZE) #define MARK_LAST ((MARK)(nlines * BLKSIZE)) +#define MARK_EOF ((MARK)((nlines + 1) * BLKSIZE)) #define MARK_AT_LINE(x) ((MARK)(x) * BLKSIZE) #define NMARKS 29 @@ -227,78 +247,101 @@ extern long prevline; /* line number from preceding file */ /*------------------------------------------------------------------------*/ /* misc housekeeping variables & functions */ -extern int tmpfd; /* fd used to access the tmp file */ -extern int tmpnum; /* counter used to generate unique filenames */ -extern long lnum[MAXBLKS]; /* last line# of each block */ -extern long nlines; /* number of lines in the file */ -extern char args[BLKSIZE]; /* file names given on the command line */ -extern int argno; /* the current element of args[] */ -extern int nargs; /* number of filenames in args */ -extern long changes; /* counts changes, to prohibit short-cuts */ -extern int significant; /* boolean: was a *REAL* change made? */ -extern BLK tmpblk; /* a block used to accumulate changes */ -extern long topline; /* file line number of top line */ -extern int leftcol; /* column number of left col */ +extern int tmpfd; /* fd used to access the tmp file */ +extern int tmpnum; /* counter used to generate unique filenames */ +extern long lnum[MAXBLKS]; /* last line# of each block */ +extern long nlines; /* number of lines in the file */ +extern char args[BLKSIZE]; /* file names given on the command line */ +extern int argno; /* the current element of args[] */ +extern int nargs; /* number of filenames in args */ +extern long changes; /* counts changes, to prohibit short-cuts */ +extern int significant; /* boolean: was a *REAL* change made? */ +extern int exitcode; /* 0=not updated, 1=overwritten, else error */ +extern BLK tmpblk; /* a block used to accumulate changes */ +extern long topline; /* file line number of top line */ +extern int leftcol; /* column number of left col */ #define botline (topline + LINES - 2) #define rightcol (leftcol + COLS - (*o_number ? 9 : 1)) -extern int physcol; /* physical column number that cursor is on */ -extern int physrow; /* physical row number that cursor is on */ -extern int exwrote; /* used to detect verbose ex commands */ -extern int doingdot; /* boolean: are we doing the "." command? */ -extern int doingglobal; /* boolean: are doing a ":g" command? */ -extern long rptlines; /* number of lines affected by a command */ -extern char *rptlabel; /* description of how lines were affected */ -extern char *fetchline(); /* read a given line from tmp file */ -extern char *parseptrn(); /* isolate a regexp in a line */ -extern MARK paste(); /* paste from cut buffer to a given point */ -extern char *wildcard(); /* expand wildcards in filenames */ -extern MARK input(); /* inserts characters from keyboard */ -extern char *linespec(); /* finds the end of a /regexp/ string */ +extern int physcol; /* physical column number that cursor is on */ +extern int physrow; /* physical row number that cursor is on */ +extern int exwrote; /* used to detect verbose ex commands */ +extern int doingdot; /* boolean: are we doing the "." command? */ +extern int doingglobal; /* boolean: are doing a ":g" command? */ +extern long rptlines; /* number of lines affected by a command */ +extern char *rptlabel; /* description of how lines were affected */ +extern char *fetchline P_((long)); /* read a given line from tmp file */ +extern char *parseptrn P_((REG char *)); /* isolate a regexp in a line */ +extern MARK paste P_((MARK, int, int)); /* paste from cut buffer to a given point */ +extern char *wildcard P_((char *)); /* expand wildcards in filenames */ +extern MARK input P_((MARK, MARK, int, int)); /* inserts characters from keyboard */ +extern char *linespec P_((REG char *, MARK *)); /* finds the end of a /regexp/ string */ #define ctrl(ch) ((ch)&037) #ifndef NO_RECYCLE -extern long allocate(); /* allocate a free block of the tmp file */ +extern long allocate P_((void)); /* allocate a free block of the tmp file */ #endif -extern int trapint(); /* trap handler for SIGINT */ -extern int deathtrap(); /* trap handler for deadly signals */ -extern void blkdirty(); /* marks a block as being "dirty" */ -extern void blkflush(); /* writes a single dirty block to the disk */ -extern void blksync(); /* forces all "dirty" blocks to disk */ -extern void blkinit(); /* resets the block cache to "empty" state */ -extern void beep(); /* rings the terminal's bell */ -extern void exrefresh(); /* writes text to the screen */ -extern void msg(); /* writes a printf-style message to the screen */ -extern void endmsgs(); /* if "manymsgs" is set, then scroll up 1 line */ -extern void garbage(); /* reclaims any garbage blocks */ -extern void redraw(); /* updates the screen after a change */ -extern void resume_curses();/* puts the terminal in "cbreak" mode */ -extern void beforedo(); /* saves current revision before a new change */ -extern void afterdo(); /* marks end of a beforedo() change */ -extern void abortdo(); /* like "afterdo()" followed by "undo()" */ -extern int undo(); /* restores file to previous undo() */ -extern void dumpkey(); /* lists key mappings to the screen */ -extern void mapkey(); /* defines a new key mapping */ -extern void savekeys(); /* lists key mappings to a file */ -extern void redrawrange(); /* records clues from modify.c */ -extern void cut(); /* saves text in a cut buffer */ -extern void delete(); /* deletes text */ -extern void add(); /* adds text */ -extern void change(); /* deletes text, and then adds other text */ -extern void cutswitch(); /* updates cut buffers when we switch files */ -extern void do_abbr(); /* defines or lists abbreviations */ -extern void do_digraph(); /* defines or lists digraphs */ -extern void exstring(); /* execute a string as EX commands */ -extern void dumpopts(); -extern void setopts(); -extern void saveopts(); -extern void savedigs(); -extern void saveabbr(); -extern void savecolor(); -extern void cutname(); -extern void cutname(); -extern void initopts(); -extern void cutend(); +extern SIGTYPE trapint P_((int)); /* trap handler for SIGINT */ +extern SIGTYPE deathtrap P_((int)); /* trap handler for deadly signals */ +extern void blkdirty P_((BLK *)); /* marks a block as being "dirty" */ +extern void blksync P_((void)); /* forces all "dirty" blocks to disk */ +extern void blkinit P_((void)); /* resets the block cache to "empty" state */ +extern void beep P_((void)); /* rings the terminal's bell */ +extern void exrefresh P_((void)); /* writes text to the screen */ +#ifdef __STDC__ +extern void msg (char *, ...); /* writes a printf-style message to the screen */ +#else +extern void msg (); /* writes a printf-style message to the screen */ +#endif +extern void endmsgs P_((void)); /* if "manymsgs" is set, then scroll up 1 line */ +extern void garbage P_((void)); /* reclaims any garbage blocks */ +extern void redraw P_((MARK, int)); /* updates the screen after a change */ +extern void resume_curses P_((int)); /* puts the terminal in "cbreak" mode */ +extern void beforedo P_((int)); /* saves current revision before a new change */ +extern void afterdo P_((void)); /* marks end of a beforedo() change */ +extern void abortdo P_((void)); /* like "afterdo()" followed by "undo()" */ +extern int undo P_((void)); /* restores file to previous undo() */ +extern void dumpkey P_((int, int)); /* lists key mappings to the screen */ +extern void mapkey P_((char *, char *, int, char *)); /* defines a new key mapping */ +extern void redrawrange P_((long, long, long)); /* records clues from modify.c */ +extern void cut P_((MARK, MARK)); /* saves text in a cut buffer */ +extern void delete P_((MARK, MARK)); /* deletes text */ +extern void add P_((MARK, char *)); /* adds text */ +extern void change P_((MARK, MARK, char *));/* deletes text, and then adds other text */ +extern void cutswitch P_((void)); /* updates cut buffers when we switch files */ +extern void do_digraph P_((int, char [])); /* defines or lists digraphs */ +extern void exstring P_((char *, int, int));/* execute a string as EX commands */ +extern void dumpopts P_((int)); /* display current option settings on the screen */ +extern void setopts P_((char *)); /* assign new values to options */ +extern void saveopts P_((int)); /* save current option values to a given fd */ +extern void savedigs P_((int)); /* save current non-standard digraphs to fd */ +extern void savecolor P_((int)); /* save current color settings (if any) to fd */ +extern void cutname P_((int)); /* select cut buffer for next cut/paste */ +extern void initopts P_((void)); /* initialize options */ +extern void cutend P_((void)); /* free all cut buffers & delete temp files */ +extern int storename P_((char *)); /* stamp temp file with pathname of text file */ +extern int tmpstart P_((char *)); /* load a text file into edit buffer */ +extern int tmpsave P_((char *, int)); /* write edit buffer out to text file */ +extern int tmpend P_((int)); /* call tmpsave(), and then tmpabort */ +extern int tmpabort P_((int)); /* abandon the current edit buffer */ +extern void savemaps P_((int, int)); /* write current :map or :ab commands to fd */ +extern int ansicolor P_((int, int)); /* emit ANSI color command to terminal */ +extern int filter P_((MARK, MARK, char *, int)); /* I/O though another program */ +extern int getkey P_((int)); /* return a keystroke, interpretting maps */ +extern int vgets P_((int, char *, int)); /* read a single line from keyboard */ +extern int doexrc P_((char *)); /* execute a string as a sequence of EX commands */ +extern int cb2str P_((int, char *, unsigned));/* return a string containing cut buffer's contents */ +extern int ansiquit P_((void)); /* neutralize previous ansicolor() call */ +extern int ttyread P_((char *, int, int)); /* read from keyboard with optional timeout */ +extern int tgetent P_((char *, char *)); /* start termcap */ +extern int tgetnum P_((char *)); /* get a termcap number */ +extern int tgetflag P_((char *)); /* get a termcap boolean */ +extern int getsize P_((int)); /* determine how big the screen is */ +extern int endcolor P_((void)); /* used during color output */ +extern int getabkey P_((int, char *, int));/* like getkey(), but also does abbreviations */ +extern int idx2col P_((MARK, REG char *, int)); /* returns column# of a given MARK */ +extern int cutneeds P_((BLK *)); /* returns bitmap of blocks needed to hold cutbuffer text */ +extern void execmap P_((int, char *, int)); /* replaces "raw" keys with "mapped" keys */ #ifndef CRUNCH -extern int wset; /* boolean: has the "window" size been set? */ +extern int wset; /* boolean: has the "window" size been set? */ #endif /*------------------------------------------------------------------------*/ @@ -313,42 +356,41 @@ extern int bavar; /* used only in BeforeAfter macros */ /* These are the movement commands. Each accepts a mark for the starting */ /* location & number and returns a mark for the destination. */ -extern MARK m_updnto(); /* k j G */ -extern MARK m_right(); /* h */ -extern MARK m_left(); /* l */ -extern MARK m_tocol(); /* | */ -extern MARK m_front(); /* ^ */ -extern MARK m_rear(); /* $ */ -extern MARK m_fword(); /* w */ -extern MARK m_bword(); /* b */ -extern MARK m_eword(); /* e */ -extern MARK m_paragraph(); /* { } [[ ]] */ -extern MARK m_match(); /* % */ +extern MARK m_updnto P_((MARK, long, int)); /* k j G */ +extern MARK m_right P_((MARK, long, int, int)); /* h */ +extern MARK m_left P_((MARK, long)); /* l */ +extern MARK m_tocol P_((MARK, long, int)); /* | */ +extern MARK m_front P_((MARK, long)); /* ^ */ +extern MARK m_rear P_((MARK, long)); /* $ */ +extern MARK m_fword P_((MARK, long, int, int)); /* w */ +extern MARK m_bword P_((MARK, long, int)); /* b */ +extern MARK m_eword P_((MARK, long, int)); /* e */ +extern MARK m_paragraph P_((MARK, long, int)); /* { } [[ ]] */ +extern MARK m_match P_((MARK, long)); /* % */ #ifndef NO_SENTENCE - extern MARK m_sentence(); /* ( ) */ +extern MARK m_sentence P_((MARK, long, int)); /* ( ) */ #endif -extern MARK m_tomark(); /* 'm */ +extern MARK m_tomark P_((MARK, long, int)); /* 'm */ #ifndef NO_EXTENSIONS -extern MARK m_wsrch(); /* ^A */ +extern MARK m_wsrch P_((char *, MARK, int)); /* ^A */ #endif -extern MARK m_nsrch(); /* n */ -extern MARK m_Nsrch(); /* N */ -extern MARK m_fsrch(); /* /regexp */ -extern MARK m_bsrch(); /* ?regexp */ +extern MARK m_nsrch P_((MARK, long, int)); /* n */ +extern MARK m_fsrch P_((MARK, char *)); /* /regexp */ +extern MARK m_bsrch P_((MARK, char *)); /* ?regexp */ #ifndef NO_CHARSEARCH - extern MARK m__ch(); /* ; , */ - extern MARK m_fch(); /* f */ - extern MARK m_tch(); /* t */ - extern MARK m_Fch(); /* F */ - extern MARK m_Tch(); /* T */ +extern MARK m__ch P_((MARK, long, int)); /* ; , */ +extern MARK m_fch P_((MARK, long, int)); /* f */ +extern MARK m_tch P_((MARK, long, int)); /* t */ +extern MARK m_Fch P_((MARK, long, int)); /* F */ +extern MARK m_Tch P_((MARK, long, int)); /* T */ #endif -extern MARK m_row(); /* H L M */ -extern MARK m_z(); /* z */ -extern MARK m_scroll(); /* ^B ^F ^E ^Y ^U ^D */ +extern MARK m_row P_((MARK, long, int)); /* H L M */ +extern MARK m_z P_((MARK, long, int)); /* z */ +extern MARK m_scroll P_((MARK, long, int)); /* ^B ^F ^E ^Y ^U ^D */ /* Some stuff that is used by movement functions... */ -extern MARK adjmove(); /* a helper fn, used by move fns */ +extern MARK adjmove P_((MARK, REG MARK, int)); /* a helper fn, used by move fns */ /* This macro is used to set the default value of cnt */ #define DEFAULT(val) if (cnt < 1) cnt = (val) @@ -358,8 +400,8 @@ extern int plen; /* length of the line */ extern long pline; /* line number that len refers to */ extern long pchgs; /* "changes" level that len refers to */ extern char *ptext; /* text of previous line, if valid */ -extern void pfetch(); -extern char digraph(); +extern void pfetch P_((long)); +extern char digraph P_((int, int)); /* This is used to build a MARK that corresponds to a specific point in the * line that was most recently pfetch'ed. @@ -370,169 +412,174 @@ extern char digraph(); /*------------------------------------------------------------------------*/ /* These are used to handle EX commands. */ -#define CMD_NULL 0 /* NOT A VALID COMMAND */ -#define CMD_ABBR 1 /* "define an abbreviation" */ -#define CMD_ARGS 2 /* "show me the args" */ -#define CMD_APPEND 3 /* "insert lines after this line" */ -#define CMD_AT 4 /* "execute a cut buffer's contents via EX" */ -#define CMD_BANG 5 /* "run a single shell command" */ -#define CMD_CC 6 /* "run `cc` and then do CMD_ERRLIST" */ -#define CMD_CD 7 /* "change directories" */ -#define CMD_CHANGE 8 /* "change some lines" */ -#define CMD_COLOR 9 /* "change the default colors" */ -#define CMD_COPY 10 /* "copy the selected text to a given place" */ -#define CMD_DELETE 11 /* "delete the selected text" */ -#define CMD_DIGRAPH 12 /* "add a digraph, or display them all" */ -#define CMD_EDIT 13 /* "switch to a different file" */ -#define CMD_EQUAL 14 /* "display a line number" */ -#define CMD_ERRLIST 15 /* "locate the next error in a list" */ -#define CMD_FILE 16 /* "show the file's status" */ -#define CMD_GLOBAL 17 /* "globally search & do a command" */ -#define CMD_INSERT 18 /* "insert lines before the current line" */ -#define CMD_JOIN 19 /* "join the selected line & the one after" */ -#define CMD_LIST 20 /* "print lines, making control chars visible" */ -#define CMD_MAKE 21 /* "run `make` and then do CMD_ERRLIST" */ -#define CMD_MAP 22 /* "adjust the keyboard map" */ -#define CMD_MARK 23 /* "mark this line" */ -#define CMD_MKEXRC 24 /* "make a .exrc file" */ -#define CMD_MOVE 25 /* "move the selected text to a given place" */ -#define CMD_NEXT 26 /* "switch to next file in args" */ -#define CMD_NUMBER 27 /* "print lines from the file w/ line numbers" */ -#define CMD_PRESERVE 28 /* "act as though vi crashed" */ -#define CMD_PREVIOUS 29 /* "switch to the previous file in args" */ -#define CMD_PRINT 30 /* "print the selected text" */ -#define CMD_PUT 31 /* "insert any cut lines before this line" */ -#define CMD_QUIT 32 /* "quit without writing the file" */ -#define CMD_READ 33 /* "append the given file after this line */ -#define CMD_RECOVER 34 /* "recover file after vi crashes" - USE -r FLAG */ -#define CMD_REWIND 35 /* "rewind to first file" */ -#define CMD_SET 36 /* "set a variable's value" */ -#define CMD_SHELL 37 /* "run some lines through a command" */ -#define CMD_SHIFTL 38 /* "shift lines left" */ -#define CMD_SHIFTR 39 /* "shift lines right" */ -#define CMD_SOURCE 40 /* "interpret a file's contents as ex commands" */ -#define CMD_STOP 41 /* same as CMD_SUSPEND */ -#define CMD_SUBAGAIN 42 /* "repeat the previous substitution" */ -#define CMD_SUBSTITUTE 43 /* "substitute text in this line" */ -#define CMD_SUSPEND 44 /* "suspend the vi session" */ -#define CMD_TR 45 /* "transliterate chars in the selected lines" */ -#define CMD_TAG 46 /* "go to a particular tag" */ -#define CMD_UNABBR 47 /* "remove an abbreviation definition" */ -#define CMD_UNDO 48 /* "undo the previous command" */ -#define CMD_UNMAP 49 /* "remove a key sequence map */ -#define CMD_VERSION 50 /* "describe which version this is" */ -#define CMD_VGLOBAL 51 /* "apply a cmd to lines NOT containing an RE" */ -#define CMD_VISUAL 52 /* "go into visual mode" */ -#define CMD_WQUIT 53 /* "write this file out (any case) & quit" */ -#define CMD_WRITE 54 /* "write the selected(?) text to a given file" */ -#define CMD_XIT 55 /* "write this file out (if modified) & quit" */ -#define CMD_YANK 56 /* "copy the selected text into the cut buffer" */ -#ifdef DEBUG -# define CMD_DEBUG 57 /* access to internal data structures */ -# define CMD_VALIDATE 58 /* check for internal consistency */ -#endif +#define CMD_NULL 0 /* NOT A VALID COMMAND */ +#define CMD_ABBR 1 /* "define an abbreviation" */ +#define CMD_ARGS 2 /* "show me the args" */ +#define CMD_APPEND 3 /* "insert lines after this line" */ +#define CMD_AT 4 /* "execute a cut buffer's contents via EX" */ +#define CMD_BANG 5 /* "run a single shell command" */ +#define CMD_CC 6 /* "run `cc` and then do CMD_ERRLIST" */ +#define CMD_CD 7 /* "change directories" */ +#define CMD_CHANGE 8 /* "change some lines" */ +#define CMD_COLOR 9 /* "change the default colors" */ +#define CMD_COPY 10 /* "copy the selected text to a given place" */ +#define CMD_DELETE 11 /* "delete the selected text" */ +#define CMD_DIGRAPH 12 /* "add a digraph, or display them all" */ +#define CMD_EDIT 13 /* "switch to a different file" */ +#define CMD_EQUAL 14 /* "display a line number" */ +#define CMD_ERRLIST 15 /* "locate the next error in a list" */ +#define CMD_FILE 16 /* "show the file's status" */ +#define CMD_GLOBAL 17 /* "globally search & do a command" */ +#define CMD_INSERT 18 /* "insert lines before the current line" */ +#define CMD_JOIN 19 /* "join the selected line & the one after" */ +#define CMD_LIST 20 /* "print lines, making control chars visible" */ +#define CMD_MAKE 21 /* "run `make` and then do CMD_ERRLIST" */ +#define CMD_MAP 22 /* "adjust the keyboard map" */ +#define CMD_MARK 23 /* "mark this line" */ +#define CMD_MKEXRC 24 /* "make a .exrc file" */ +#define CMD_MOVE 25 /* "move the selected text to a given place" */ +#define CMD_NEXT 26 /* "switch to next file in args" */ +#define CMD_NUMBER 27 /* "print lines from the file w/ line numbers" */ +#define CMD_POP 28 /* "pop a position off the tagstack" */ +#define CMD_PRESERVE 29 /* "act as though vi crashed" */ +#define CMD_PREVIOUS 30 /* "switch to the previous file in args" */ +#define CMD_PRINT 31 /* "print the selected text" */ +#define CMD_PUT 32 /* "insert any cut lines before this line" */ +#define CMD_QUIT 33 /* "quit without writing the file" */ +#define CMD_READ 34 /* "append the given file after this line */ +#define CMD_RECOVER 35 /* "recover file after vi crashes" - USE -r FLAG */ +#define CMD_REWIND 36 /* "rewind to first file" */ +#define CMD_SET 37 /* "set a variable's value" */ +#define CMD_SHELL 38 /* "run some lines through a command" */ +#define CMD_SHIFTL 39 /* "shift lines left" */ +#define CMD_SHIFTR 40 /* "shift lines right" */ +#define CMD_SOURCE 41 /* "interpret a file's contents as ex commands" */ +#define CMD_STOP 42 /* same as CMD_SUSPEND */ +#define CMD_SUBAGAIN 43 /* "repeat the previous substitution" */ +#define CMD_SUBSTITUTE 44 /* "substitute text in this line" */ +#define CMD_SUSPEND 45 /* "suspend the vi session" */ +#define CMD_TR 46 /* "transliterate chars in the selected lines" */ +#define CMD_TAG 47 /* "go to a particular tag" */ +#define CMD_UNABBR 48 /* "remove an abbreviation definition" */ +#define CMD_UNDO 49 /* "undo the previous command" */ +#define CMD_UNMAP 50 /* "remove a key sequence map */ +#define CMD_VERSION 51 /* "describe which version this is" */ +#define CMD_VGLOBAL 52 /* "apply a cmd to lines NOT containing an RE" */ +#define CMD_VISUAL 53 /* "go into visual mode" */ +#define CMD_WQUIT 54 /* "write this file out (any case) & quit" */ +#define CMD_WRITE 55 /* "write the selected(?) text to a given file" */ +#define CMD_XIT 56 /* "write this file out (if modified) & quit" */ +#define CMD_YANK 57 /* "copy the selected text into the cut buffer" */ +#define CMD_DEBUG 58 /* access to internal data structures */ +#define CMD_VALIDATE 59 /* check for internal consistency */ typedef int CMD; -extern void ex(); -extern void vi(); -extern void doexcmd(); +extern void ex P_((void)); +extern void vi P_((void)); +extern void doexcmd P_((char *)); -extern void cmd_append(); -extern void cmd_args(); +extern void cmd_append P_((MARK, MARK, CMD, int, char *)); +extern void cmd_args P_((MARK, MARK, CMD, int, char *)); #ifndef NO_AT -extern void cmd_at(); + extern void cmd_at P_((MARK, MARK, CMD, int, char *)); #endif -extern void cmd_cd(); +extern void cmd_cd P_((MARK, MARK, CMD, int, char *)); #ifndef NO_COLOR -extern void cmd_color(); + extern void cmd_color P_((MARK, MARK, CMD, int, char *)); #endif -extern void cmd_delete(); +extern void cmd_delete P_((MARK, MARK, CMD, int, char *)); #ifndef NO_DIGRAPH -extern void cmd_digraph(); + extern void cmd_digraph P_((MARK, MARK, CMD, int, char *)); #endif -extern void cmd_edit(); +extern void cmd_edit P_((MARK, MARK, CMD, int, char *)); #ifndef NO_ERRLIST -extern void cmd_errlist(); + extern void cmd_errlist P_((MARK, MARK, CMD, int, char *)); #endif -extern void cmd_file(); -extern void cmd_global(); -extern void cmd_join(); -extern void cmd_mark(); +extern void cmd_file P_((MARK, MARK, CMD, int, char *)); +extern void cmd_global P_((MARK, MARK, CMD, int, char *)); +extern void cmd_join P_((MARK, MARK, CMD, int, char *)); +extern void cmd_mark P_((MARK, MARK, CMD, int, char *)); #ifndef NO_ERRLIST -extern void cmd_make(); + extern void cmd_make P_((MARK, MARK, CMD, int, char *)); #endif -extern void cmd_map(); +extern void cmd_map P_((MARK, MARK, CMD, int, char *)); #ifndef NO_MKEXRC -extern void cmd_mkexrc(); + extern void cmd_mkexrc P_((MARK, MARK, CMD, int, char *)); #endif -extern void cmd_next(); -extern void cmd_print(); -extern void cmd_put(); -extern void cmd_read(); -extern void cmd_set(); -extern void cmd_shell(); -extern void cmd_shift(); -extern void cmd_source(); -extern void cmd_substitute(); -extern void cmd_tag(); -extern void cmd_undo(); -extern void cmd_version(); -extern void cmd_write(); -extern void cmd_xit(); -extern void cmd_move(); +extern void cmd_next P_((MARK, MARK, CMD, int, char *)); +#ifndef NO_TAGSTACK +extern void cmd_pop P_((MARK, MARK, CMD, int, char *)); +#endif +extern void cmd_print P_((MARK, MARK, CMD, int, char *)); +extern void cmd_put P_((MARK, MARK, CMD, int, char *)); +extern void cmd_read P_((MARK, MARK, CMD, int, char *)); +extern void cmd_set P_((MARK, MARK, CMD, int, char *)); +extern void cmd_shell P_((MARK, MARK, CMD, int, char *)); +extern void cmd_shift P_((MARK, MARK, CMD, int, char *)); +extern void cmd_source P_((MARK, MARK, CMD, int, char *)); +extern void cmd_substitute P_((MARK, MARK, CMD, int, char *)); +extern void cmd_tag P_((MARK, MARK, CMD, int, char *)); +extern void cmd_undo P_((MARK, MARK, CMD, int, char *)); +extern void cmd_version P_((MARK, MARK, CMD, int, char *)); +extern void cmd_write P_((MARK, MARK, CMD, int, char *)); +extern void cmd_xit P_((MARK, MARK, CMD, int, char *)); +extern void cmd_move P_((MARK, MARK, CMD, int, char *)); #ifdef DEBUG -extern void cmd_debug(); -extern void cmd_validate(); + extern void cmd_debug P_((MARK, MARK, CMD, int, char *)); + extern void cmd_validate P_((MARK, MARK, CMD, int, char *)); #endif #ifdef SIGTSTP -extern void cmd_suspend(); + extern void cmd_suspend P_((MARK, MARK, CMD, int, char *)); #endif /*----------------------------------------------------------------------*/ /* These are used to handle VI commands */ -extern MARK v_1ex(); /* : */ -extern MARK v_mark(); /* m */ -extern MARK v_quit(); /* Q */ -extern MARK v_redraw(); /* ^L ^R */ -extern MARK v_ulcase(); /* ~ */ -extern MARK v_undo(); /* u */ -extern MARK v_xchar(); /* x X */ -extern MARK v_replace(); /* r */ -extern MARK v_overtype(); /* R */ -extern MARK v_selcut(); /* " */ -extern MARK v_paste(); /* p P */ -extern MARK v_yank(); /* y Y */ -extern MARK v_delete(); /* d D */ -extern MARK v_join(); /* J */ -extern MARK v_insert(); /* a A i I o O */ -extern MARK v_change(); /* c C */ -extern MARK v_subst(); /* s */ -extern MARK v_lshift(); /* < */ -extern MARK v_rshift(); /* > */ -extern MARK v_reformat(); /* = */ -extern MARK v_filter(); /* ! */ -extern MARK v_status(); /* ^G */ -extern MARK v_switch(); /* ^^ */ -extern MARK v_tag(); /* ^] */ -extern MARK v_xit(); /* ZZ */ -extern MARK v_undoline(); /* U */ -extern MARK v_again(); /* & */ +extern MARK v_1ex P_((MARK, char *)); /* : */ +extern MARK v_mark P_((MARK, long, int)); /* m */ +extern MARK v_quit P_((void)); /* Q */ +extern MARK v_redraw P_((void)); /* ^L ^R */ +extern MARK v_ulcase P_((MARK, long)); /* ~ */ +extern MARK v_undo P_((MARK)); /* u */ +extern MARK v_xchar P_((MARK, long, int)); /* x X */ +extern MARK v_replace P_((MARK, long, int));/* r */ +extern MARK v_overtype P_((MARK)); /* R */ +extern MARK v_selcut P_((MARK, long, int)); /* " */ +extern MARK v_paste P_((MARK, long, int)); /* p P */ +extern MARK v_yank P_((MARK, MARK)); /* y Y */ +extern MARK v_delete P_((MARK, MARK)); /* d D */ +extern MARK v_join P_((MARK, long)); /* J */ +extern MARK v_insert P_((MARK, long, int)); /* a A i I o O */ +extern MARK v_change P_((MARK, MARK)); /* c C */ +extern MARK v_subst P_((MARK, long)); /* s */ +extern MARK v_lshift P_((MARK, MARK)); /* < */ +extern MARK v_rshift P_((MARK, MARK)); /* > */ +extern MARK v_reformat P_((MARK, MARK)); /* = */ +extern MARK v_filter P_((MARK, MARK)); /* ! */ +extern MARK v_status P_((void)); /* ^G */ +extern MARK v_switch P_((void)); /* ^^ */ +extern MARK v_tag P_((char *, MARK, long)); /* ^] */ +extern MARK v_xit P_((MARK, long, int)); /* ZZ */ +extern MARK v_undoline P_((MARK)); /* U */ +extern MARK v_again P_((MARK, MARK)); /* & */ #ifndef NO_EXTENSIONS - extern MARK v_keyword(); /* K */ - extern MARK v_increment(); /* * */ +extern MARK v_keyword P_((char *, MARK, long)); /* K */ +extern MARK v_increment P_((char *, MARK, long)); /* * */ #endif #ifndef NO_ERRLIST - extern MARK v_errlist(); /* * */ +extern MARK v_errlist P_((MARK)); /* * */ #endif #ifndef NO_AT - extern MARK v_at(); /* @ */ +extern MARK v_at P_((MARK, long, int)); /* @ */ #endif #ifdef SIGTSTP - extern MARK v_suspend(); /* ^Z */ +extern MARK v_suspend P_((void)); /* ^Z */ #endif #ifndef NO_POPUP - extern MARK v_popup(); /* \ */ +extern MARK v_popup P_((MARK, MARK)); /* \ */ +#endif +#ifndef NO_TAGSTACK +extern MARK v_pop P_((MARK, long, int)); /* ^T */ #endif /*----------------------------------------------------------------------*/ @@ -546,8 +593,10 @@ extern MARK v_again(); /* & */ #define NCOL 0x20 /* this command can't change the column# */ #define NREL 0x40 /* this is "non-relative" -- set the '' mark */ #define SDOT 0x80 /* set the "dot" variables, for the "." cmd */ +#define FINL 0x100 /* final testing, more strict! */ +#define NWRP 0x200 /* no line-wrap (used for 'w' and 'W') */ #ifndef NO_VISIBLE -# define VIZ 0x100 /* commands which can be used with 'v' */ +# define VIZ 0x400 /* commands which can be used with 'v' */ #else # define VIZ 0 #endif @@ -586,11 +635,14 @@ extern int mode; #ifndef NO_VISIBLE extern MARK V_from; extern int V_linemd; -extern MARK v_start(); +extern MARK v_start P_((MARK m, long cnt, int cmd)); #endif #ifdef DEBUG # define malloc(size) dbmalloc(size, __FILE__, __LINE__) # define free(ptr) dbfree(ptr, __FILE__, __LINE__) -extern char *dbmalloc(); +# define checkmem() dbcheckmem(__FILE__, __LINE__) +extern char *dbmalloc P_((int, char *, int)); +#else +# define checkmem() #endif diff --git a/usr.bin/elvisrecover/elvisrecover.c b/usr.bin/elvisrecover/elvisrecover.c index a0069a94e911..e4d7159439fe 100644 --- a/usr.bin/elvisrecover/elvisrecover.c +++ b/usr.bin/elvisrecover/elvisrecover.c @@ -14,6 +14,10 @@ #include "config.h" #include "vi.h" +void recover P_((char *, char *)); +void main P_((int, char **)); + + void recover(basename, outname) char *basename; /* the name of the file to recover */ char *outname; /* the name of the file to write to */ @@ -164,6 +168,7 @@ void recover(basename, outname) #endif } +void main(argc, argv) int argc; char **argv; @@ -172,7 +177,7 @@ main(argc, argv) if (argc > 3) { fprintf(stderr, "usage: %s [preserved_file [recovery_file]]\n", argv[0]); - exit(1); + exit(2); } /* recover the requested file, or list recoverable files */ diff --git a/usr.bin/ref/Makefile b/usr.bin/ref/Makefile new file mode 100644 index 000000000000..32de9d5103cd --- /dev/null +++ b/usr.bin/ref/Makefile @@ -0,0 +1,7 @@ + +PROG= ref +CFLAGS+=-I${.CURDIR}/../elvis +SRCS= ref.c + +.include +.PATH: ${.CURDIR}/../elvis diff --git a/usr.bin/ref/ref.1 b/usr.bin/ref/ref.1 new file mode 100644 index 000000000000..e7d2e178f144 --- /dev/null +++ b/usr.bin/ref/ref.1 @@ -0,0 +1,88 @@ +.TH REF 1 +.SH NAME +ref - Display a C function header +.SH SYNOPSIS +\fBref\fR [-t] [-c \fIclass\fR]... [-f \fIfile\fR]... \fItag\fR +.SH DESCRIPTION +\fIref\fP quickly locates and displays the header of a function. +To do this, \fIref\fR +looks in the "tags" file for the line that describes the function, and then +scans the source file for the function. +When it locates the function, it displays an introductory comment +(if there is one), the function's declaration, and the declarations of all +arguments. +.SH "SEARCH METHOD" +.PP +\fIref\fR uses a fairly sophisticated tag look-up algorithm. +If you supply a filename via \fB-f\fR \fIfile\fR, then elvis first scans +the tags file for a static tag from that file. +This search is limited to the tags file in the current directory. +.PP +If you supply a classname via \fB-c\fR \fIclass\fR, then elvis searches +for a tag from that class. +This search is not limited to the current directory; +You can supply a list of directories in the environment variable \fITAGPATH\fR, +and \fIref\fR will search through the "tags" file in each directory until it finds +a tag in the desired class. +.PP +If that fails, \fIref\fR will then try to look up an ordinary global tag. +This search checks all of the directories listed in \fITAGPATH\fR, too. +.PP +If you've given the \fB-t\fR flag, then \fIref\fR will simply output the tag line that +it found, and then exit. +Without \fB-t\fR, though, \fIref\fR will search for the tag line. +It will try to open the source file, which should be in the same directory +as the tags file where the tag was discovered. +If the source file doesn't exist, or is unreadable, then \fIref\fR will try to open +a file called "\fIrefs\fR" in that directory. +Either way, \fIref\fR will try to locate the tag, and display whatever it finds. +.SH "INTERACTION WITH ELVIS" +.PP +\fIref\fP is used by \fIelvis\fR' shift-K command. +If the cursor is located on a word such as "splat", in the file "foo.c", +then \fIelvis\fR will invoke \fIref\fR with the command "ref -f foo.c splat". +.PP +If \fIelvis\fR has been compiled with the -DEXTERNAL_TAGS flag, then \fIelvis\fR will +use \fIref\fR \fB\fRto scan the tags files. +This is slower than the built-in tag searching, but it allows \fIelvis\fR to access +the more sophisticated tag lookup provided by \fIref\fR. +Other than that, external tags should act exactly like internal tags. +.SH OPTIONS +.IP \fB-t\fR +Output tag info, instead of the function header. +.IP "\fB-f\fR \fIfile\fR" +The tag might be a static function in \fIfile\fR. +You can use several -f flags to have \fIref\fR consider static tags from more than one file. +.IP "\fB-c\fR \fIclass\fR" +The tag might be a member of class \fIclass\fR. +You can use several -c flags to have \fIref\fR consider tags from more than one class. +.SH FILES +.IP \fBtags\fR +List of function names and their locations, generated by \fIctags\fR. +.IP \fBrefs\fR +Function headers extracted from source files (optional). +.SH ENVIRONMENT +.IP \fBTAGPATH\fR +List of directories to be searched. +The elements in the list are separated by either +semicolons (for MS-DOS, Atari TOS, and AmigaDos), or +by colons (every other operating system). +For each operating system, \fIref\fR has a built-in default which is probably +adequate. +.SH NOTES +.PP +You might want to generate a "tags" file the directory that contains the +source code for standard C library on your system. +If licensing restrictions prevent you from making the library source readable +by everybody, then you can have \fIctags\fR generate a "refs" file, +and make "refs" readable by everybody. +.PP +If your system doesn't come with the library source code, then perhaps you +can produce something workable from the \fIlint\fR libraries. +.SH "SEE ALSO" +elvis(1), ctags(1) +.SH AUTHOR +.nf +Steve Kirkendall +kirkenda@cs.pdx.edu +.fi diff --git a/usr.bin/ref/ref.c b/usr.bin/ref/ref.c new file mode 100644 index 000000000000..0cc105fbea15 --- /dev/null +++ b/usr.bin/ref/ref.c @@ -0,0 +1,550 @@ +/* ref2.c */ + +/* This is a totally rewritten version of ref. This version looks for the + * desired function name in the "tags" file, and then reads the header out + * from the source file. There is no longer any need for a "refs" file. + * + * Usage: ref [-t] [-f file] [-c class] tag + * Options: -t output tag info, not the description + * -f file default filename for static functions + * -c class default class names for class functions + */ +#ifdef __STDC__ +# include +# include +#endif + +#include +#include "config.h" + +extern char *cktagdir P_((char *, char *)); +extern int getline P_((char *, int, FILE *)); +extern int lookup P_((char *, char *)); +extern int find P_((char *)); +extern void usage P_((void)); +extern int countcolons P_((char *)); +extern void main P_((int, char **)); + + +/* This is the default path that is searched for tags */ +#if OSK +# define DEFTAGPATH ".:/dd/defs:/dd/defs/sys:/dd/usr/src/lib:../lib:/dd/usr/lib" +#else +# if ANY_UNIX +# define DEFTAGPATH ".:/usr/include:/usr/include/sys:/usr/src/lib:../lib:/usr/local/lib" +# else +# if MSDOS || TOS +# define DEFTAGPATH ".;C:\\include;C:\\include\\sys;C:\\lib;..\\lib" +# define SEP ';' +# else +# if AMIGA +# define DEFTAGPATH ".;Include:;Include:sys" +# define SEP ';' +# else /* any other OS */ +# define DEFTAGPATH "." +# endif +# endif +# endif +#endif + +#ifndef SEP +# define SEP ':' +#endif + + +/* These variables reflect the command-line options given by the user. */ +int taginfo; /* boolean: give only the tag info? (not header?) */ +char *def_file; /* default filename for static functions */ +char *def_class; /* default classname for class members */ +int colons; /* #colons in tag: 0=normal, 1=static, 2=member */ + +/* This function checks for a tag in the "tags" file of given directory. + * If the tag is found, then it returns a pointer to a static buffer which + * contains the filename, a tab character, and a linespec for finding the + * the tag. If the tag is not found in the "tags" file, or if the "tags" + * file cannot be opened or doesn't exist, then this function returns NULL. + */ +char *cktagdir(tag, dir) + char *tag; /* name of the tag to look for */ + char *dir; /* name of the directory to check */ +{ + char buf[BLKSIZE]; + static char found[BLKSIZE]; + FILE *tfile; + int len; + +#if AMIGA + if (dir[strlen(dir) - 1] == COLON) + sprintf(buf, "%s%s", dir, TAGS); /* no slash after colon. */ + else +#endif + /* construct the name of the "tags" file in this directory */ + sprintf(buf, "%s%c%s", dir, SLASH, TAGS); + + /* Try to open the tags file. Return NULL if can't open */ +#if AMIGA + if (buf[0] == '.' && buf[1] == SLASH) + tfile = fopen(&buf[2], "r"); + else +#endif + tfile = fopen(buf, "r"); + if (!tfile) + { + return (char *)0; + } + + /* compute the length of the tagname once */ + len = strlen(tag); + + /* read lines until we get the one for this tag */ + found[0] = '\0'; + while (fgets(buf, sizeof buf, tfile)) + { + /* is this the one we want? */ + if (!strncmp(buf, tag, len) && buf[len] == '\t') + { + /* we've found a match -- remember it */ + strcpy(found, buf); + + /* if there is no default file, or this match is in + * the default file, then we've definitely found the + * one we want. Break out of the loop now. + */ + if (!def_file || !strncmp(&buf[len + 1], def_file, strlen(def_file))) + { + break; + } + } + } + + /* we're through reading */ + fclose(tfile); + + /* if there's anything in found[], use it */ + if (found[0]) + { + return &found[len + 1]; + } + + /* else we didn't find it */ + return (char *)0; +} + +/* This function reads a single textline from a binary file. It returns + * the number of bytes read, or 0 at EOF. + */ +int getline(buf, limit, fp) + char *buf; /* buffer to read into */ + int limit; /* maximum characters to read */ + FILE *fp; /* binary stream to read from */ +{ + int bytes; /* number of bytes read so far */ + int ch; /* single character from file */ + + for (bytes = 0, ch = 0; ch != '\n' && --limit > 0 && (ch = getc(fp)) != EOF; bytes++) + { +#if MSDOS || TOS + /* since this is a binary file, we'll need to manually strip CR's */ + if (ch == '\r') + { + continue; + } +#endif + *buf++ = ch; + } + *buf = '\0'; + + return bytes; +} + + +/* This function reads a source file, looking for a given tag. If it finds + * the tag, then it displays it and returns TRUE. Otherwise it returns FALSE. + * To display the tag, it attempts to output any introductory comment, the + * tag line itself, and any arguments. Arguments are assumed to immediately + * follow the tag line, and start with whitespace. Comments are assumed to + * start with lines that begin with "/*", "//", "(*", or "--", and end at the + * tag line or at a blank line. + */ +int lookup(dir, entry) + char *dir; /* name of the directory that contains the source */ + char *entry; /* source filename, , linespec */ +{ + char *name; /* basename of source file */ + char buf[BLKSIZE]; /* pathname of source file */ + long lnum; /* desired line number */ + long thislnum; /* current line number */ + long here; /* seek position where current line began */ + long comment; /* seek position of introductory comment, or -1L */ + FILE *sfile; /* used for reading the source file */ + int len; /* length of string */ + int noargs = 0; /* boolean: don't show lines after tag line? */ + char *ptr; + + + /* construct the pathname of the source file */ + name = entry; + strcpy(buf, dir); + ptr = buf + strlen(buf); +#if AMIGA + if (ptr[-1] != COLON) +#endif + *ptr++ = SLASH; + while (*entry != '\t') + { + *ptr++ = *entry++; + } + *entry++ = *ptr = '\0'; + + /* searching for string or number? */ + if (*entry >= '0' && *entry <= '9') + { + /* given a specific line number */ + lnum = atol(entry); + entry = (char *)0; + noargs = 1; + } + else + { + /* given a string -- strip off "/^" and "$/\n" */ + entry += 2; + len = strlen(entry) - 2; + if (entry[len - 1] == '$') + { + entry[len - 1] = '\n'; + } + if (!strchr(entry, '(')) + { + noargs = 1; + } + lnum = 0L; + } + + /* Open the file. Note that we open the file in binary mode even + * though we know it is a text file, because ftell() and fseek() + * don't work on text files. + */ +#if MSDOS || TOS + sfile = fopen(buf, "rb"); +#else +# if AMIGA + if (buf[0] == '.' && buf[1] == SLASH) + sfile = fopen(&buf[2], "r"); + else +# endif + sfile = fopen(buf, "r"); +#endif + if (!sfile) + { + /* can't open the real source file. Try "refs" instead */ +#if AMIGA + if (dir[strlen(dir) - 1] == COLON) + sprintf(buf, "%srefs", dir); + else +#endif + sprintf(buf, "%s%crefs", dir, SLASH); +#if MSDOS || TOS + sfile = fopen(buf, "rb"); +#else +# if AMIGA + if (buf[0] == '.' && buf[1] == SLASH) + sfile = fopen(&buf[2], "r"); + else +# endif + sfile = fopen(buf, "r"); +#endif + if (!sfile) + { + /* failed! */ + return 0; + } + name = "refs"; + } + + /* search the file */ + for (comment = -1L, thislnum = 0; here = ftell(sfile), thislnum++, getline(buf, BLKSIZE, sfile) > 0; ) + { + /* Is this the start/end of a comment? */ + if (comment == -1L) + { + /* starting a comment? */ + if (buf[0] == '/' && buf[1] == '*' + || buf[0] == '/' && buf[1] == '/' + || buf[0] == '(' && buf[1] == '*' + || buf[0] == '-' && buf[1] == '-') + { + comment = here; + } + } + else + { + /* ending a comment? */ + if (buf[0] == '\n' || buf[0] == '#') + { + comment = -1L; + } + } + + /* is this the tag line? */ + if (lnum == thislnum || (entry && !strncmp(buf, entry, len))) + { + /* display the filename & line number where found */ + if (strcmp(dir, ".")) + printf("%s%c%s, line %ld:\n", dir, SLASH, name, thislnum); + else + printf("%s, line %ld:\n", name, thislnum); + + /* if there were introductory comments, show them */ + if (comment != -1L) + { + fseek(sfile, comment, 0); + while (comment != here) + { + getline(buf, BLKSIZE, sfile); + fputs(buf, stdout); + comment = ftell(sfile); + } + + /* re-fetch the tag line */ + fgets(buf, BLKSIZE, sfile); + } + + /* show the tag line */ + fputs(buf, stdout); + + /* are we expected to show argument lines? */ + if (!noargs) + { + /* show any argument lines */ + while (getline(buf, BLKSIZE, sfile) > 0 + && buf[0] != '#' + && strchr(buf, '{') == (char *)0) + { + fputs(buf, stdout); + } + } + + /* Done! Close the file, and return TRUE */ + fclose(sfile); + return 1; + } + } + + /* not found -- return FALSE */ + return 0; +} + +/* This function searches through the entire search path for a given tag. + * If it finds the tag, then it displays the info and returns TRUE; + * otherwise it returns FALSE. + */ +int find(tag) + char *tag; /* the tag to look up */ +{ + char *tagpath; + char dir[80]; + char *ptr; + int len; + + if (colons == 1) + { + /* looking for static function -- only look in current dir */ + tagpath = "."; + } + else + { + /* get the tagpath from the environment. Default to DEFTAGPATH */ + tagpath = getenv("TAGPATH"); + if (!tagpath) + { + tagpath = DEFTAGPATH; + } + } + + /* for each entry in the path... */ + while (*tagpath) + { + /* Copy the entry into the dir[] buffer */ + for (ptr = dir; *tagpath && *tagpath != SEP; tagpath++) + { + *ptr++ = *tagpath; + } + if (*tagpath == SEP) + { + tagpath++; + } + + /* if the entry ended with "/tags", then strip that off */ + len = strlen(TAGS); + if (&dir[len] < ptr && ptr[-len - 1] == SLASH && !strncmp(&ptr[-len], TAGS, len)) + { + ptr -= len + 1; + } + + /* if the entry is now an empty string, then assume "." */ + if (ptr == dir) + { + *ptr++ = '.'; + } + *ptr = '\0'; + + /* look for the tag in this path. If found, then display it + * and exit. + */ + ptr = cktagdir(tag, dir); + if (ptr) + { + /* just supposed to display tag info? */ + if (taginfo) + { + /* then do only that! */ + if (strcmp(dir, ".")) + { + printf("%s%c%s", dir, SLASH, ptr); + } + else + { + /* avoid leading "./" if possible */ + fputs(ptr, stdout); + } + return 1; + } + else + { + /* else look up the declaration of the thing */ + return lookup(dir, ptr); + } + } + } + + /* if we get here, then the tag wasn't found anywhere */ + return 0; +} + +void usage() +{ + fputs("usage: ref [-t] [-c class] [-f file] tag\n", stderr); + fputs(" -t output tag info, instead of the function header\n", stderr); + fputs(" -f File tag might be a static function in File\n", stderr); + fputs(" -c Class tag might be a member of class Class\n", stderr); + exit(2); +} + + +int countcolons(str) + char *str; +{ + while (*str != ':' && *str) + { + str++; + } + if (str[0] != ':') + { + return 0; + } + else if (str[1] != ':') + { + return 1; + } + return 2; +} + +void main(argc, argv) + int argc; + char **argv; +{ + char def_tag[100]; /* used to build tag name with default file/class */ + int i; + + /* parse flags */ + for (i = 1; i < argc && argv[i][0] == '-'; i++) + { + switch (argv[i][1]) + { + case 't': + taginfo = 1; + break; + + case 'f': + if (argv[i][2]) + { + def_file = &argv[i][2]; + } + else if (++i < argc) + { + def_file = argv[i]; + } + else + { + usage(); + } + break; + + case 'c': + if (argv[i][2]) + { + def_class = &argv[i][2]; + } + else if (++i < argc) + { + def_class = argv[i]; + } + else + { + usage(); + } + break; + + default: + usage(); + } + } + + /* if no tag was given, complain */ + if (i + 1 != argc) + { + usage(); + } + + /* does the tag have an explicit class or file? */ + colons = countcolons(argv[i]); + + /* if not, then maybe try some defaults */ + if (colons == 0) + { + /* try a static function in the file first */ + if (def_file) + { + sprintf(def_tag, "%s:%s", def_file, argv[i]); + colons = 1; + if (find(def_tag)) + { + exit(0); + } + } + + /* try a member function for a class */ + if (def_class) + { + sprintf(def_tag, "%s::%s", def_class, argv[i]); + colons = 2; + if (find(def_tag)) + { + exit(0); + } + } + + /* oh, well */ + colons = 0; + } + + /* find the tag */ + if (find(argv[i])) + { + exit(0); + } + + /* Give up. If doing tag lookup then exit(0), else exit(1) */ + exit(!taginfo); + /*NOTREACHED*/ +}