Path: utzoo!utgpu!news-server.csri.toronto.edu!rutgers!usc!elroy.jpl.nasa.gov!mahendo!wlbr!roger.imsd.contel.com!mh From: mh@roger.imsd.contel.com (Mike H.) Newsgroups: comp.windows.news Subject: NeWS version of elvis (the vi clone) part 8 of 9 Message-ID: <1991Jan11.021722.27773@wlbr.imsd.contel.com> Date: 11 Jan 91 02:17:22 GMT References: Sender: news@wlbr.imsd.contel.com (news) Distribution: comp Organization: Contel FSD, Westlake Village, CA Lines: 2683 Nntp-Posting-Host: roger.imsd.contel.com #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # shell.c # sysdos.c # system.c # tinytcap.c # tio.c # tmp.c # tnamerec.c # This archive created: Thu Jan 10 17:21:10 1991 export PATH; PATH=/bin:$PATH if test -f 'shell.c' then echo shar: will not over-write existing file "'shell.c'" else cat << \SHAR_EOF > 'shell.c' /* shell.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* * This file contains a minimal version of a shell for TOS. It allows the * setting of an environment, calling programs, and exiting. * If you don't have another one, this might be sufficient, but you should * prefer *any* other shell. * You may, however, want to set your SHELL environment variable to this * shell: it implements the -c switch, which is required by Elvis, and * not supported by most other atari shells. */ #include #include #include extern char *getenv(), *malloc(); extern char **environ; long _stksize=16384; #define MAXENV 50 struct { char *name; char *value; } myenv[MAXENV]; int cmd_set(), cmd_exit(); struct buildins { char *name; int (*func)(); } buildins[]= { "exit", cmd_exit, "set", cmd_set, 0, }; main(argc, argv) int argc; char **argv; { char buf[128]; int i; for (i=0; environ[i] && strncmp(environ[i],"ARGV=",5); i++) cmd_set(environ[i]); script("profile.sh"); if (argc>1 && !strcmp(argv[1], "-c")) { buf[0]='\0'; for (i=2; i2) strcat(buf, " "); strcat(buf, argv[i]); } execute(buf); } else while (fputs("$ ", stdout), gets(buf)) execute(buf); } execute(buf) char *buf; { char *scan=buf; char cmd[80]; char line[128]; char env[4096], *ep=env; int i; while (*scan==' ') scan++; if (!*scan) return; while (*scan && *scan!=' ') scan++; if (*scan) *scan++='\0'; for (i=0; buildins[i].name; i++) if (!strcmp(buf, buildins[i].name)) return (*buildins[i].func)(scan); if (!searchpath(buf, cmd)) { printf("%s: not found\n", buf); return -1; } strcpy(line+1, scan); line[0]=strlen(scan); for (i=0; i 'sysdos.c' /* sysdos.c -- DOS version of system.c */ /* Author: * Guntram Blohm * Buchenstrasse 19 * 7904 Erbach, West Germany * Tel. ++49-7305-6997 * sorry - no regular network connection */ /* This file is derived from Steve Kirkendall's system.c. * * Entry points are: * system(cmd) - run a single shell command * wildcard(names) - expand wildcard characters in filanames * * This file is for use with DOS and TOS. For OS/2, slight modifications * might be sufficient. For UNIX, use system.c. For Amiga, completely * rewrite this stuff. * * Another system function, filter, is the same on DOS and UNIX and thus * can be found in the original system.c. */ #include "config.h" #include "vi.h" extern char **environ; #if MSDOS #include extern unsigned char _osmajor; #endif #if TOS #include #endif #if MSDOS || TOS #include /* * Calling command is a bit nasty because of the undocumented yet sometimes * used feature to change the option char to something else than /. * Versions 2.x and 3.x support this, 4.x doesn't. * * For Atari, some shells define a shortcut entry which is faster than * shell -c. Also, Mark Williams uses a special ARGV environment variable * to pass more than 128 chars to a called command. * We try to support all of these features here. */ int system(cmd) const char *cmd; { #if MSDOS char *cmdswitch="/c"; if (_osmajor<4) cmdswitch[0]=switchar(); return spawnle(P_WAIT, o_shell, o_shell, cmdswitch, cmd, (char *)0, environ); #else long ssp; int (*shell)(); char line[130]; char env[4096], *ep=env; int i; /* does our shell have a shortcut, that we can use? */ ssp = Super(0L); shell = *((int (**)())0x4F6); Super(ssp); if (shell) return (*shell)(cmd); /* else we'll have to call a shell ... */ for (i=0; environ[i] && strncmp(environ[i], "ARGV=", 5); i++) { strcpy(ep, environ[i]); ep+=strlen(ep)+1; } if (environ[i]) { strcpy(ep, environ[i]); ep+=strlen(ep)+1; strcpy(ep, o_shell); ep+=strlen(ep)+1; strcpy(ep, "-c"); ep+=3; strcpy(ep, cmd); ep+=strlen(ep)+1; } *ep='\0'; strcpy(line+1, "-c "); strncat(line+1, cmd, 126); line[0]=strlen(line+1); return Pexec(0, o_shell, line, env); #endif } /* This private function opens a pipe from a filter. It is similar to the * system() function above, and to popen(cmd, "r"). * sorry - i cant use cmdstate until rpclose, but get it from spawnle. */ static int cmdstate; static char output[80]; int rpipe(cmd, in) char *cmd; /* the filter command to use */ int in; /* the fd to use for stdin */ { int fd, old0, old1, old2; /* create the file that will collect the filter's output */ strcpy(output, o_directory); if ((fd=strlen(output)) && !strchr("/\\:", output[fd-1])) output[fd++]=SLASH; strcpy(output+fd, SCRATCHIN+3); mktemp(output); close(creat(output, 0666)); if ((fd=open(output, O_RDWR))==-1) { unlink(output); return -1; } /* save and redirect stdin, stdout, and stderr */ old0=dup(0); old1=dup(1); if (in) { dup2(in, 0); close(in); } dup2(fd, 1); /* call command */ cmdstate=system(cmd); /* restore old std... */ dup2(old0, 0); close(old0); dup2(old1, 1); close(old1); /* rewind command output */ lseek(fd, 0L, 0); return fd; } /* This function closes the pipe opened by rpipe(), and returns 0 for success */ int rpclose(fd) int fd; { int status; close(fd); unlink(output); return cmdstate; } #endif SHAR_EOF fi # end of overwriting check if test -f 'system.c' then echo shar: will not over-write existing file "'system.c'" else cat << \SHAR_EOF > 'system.c' /* system.c -- UNIX version */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains a new version of the system() function and related stuff. * * Entry points are: * system(cmd) - run a single shell command * wildcard(names) - expand wildcard characters in filanames * filter(m,n,cmd) - run text lines through a filter program * * This is probably the single least portable file in the program. The code * shown here should work correctly if it links at all; it will work on UNIX * and any O.S./Compiler combination which adheres to UNIX forking conventions. */ #include "config.h" #include "vi.h" #include extern char **environ; #if ANY_UNIX /* This is a new version of the system() function. The only difference * between this one and the library one is: this one uses the o_shell option. */ int system(cmd) char *cmd; /* a command to run */ { int status; /* exit status of the command */ /* warn the user if the file hasn't been saved yet */ if (*o_warn && tstflag(file, MODIFIED)) { if (mode == MODE_VI) { mode = MODE_COLON; } msg("Warning: \"%s\" has been modified but not yet saved", origname); } signal(SIGINT, SIG_IGN); switch (fork()) { case -1: /* error */ msg("fork() failed"); status = -1; break; case 0: /* child */ /* for the child, close all files except stdin/out/err */ for (status = 3; status < 60 && (close(status), errno != EINVAL); status++) { } signal(SIGINT, SIG_DFL); if (cmd == o_shell) { execle(o_shell, o_shell, (char *)0, environ); } else { execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); } msg("execle(\"%s\", ...) failed", o_shell); exit(1); /* if we get here, the exec failed */ default: /* parent */ wait(&status); signal(SIGINT, trapint); } return status; } /* This private function opens a pipe from a filter. It is similar to the * system() function above, and to popen(cmd, "r"). */ static int rpipe(cmd, in) char *cmd; /* the filter command to use */ int in; /* the fd to use for stdin */ { int r0w1[2];/* the pipe fd's */ /* make the pipe */ if (pipe(r0w1) < 0) { return -1; /* pipe failed */ } /* The parent process (elvis) ignores signals while the filter runs. * The child (the filter program) will reset this, so that it can * catch the signal. */ signal(SIGINT, SIG_IGN); switch (fork()) { case -1: /* error */ return -1; case 0: /* child */ /* close the "read" end of the pipe */ close(r0w1[0]); /* redirect stdout to go to the "write" end of the pipe */ close(1); dup(r0w1[1]); close(2); dup(r0w1[1]); close(r0w1[1]); /* redirect stdin */ if (in != 0) { close(0); dup(in); close(in); } /* the filter should accept SIGINT signals */ signal(SIGINT, SIG_DFL); /* exec the shell to run the command */ execle(o_shell, o_shell, "-c", cmd, (char *)0, environ); exit(1); /* if we get here, exec failed */ default: /* parent */ /* close the "write" end of the pipe */ close(r0w1[1]); return r0w1[0]; } } #endif /* non-DOS */ #if OSK /* This private function opens a pipe from a filter. It is similar to the * system() function above, and to popen(cmd, "r"). */ static int rpipe(cmd, in) char *cmd; /* the filter command to use */ int in; /* the fd to use for stdin */ { char **argblk; char *p, *buffer, *command; int stdinp, stdoutp; unsigned addstack = 0; int words, len, loop = 1; int fp, pipe_pid; extern int os9forkc(); extern char *index(); command = cmd; words = 0; if ((buffer = (char*) malloc(strlen(cmd))) == (char*) 0) return 0; do { if (!(p = index(command, ' '))) { loop--; len = strlen(command); } else len = p - command; words++; while (command[len] && command[len] == ' ') len++; if (!command[len]) break; command = command + len; } while (loop); if ((argblk = (char **)malloc((words+1) * sizeof(char*))) == (char **)0) return 0; command = cmd; words = 0; do { if (!(p = index(command, ' '))) { loop--; len = strlen(command); } else len = p - command; strncpy(buffer, command, len); argblk[words++] = buffer; buffer += len; *buffer++ = '\0'; while (command[len] && command[len] == ' ') len++; if (!command[len]) break; command = command + len; } while (loop); if (argblk[words - 1][0] == '#') addstack = 1024 * atoi(&argblk[--words][1]); argblk[words] = 0; stdoutp = dup(1); close(1); /* close stdout */ if ((fp = open("/pipe",S_IREAD)) < 0) { dup(stdoutp); close(stdoutp); return 0; } if (in != 0) { stdinp = dup(0); close(0); dup(in); close(in); } pipe_pid = os9exec(os9forkc,argblk[0],argblk,environ,addstack,0,3); if (pipe_pid == -1) { fclose(fp); dup(stdoutp); close(stdoutp); if (in != 0) { close(0); dup(stdinp); } return 0; } fp = (short)dup(1); /* save pipe */ close(1); /* get rid of the pipe */ dup(stdoutp); /* restore old stdout */ close(stdoutp); /* close path to stdout copy */ if (in != 0) { close(0); dup(stdinp); } return fp; } #endif #if ANY_UNIX || OSK /* This function closes the pipe opened by rpipe(), and returns 0 for success */ static int rpclose(fd) int fd; { int status; close(fd); wait(&status); signal(SIGINT, trapint); return status; } #endif /* non-DOS */ /* This function expands wildcards in a filename or filenames. It does this * by running the "echo" command on the filenames via the shell; it is assumed * that the shell will expand the names for you. If for any reason it can't * run echo, then it returns the names unmodified. */ #if MSDOS || TOS #define PROG "wildcard " #define PROGLEN 9 #include #else #define PROG "echo " #define PROGLEN 5 #endif char *wildcard(names) char *names; { int i, j, fd; REG char *s, *d; /* build the echo command */ if (names != tmpblk.c) { /* the names aren't in tmpblk.c, so we can do it the easy way */ strcpy(tmpblk.c, PROG); strcat(tmpblk.c, names); } else { /* the names are already in tmpblk.c, so shift them to make * room for the word "echo " */ for (s = names + strlen(names) + 1, d = s + PROGLEN; s > names; ) { *--d = *--s; } strncpy(names, PROG, PROGLEN); } /* run the command & read the resulting names */ fd = rpipe(tmpblk.c, 0); if (fd < 0) return names; i = 0; do { j = tread(fd, tmpblk.c + i, BLKSIZE - i); i += j; } while (j > 0); /* successful? */ if (rpclose(fd) == 0 && j == 0 && i < BLKSIZE && i > 0) { tmpblk.c[i-1] = '\0'; /* "i-1" so we clip off the newline */ return tmpblk.c; } else { return names; } } /* This function runs a range of lines through a filter program, and replaces * the original text with the filtered version. As a special case, if "to" * is MARK_UNSET, then it runs the filter program with stdin coming from * /dev/null, and inserts any output lines. */ int filter(from, to, cmd) MARK from, to; /* the range of lines to filter */ char *cmd; /* the filter command */ { int scratch; /* fd of the scratch file */ int fd; /* fd of the pipe from the filter */ char scrout[50]; /* name of the scratch out file */ MARK new; /* place where new text should go */ int i; /* write the lines (if specified) to a temp file */ if (to) { /* we have lines */ #if MSDOS || TOS strcpy(scrout, o_directory); if ((i=strlen(scrout)) && strchr("\\/:", scrout[i-1])) scrout[i++]=SLASH; strcpy(scrout+i, SCRATCHOUT+3); #else sprintf(scrout, SCRATCHOUT, o_directory); #endif mktemp(scrout); cmd_write(from, to, CMD_BANG, 0, scrout); /* use those lines as stdin */ scratch = open(scrout, O_RDONLY); if (scratch < 0) { unlink(scrout); return -1; } } else { scratch = 0; } /* start the filter program */ fd = rpipe(cmd, scratch); if (fd < 0) { if (to) { close(scratch); unlink(scrout); } return -1; } ChangeText { /* adjust MARKs for whole lines, and set "new" */ from &= ~(BLKSIZE - 1); if (to) { to &= ~(BLKSIZE - 1); to += BLKSIZE; new = to; } else { new = from + BLKSIZE; } /* repeatedly read in new text and add it */ while ((i = tread(fd, tmpblk.c, BLKSIZE - 1)) > 0) { tmpblk.c[i] = '\0'; add(new, tmpblk.c); for (i = 0; tmpblk.c[i]; i++) { if (tmpblk.c[i] == '\n') { new = (new & ~(BLKSIZE - 1)) + BLKSIZE; } else { new++; } } } } /* delete old text, if any */ if (to) { delete(from, to); } /* Reporting... */ rptlabel = "more"; if (rptlines < 0) { rptlines = -rptlines; rptlabel = "less"; } /* cleanup */ rpclose(fd); if (to) { close(scratch); unlink(scrout); } return 0; } SHAR_EOF fi # end of overwriting check if test -f 'tinytcap.c' then echo shar: will not over-write existing file "'tinytcap.c'" else cat << \SHAR_EOF > 'tinytcap.c' /* tinytcap.c */ /* This file contains functions which simulate the termcap functions, but which * can only describe the capabilities of the ANSI.SYS and NANSI.SYS drivers on * an MS-DOS system or the VT-52 emulator of an Atari-ST. These functions * do *NOT* access a "termcap" database file. */ #include "config.h" #if MSDOS || TOS || MINIX || COHERENT #define CAP(str) CAP2((str)[0], (str)[1]) #define CAP2(a,b) (((a) << 8) + ((b) & 0xff)) #if MSDOS # define VAL2(v,a) (a) # define VAL3(v,a,n) (nansi ? (n) : (a)) static int nansi; #endif #if TOS # define VAL2(v,a) (v) # define VAL3(v,a,n) (v) #endif #if MINIX || COHERENT # define VAL2(v,a) (a) # define VAL3(v,a,n) (n) #endif /*ARGSUSED*/ int tgetent(bp, name) char *bp; /* buffer for storing the entry -- ignored */ char *name; /* name of the entry */ { #if MSDOS nansi = strcmp(name, "ansi"); #endif return 1; } int tgetnum(id) char *id; { switch (CAP(id)) { case CAP2('l','i'): return 25; case CAP2('c','o'): return 80; case CAP2('s','g'): return 0; case CAP2('u','g'): return 0; default: return -1; } } int tgetflag(id) char *id; { switch (CAP(id)) { #if !MINIX || COHERENT case CAP2('a','m'): return 1; #endif case CAP2('b','s'): return 1; case CAP2('m','i'): return 1; default: return 0; } } /*ARGSUSED*/ char *tgetstr(id, bp) char *id; char **bp; /* pointer to pointer to buffer - ignored */ { switch (CAP(id)) { case CAP2('c','e'): return VAL2("\033K", "\033[K"); case CAP2('c','l'): return VAL2("\033E", "\033[2J"); case CAP2('a','l'): return VAL3("\033L", (char *)0, "\033[L"); case CAP2('d','l'): return VAL3("\033M", (char *)0, "\033[M"); case CAP2('c','m'): return VAL2("\033Y%i%+ %+ ", "\033[%i%d;%dH"); case CAP2('d','o'): return VAL2("\033B", "\033[B"); case CAP2('n','d'): return VAL2("\033C", "\033[C"); case CAP2('u','p'): return VAL2("\033A", "\033[A"); case CAP2('t','i'): return VAL2("\033e", ""); case CAP2('t','e'): return VAL2("", ""); case CAP2('s','o'): return VAL2("\033p", "\033[7m"); case CAP2('s','e'): return VAL2("\033q", "\033[m"); case CAP2('u','s'): return VAL2((char *)0, "\033[4m"); case CAP2('u','e'): return VAL2((char *)0, "\033[m"); case CAP2('m','d'): return VAL2((char *)0, "\033[1m"); case CAP2('m','e'): return VAL2((char *)0, "\033[m"); #if MINIX || COHERENT case CAP2('k','u'): return "\033[A"; case CAP2('k','d'): return "\033[B"; case CAP2('k','l'): return "\033[D"; case CAP2('k','r'): return "\033[C"; case CAP2('k','P'): return "\033[V"; case CAP2('k','N'): return "\033[U"; case CAP2('k','h'): return "\033[H"; # if MINIX case CAP2('k','H'): return "\033[Y"; # else /* COHERENT */ case CAP2('k','H'): return "\033[24H"; # endif #else /* MS-DOS or TOS */ case CAP2('k','u'): return "#H"; case CAP2('k','d'): return "#P"; case CAP2('k','l'): return "#K"; case CAP2('k','r'): return "#M"; case CAP2('k','h'): return "#G"; case CAP2('k','H'): return "#O"; case CAP2('k','P'): return "#I"; case CAP2('k','N'): return "#Q"; #endif default: return (char *)0; } } /*ARGSUSED*/ char *tgoto(cm, destcol, destrow) char *cm; /* cursor movement string -- ignored */ int destcol;/* destination column, 0 - 79 */ int destrow;/* destination row, 0 - 24 */ { static char buf[30]; #if MSDOS || MINIX || COHERENT sprintf(buf, "\033[%d;%dH", destrow + 1, destcol + 1); #endif #if TOS sprintf(buf, "\033Y%c%c", ' ' + destrow, ' ' + destcol); #endif return buf; } /*ARGSUSED*/ void tputs(cp, affcnt, outfn) char *cp; /* the string to output */ int affcnt; /* number of affected lines -- ignored */ int (*outfn)(); /* the output function */ { while (*cp) { (*outfn)(*cp); cp++; } } #endif SHAR_EOF fi # end of overwriting check if test -f 'tio.c' then echo shar: will not over-write existing file "'tio.c'" else cat << \SHAR_EOF > 'tio.c' /* tio.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains terminal I/O functions */ #include "config.h" #if BSD || COHERENT # include #endif #include #include "vi.h" /* This function reads in a line from the terminal. */ int vgets(prompt, buf, bsize) char prompt; /* the prompt character, or '\0' for none */ char *buf; /* buffer into which the string is read */ int bsize; /* size of the buffer */ { int len; /* how much we've read so far */ int ch; /* a character from the user */ int quoted; /* is the next char quoted? */ int tab; /* column position of cursor */ char widths[132]; /* widths of characters */ #ifndef NO_DIGRAPH int erased; /* 0, or first char of a digraph */ #endif /* show the prompt */ move(LINES - 1, 0); tab = 0; if (prompt) { addch(prompt); tab = 1; } clrtoeol(); refresh(); /* read in the line */ #ifndef NO_DIGRAPH erased = #endif quoted = len = 0; for (;;) { ch = getkey(quoted ? 0 : WHEN_EX); /* some special conversions */ if (ch == ctrl('D') && len == 0) ch = ctrl('['); #ifndef NO_DIGRAPH if (*o_digraph && erased != 0 && ch != '\b') { ch = digraph(erased, ch); erased = 0; } #endif /* inhibit detection of special chars (except ^J) after a ^V */ if (quoted && ch != '\n') { ch |= 256; } /* process the character */ switch(ch) { case ctrl('V'): qaddch('^'); qaddstr("BC"); quoted = TRUE; break; case ctrl('['): return -1; case '\n': #if OSK case '\l': #else case '\r': #endif clrtoeol(); goto BreakBreak; case '\b': if (len > 0) { int b; len--; #ifndef NO_DIGRAPH erased = buf[len]; #endif for (b = 8 - widths[len]; b < 8; b++) { qaddstr(BC); } if (mode == MODE_EX) { clrtoeol(); } tab -= widths[len]; } else { return -1; } break; default: /* strip off quotation bit */ if (ch & 256) { ch &= ~256; quoted = FALSE; qaddch(' '); qaddstr(BC); } /* add & echo the char */ if (len < bsize - 1) { if (ch == '\t') { widths[len] = *o_tabstop - (tab % *o_tabstop); addstr(" " + 8 - widths[len]); tab += widths[len]; } else if (ch > 0 && ch < ' ') /* > 0 by GB */ { addch('^'); addch(ch + '@'); widths[len] = 2; tab += 2; } else if (ch == '\177') { addch('^'); addch('?'); widths[len] = 2; tab += 2; } else { addch(ch); widths[len] = 1; tab++; } buf[len++] = ch; } else { Beep(); } } } BreakBreak: refresh(); buf[len] = '\0'; return len; } /* ring the terminal's bell */ void beep() { if (*o_vbell) { do_VB(); refresh(); } else if (*o_errorbells) { ttywrite("\007", 1); } } static int manymsgs; /* This variable keeps msgs from overwriting each other */ static char pmsg[80]; /* previous message (waiting to be displayed) */ /*- The Appendmsg() and Rendermsg() macros exist to isolate the mechanics behind displaying something on the msg line. this is to accomodate window versions of elvis which may display the message line somewhere other than the main editing window. appendmsg() and rendermsg() are the simple tty based versions of Rendermsg() and Appendmsg(). See wconfig.h for what Rendermsg and Appendmsg are defined as. Note that they must stay non-static this is so window versions can use them if they must fall back on using the tty they were started from - MCH */ int appendmsg(orig, new) char *orig, *new; { # ifdef lint orig = orig; /* orig param unused by tty version */ # endif qaddstr(new); refresh(); return 0; } int rendermsg(msgtxt) char *msgtxt; { move(LINES - 1, 0); if (*msgtxt) { standout(); qaddch(' '); qaddstr(msgtxt); qaddch(' '); standend(); } clrtoeol(); return 0; } static int showmsg() { /* if there is no message to show, then don't */ if (!manymsgs) return FALSE; Rendermsg(pmsg); /* does the actual rendering */ manymsgs = FALSE; return TRUE; } void endmsgs() { if (manymsgs) { showmsg(); addch('\n'); } } /* Write a message in an appropriate way. This should really be a varargs * function, but there is no such thing as vwprintw. Hack!!! * * In MODE_EX or MODE_COLON, the message is written immediately, with a * newline at the end. * * In MODE_VI, the message is stored in a character buffer. It is not * displayed until getkey() is called. msg() will call getkey() itself, * if necessary, to prevent messages from being lost. * * msg("") - clears the message line * msg("%s %d", ...) - does a printf onto the message line */ #ifdef NO_VSPRINTF /* use this *only* if you do not have vsprintf this is dangerous on things like a sparc chip - MCH */ /*VARARGS1*/ void msg(fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) char *fmt; long arg1, arg2, arg3, arg4, arg5, arg6, arg7; { if (mode != MODE_VI) { sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7); qaddstr(pmsg); addch('\n'); exrefresh(); } else { /* wait for keypress between consecutive msgs */ if (manymsgs) { getkey(WHEN_MSG); } /* real message */ sprintf(pmsg, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7); manymsgs = TRUE; } } #else #include void msg(va_alist) va_dcl { char *fmt; va_list args; va_start(args); fmt = va_arg(args, char *); if (mode != MODE_VI) { vsprintf(pmsg, fmt, args); qaddstr(pmsg); addch('\n'); exrefresh(); } else { /* wait for keypress between consecutive msgs */ if (manymsgs) { getkey(WHEN_MSG); } /* real message */ vsprintf(pmsg, fmt, args); manymsgs = TRUE; } va_end(args); return; } #endif /* This function calls refresh() if the option exrefresh is set */ void exrefresh() { char *scan; /* If this ex command wrote ANYTHING set exwrote so vi's : command * can tell that it must wait for a user keystroke before redrawing. */ for (scan=kbuf; scan 0 && keybuf[atnext]) { msg("Can't nest @ commands"); return FALSE; } /* use the empty portion of keybuf[] to get chars from the cut buffer */ len = cb2str(cbname, keybuf + nkeys, sizeof keybuf - nkeys); if (len < 0) { msg("Invalid cut buffer name. Must be a-z"); return FALSE; } if (len == 0) { msg("Cut buffer \"%c is empty", cbname); return FALSE; } else if (len >= sizeof keybuf - nkeys) { msg("Cut buffer \"%c is too large to execute", cbname); return FALSE; } /* prepare to "read" those keys on subsequent getkey() calls */ atnext = nkeys; return TRUE; } #endif /* This array describes mapped key sequences */ static struct _keymap { char *name; /* name of the key, or NULL */ char rawin[LONGKEY]; /* the unmapped version of input */ char cooked[80]; /* the mapped version of input */ int len; /* length of the unmapped version */ int when; /* when is this key mapped? */ } mapped[MAXMAPS]; #if !MSDOS && !TOS # if BSD || COHERENT static jmp_buf env_timeout; static int dummy() { longjmp(env_timeout, 1); return 0; } # else static int dummy() { } # endif #endif /* This function reads in a keystroke for VI mode. It automatically handles * key mapping. */ int getkey(when) int when; /* which bits must be ON? */ { static char *cooked; /* rawin, or pointer to converted key */ static int oldwhen; /* "when" from last time */ static int oldleft; static long oldtop; static long oldnlines; static char *cshape; /* current cursor shape */ REG char *kptr; /* &keybuf[next] */ REG struct _keymap *km; /* used to count through keymap */ REG int i, j, k; #ifdef DEBUG watch(); #endif /* if this key is needed for delay between multiple error messages, * then reset the manymsgs flag and abort any mapped key sequence. */ if (showmsg()) { if (when == WHEN_MSG) { Appendmsg(pmsg, "[More...]"); cooked = (char *)0; } else if (when == WHEN_VIINP || when == WHEN_VIREP) { redraw(cursor, TRUE); } } #ifndef NO_AT /* if we're in the middle of a visual @ macro, take atnext */ if (atnext > 0) { if (keybuf[atnext]) { return keybuf[atnext++]; } atnext = 0; } #endif /* if we're doing a mapped key, get the next char */ if (cooked && *cooked) { return *cooked++; } /* if keybuf is empty, fill it */ if (next == nkeys) { #ifndef NO_CURSORSHAPE /* make sure the cursor is the right shape */ if (has_CQ) { cooked = cshape; switch (when) { case WHEN_EX: cooked = CX; break; case WHEN_VICMD: cooked = CV; break; case WHEN_VIINP: cooked = CI; break; case WHEN_VIREP: cooked = CR; break; } if (cooked != cshape) { cshape = cooked; switch (when) { case WHEN_EX: do_CX(); break; case WHEN_VICMD: do_CV(); break; case WHEN_VIINP: do_CI(); break; case WHEN_VIREP: do_CR(); break; } } cooked = (char *)0; } #endif #ifndef NO_SHOWMODE /* if "showmode" then say which mode we're in */ if (*o_smd && mode == MODE_VI && (when != oldwhen || topline != oldtop || leftcol != oldleft || nlines != oldnlines)) { oldwhen = when; oldtop = topline; oldleft = leftcol; oldnlines = nlines; if (when & WHEN_VICMD) { redraw(cursor, FALSE); move(LINES - 1, COLS - 10); standout(); addstr("Command"); standend(); redraw(cursor, FALSE); } else if (when & WHEN_VIINP) { redraw(cursor, TRUE); move(LINES - 1, COLS - 10); standout(); addstr(" Input "); standend(); redraw(cursor, TRUE); } else if (when & WHEN_VIREP) { redraw(cursor, TRUE); move(LINES - 1, COLS - 10); standout(); addstr("Replace"); standend(); redraw(cursor, TRUE); } } else #endif /* redraw if getting a VI command */ if (when & WHEN_VICMD) { redraw(cursor, FALSE); } /* read the rawin keystrokes */ refresh(); while ((nkeys = ttyread(keybuf, sizeof keybuf)) < 0) { /* terminal was probably resized */ *o_lines = LINES; *o_columns = COLS; if (when & (WHEN_VICMD|WHEN_VIINP|WHEN_VIREP)) { redraw(MARK_UNSET, FALSE); redraw(cursor, (when & WHEN_VICMD) == 0); refresh(); } } next = 0; /* if nkeys == 0 then we've reached EOF of an ex script. */ if (nkeys == 0) { tmpabort(TRUE); move(LINES - 1, 0); clrtoeol(); refresh(); endwin(); exit(1); } } /* see how many mapped keys this might be */ kptr = &keybuf[next]; for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++) { if ((km->when & when) && km->len > 0 && *km->rawin == *kptr) { if (km->len > nkeys - next) { if (!strncmp(km->rawin, kptr, nkeys - next)) { j++; } } else { if (!strncmp(km->rawin, kptr, km->len)) { j++; k = i; } } } } /* if more than one, try to read some more */ while (j > 1) { #if BSD || COHERENT if (setjmp(env_timeout)) { /* we timed out - assume no mapping */ j = 0; break; } #endif #if ANY_UNIX signal(SIGALRM, dummy); #endif #if OSK signal(SIGQUIT, dummy); #endif alarm((unsigned)*o_keytime); i = nkeys; if ((k = ttyread(keybuf + nkeys, sizeof keybuf - nkeys)) >= 0) { nkeys += k; } alarm(0); #if OSK # ifndef DEBUG signal(SIGQUIT, SIG_IGN); # endif #endif /* if we couldn't read any more, pretend 0 mapped keys */ if (i == nkeys) { j = 0; } else /* else we got some more - try again */ { for (i = j = 0, k = -1, km = mapped; i < MAXMAPS; i++, km++) { if ((km->when & when) && km->len > 0 && *km->rawin == *kptr) { if (km->len > nkeys - next) { if (!strncmp(km->rawin, kptr, nkeys - next)) { j++; } } else { if (!strncmp(km->rawin, kptr, km->len)) { j++; k = i; } } } } } } /* if unambiguously mapped key, use it! */ if (j == 1 && k >= 0) { next += mapped[k].len; cooked = mapped[k].cooked; #ifndef NO_EXTENSIONS if ((when & (WHEN_VIINP|WHEN_VIREP)) && (mapped[k].when & WHEN_INMV)) { return 0; /* special case, means "a movement char follows" */ } else #endif { return *cooked++; } } else /* assume key is unmapped, but still translate weird erase key to '\b' */ if (keybuf[next] == ERASEKEY && when != 0) { next++; return '\b'; } else if (keybuf[next] == '\0') { next++; return ('A' & 0x1f); } else { return keybuf[next++]; } } /* This function maps or unmaps a key */ void mapkey(rawin, cooked, when, name) char *rawin; /* the input key sequence, before mapping */ char *cooked;/* after mapping */ short when; /* bitmap of when mapping should happen */ char *name; /* name of the key, if any */ { int i, j; #ifndef NO_EXTENSIONS /* if the mapped version starts with the word "visual" then set WHEN_INMV */ if (!strncmp(cooked, "visual ", 7)) { when |= WHEN_INMV; cooked += 7; } /* if WHEN_INMV is set, then WHEN_VIINP and WHEN_VIREP must be set */ if (when & WHEN_INMV) { when |= (WHEN_VIINP | WHEN_VIREP); } #endif /* see if the key sequence was mapped before */ j = strlen(rawin); for (i = 0; i < MAXMAPS; i++) { if (mapped[i].len == j && !strncmp(mapped[i].rawin, rawin, j) && (mapped[i].when & when)) { break; } } /* if not already mapped, then try to find a new slot to use */ if (i == MAXMAPS) { for (i = 0; i < MAXMAPS && mapped[i].len > 0; i++) { } } /* no room for the new key? */ if (i == MAXMAPS) { msg("No room left in the key map table"); return; } /* map the key */ if (cooked && *cooked) { /* Map the key */ mapped[i].len = j; strncpy(mapped[i].rawin, rawin, j); strcpy(mapped[i].cooked, cooked); mapped[i].when = when; mapped[i].name = name; } else /* unmap the key */ { mapped[i].len = 0; } } /* Dump keys of a given type - WHEN_VICMD dumps the ":map" keys, and * WHEN_VIINP|WHEN_VIREP dumps the ":map!" keys */ void dumpkey(when) int when; /* WHEN_XXXX of mappings to be dumped */ { int i, len, mlen; char *scan; char *mraw; for (i = 0; i < MAXMAPS; i++) { /* skip unused entries, or entries that don't match "when" */ if (mapped[i].len <= 0 || !(mapped[i].when & when)) { continue; } /* dump the key label, if any */ len = 8; if (mapped[i].name) { qaddstr(mapped[i].name); len -= strlen(mapped[i].name); } do { qaddch(' '); } while (len-- > 0); /* dump the raw version */ len = 0; mlen = mapped[i].len; mraw = mapped[i].rawin; for (scan = mraw; scan < mraw + mlen; scan++) { if (UCHAR(*scan) < ' ' || *scan == '\177') { qaddch('^'); qaddch(*scan ^ '@'); len += 2; } else { qaddch(*scan); len++; } } do { qaddch(' '); } while (++len < 8); /* dump the mapped version */ #ifndef NO_EXTENSIONS if ((mapped[i].when & WHEN_INMV) && (when & (WHEN_VIINP|WHEN_VIREP))) { qaddstr("visual "); } #endif for (scan = mapped[i].cooked; *scan; scan++) { if (UCHAR(*scan) < ' ' || *scan == '\177') { qaddch('^'); qaddch(*scan ^ '@'); } else { qaddch(*scan); } } addch('\n'); exrefresh(); } } #ifndef MKEXRC /* This function saves the current configuration of mapped keys to a file */ void savekeys(fd) int fd; /* file descriptor to save them to */ { int i; char buf[80]; /* now write a map command for each key other than the arrows */ for (i = 0; i < MAXMAPS; i++) { /* ignore keys that came from termcap */ if (mapped[i].name) { continue; } /* If this isn't used, ignore it */ if (mapped[i].len <= 0) { continue; } /* write the map command */ #ifndef NO_EXTENSIONS if (mapped[i].when & WHEN_INMV) { #if OSK char fmt[80]; sprintf(fmt, "map%%s %%.%ds %%s\n", mapped[i].len); sprintf(buf, fmt, (mapped[i].when & WHEN_VICMD) ? "" : "!", #else sprintf(buf, "map%s %.*s visual %s\n", (mapped[i].when & WHEN_VICMD) ? "" : "!", mapped[i].len, #endif mapped[i].rawin, mapped[i].cooked); twrite(fd, buf, strlen(buf)); } else #endif { if (mapped[i].when & WHEN_VICMD) { #if OSK char fmt[80]; sprintf(fmt, "map %%.%ds %%s\n", mapped[i].len); sprintf(buf, fmt, #else sprintf(buf, "map %.*s %s\n", mapped[i].len, #endif mapped[i].rawin, mapped[i].cooked); twrite(fd, buf, strlen(buf)); } if (mapped[i].when & (WHEN_VIINP | WHEN_VIREP)) { #if OSK char fmt[80]; sprintf(fmt, "map! %%.%ds %%s\n", mapped[i].len); sprintf(buf, fmt, #else sprintf(buf, "map! %.*s %s\n", mapped[i].len, #endif mapped[i].rawin, mapped[i].cooked); twrite(fd, buf, strlen(buf)); } } } } #endif SHAR_EOF fi # end of overwriting check if test -f 'tmp.c' then echo shar: will not over-write existing file "'tmp.c'" else cat << \SHAR_EOF > 'tmp.c' /* tmpfile.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains functions which create & readback a TMPFILE */ #include "config.h" #include #include "vi.h" #if TOS # include #else # if OSK # include "osk.h" # else # include # endif #endif #ifndef NO_MODELINE static void do_modeline(l, stop) long l; /* line number to start at */ long stop; /* line number to stop at */ { char *str; /* used to scan through the line */ char *start; /* points to the start of the line */ char buf[80]; /* if modelines are disabled, then do nothing */ if (!*o_modeline) { return; } /* for each line... */ for (l = 1; l <= stop; l++) { /* for each position in the line.. */ for (str = fetchline(l); *str; str++) { /* if it is the start of a modeline command... */ if ((str[0] == 'e' && str[1] == 'x' || str[0] == 'v' && str[1] == 'i') && str[2] == ':') { start = str += 3; /* find the end */ while (*str && *str != ':') { str++; } /* if it is a well-formed modeline, execute it */ if (*str && str - start < sizeof buf) { strncpy(buf, start, (int)(str - start)); buf[str - start] = '\0'; doexcmd(buf); break; } } } } } #endif /* The FAIL() macro prints an error message and then exits. */ #define FAIL(why,arg) mode = MODE_EX; msg(why, arg); endwin(); exit(9) /* This is the name of the temp file */ static char tmpname[MAXTMPNAMELEN]; /* This function creates the temp file and copies the original file into it. * Returns if successful, or stops execution if it fails. */ int tmpstart(filename) char *filename; /* name of the original file */ { int origfd; /* fd used for reading the original file */ struct stat statb; /* stat buffer, used to examine inode */ REG BLK *this; /* pointer to the current block buffer */ REG BLK *next; /* pointer to the next block buffer */ int inbuf; /* number of characters in a buffer */ int nread; /* number of bytes read */ REG int j, k; int i; int sum; /* used for calculating a checksum for this */ char *scan; long nbytes; /* switching to a different file certainly counts as a change */ changes++; redraw(MARK_UNSET, FALSE); /* open the original file for reading */ *origname = '\0'; if (filename && *filename) { strcpy(origname, filename); origfd = open(origname, O_RDONLY); if (origfd < 0 && errno != ENOENT) { msg("Can't open \"%s\"", origname); return Tmpstart(""); } if (origfd >= 0) { if (stat(origname, &statb) < 0) { FAIL("Can't stat \"%s\"", origname); } #if TOS if (origfd >= 0 && (statb.st_mode & S_IJDIR)) #else # if OSK if (origfd >= 0 && (statb.st_mode & S_IFDIR)) # else if (origfd >= 0 && (statb.st_mode & S_IFMT) != S_IFREG) # endif #endif { msg("\"%s\" is not a regular file", origname); return Tmpstart(""); } } else { stat(".", &statb); } if (origfd >= 0) { origtime = statb.st_mtime; #if MSDOS || OSK if (*o_readonly || !(statb.st_mode & S_IWRITE)) #endif #if TOS if (*o_readonly || (statb.st_mode & S_IJRON)) #endif #if ANY_UNIX if (*o_readonly || !(statb.st_mode & (statb.st_uid != geteuid() ? 0022 : 0200))) #endif { setflag(file, READONLY); } } else { origtime = 0L; } } else { setflag(file, NOFILE); origfd = -1; origtime = 0L; stat(".", &statb); } /* generate a checksum from the file's name */ for (sum = 0, scan = origname + strlen(origname); --scan >= origname && (isascii(*scan) && isalnum(*scan) || *scan == '.'); sum = sum + *scan) { } sum &= 0xf; /* make a name for the tmp file */ #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, sum, statb.st_ino, statb.st_dev); #else /* throw the pid into the name so we can edit the same file more * than once MCH */ sprintf(tmpname, TMPNAME, o_directory, sum, statb.st_ino, statb.st_dev, getpid()); #endif /* make sure nobody else is editing the same file */ if (access(tmpname, 0) == 0) { if (*origname) { msg("\"%s\" is busy", filename); return Tmpstart(""); } FAIL("\"%s\" is busy", filename); } /* create the temp file */ #if ANY_UNIX close(creat(tmpname, 0600)); /* only we can read it */ #else close(creat(tmpname, FILEPERMS)); /* anybody body can read it, alas */ #endif tmpfd = open(tmpname, O_RDWR | O_BINARY); if (tmpfd < 0) { FAIL("Can't create temporary file, errno=%d", errno); return 1; } /* allocate space for the header in the file */ write(tmpfd, hdr.c, (unsigned)BLKSIZE); #ifndef NO_RECYCLE /* initialize the block allocator */ /* This must already be done here, before the first attempt * to write to the new file! GB */ garbage(); #endif /* initialize lnum[] */ for (i = 1; i < MAXBLKS; i++) { lnum[i] = INFINITY; } lnum[0] = 0; /* if there is no original file, then create a 1-line file */ if (origfd < 0) { hdr.n[0] = 0; /* invalid inode# denotes new file */ this = blkget(1); /* get the new text block */ strcpy(this->c, "\n"); /* put a line in it */ lnum[1] = 1L; /* block 1 ends with line 1 */ nlines = 1L; /* there is 1 line in the file */ nbytes = 1L; if (*origname) { msg("\"%s\" [NEW FILE] 1 line, 1 char", origname); } else { msg("\"[NO FILE]\" 1 line, 1 char"); } } else /* there is an original file -- read it in */ { hdr.n[0] = statb.st_ino; nbytes = nlines = 0; /* preallocate 1 "next" buffer */ i = 1; next = blkget(i); inbuf = 0; /* loop, moving blocks from orig to tmp */ for (;;) { /* "next" buffer becomes "this" buffer */ this = next; /* read [more] text into this block */ nread = tread(origfd, &this->c[inbuf], BLKSIZE - 1 - inbuf); if (nread < 0) { close(origfd); close(tmpfd); tmpfd = -1; unlink(tmpname); FAIL("Error reading \"%s\"", origname); } /* convert NUL characters to something else */ for (k = inbuf; k < inbuf + nread; k++) { if (!this->c[k]) { setflag(file, HADNUL); this->c[k] = 0x80; } } inbuf += nread; /* if the buffer is empty, quit */ if (inbuf == 0) { goto FoundEOF; } #if MSDOS || TOS /* BAH! MS text mode read fills inbuf, then compresses eliminating \r but leaving garbage at end of buf. The same is true for TURBOC. GB. */ memset(this->c + inbuf, '\0', BLKSIZE - inbuf); #endif /* search backward for last newline */ for (k = inbuf; --k >= 0 && this->c[k] != '\n';) { } if (k++ < 0) { if (inbuf >= BLKSIZE - 1) { k = 80; } else { k = inbuf; } } /* allocate next buffer */ next = blkget(++i); /* move fragmentary last line to next buffer */ inbuf -= k; for (j = 0; k < BLKSIZE; j++, k++) { next->c[j] = this->c[k]; this->c[k] = 0; } /* if necessary, add a newline to this buf */ for (k = BLKSIZE - inbuf; --k >= 0 && !this->c[k]; ) { } if (this->c[k] != '\n') { setflag(file, ADDEDNL); this->c[k + 1] = '\n'; } /* count the lines in this block */ for (k = 0; k < BLKSIZE && this->c[k]; k++) { if (this->c[k] == '\n') { nlines++; } nbytes++; } lnum[i - 1] = nlines; } FoundEOF: /* if this is a zero-length file, add 1 line */ if (nlines == 0) { this = blkget(1); /* get the new text block */ strcpy(this->c, "\n"); /* put a line in it */ lnum[1] = 1; /* block 1 ends with line 1 */ nlines = 1; /* there is 1 line in the file */ nbytes = 1; } #if MSDOS || TOS /* each line has an extra CR that we didn't count yet */ nbytes += nlines; #endif /* report the number of lines in the file */ msg("\"%s\" %s %ld line%s, %ld char%s", origname, (tstflag(file, READONLY) ? "[READONLY]" : ""), nlines, nlines == 1 ? "" : "s", nbytes, nbytes == 1 ? "" : "s"); } /* initialize the cursor to start of line 1 */ cursor = MARK_FIRST; /* close the original file */ close(origfd); /* any other messages? */ if (tstflag(file, HADNUL)) { msg("This file contained NULs. They've been changed to \\x80 chars"); } if (tstflag(file, ADDEDNL)) { msg("Newline characters have been inserted to break up long lines"); } #ifndef NO_MODELINE if (nlines > 10) { do_modeline(1L, 5L); do_modeline(nlines - 4L, nlines); } else { do_modeline(1L, nlines); } #endif return 0; } /* This function copies the temp file back onto an original file. * Returns TRUE if successful, or FALSE if the file could NOT be saved. */ int tmpsave(filename, bang) char *filename; /* the name to save it to */ int bang; /* forced write? */ { int fd; /* fd of the file we're writing to */ REG int len; /* length of a text block */ REG BLK *this; /* a text block */ long bytes; /* byte counter */ REG int i; /* if no filename is given, assume the original file name */ if (!filename || !*filename) { filename = origname; } /* if still no file name, then fail */ if (!*filename) { msg("Don't know a name for this file -- NOT WRITTEN"); return FALSE; } /* can't rewrite a READONLY file */ if (!strcmp(filename, origname) && *o_readonly && !bang) { msg("\"%s\" [READONLY] -- NOT WRITTEN", filename); return FALSE; } /* open the file */ if (*filename == '>' && filename[1] == '>') { filename += 2; while (*filename == ' ' || *filename == '\t') { filename++; } #ifdef O_APPEND fd = open(filename, O_WRONLY|O_APPEND); #else fd = open(filename, O_WRONLY); lseek(fd, 0L, 2); #endif } else { /* either the file must not exist, or it must be the original * file, or we must have a bang */ if (strcmp(filename, origname) && access(filename, 0) == 0 && !bang) { msg("File already exists - Use :w! to overwrite"); return FALSE; } fd = creat(filename, FILEPERMS); } if (fd < 0) { msg("Can't write to \"%s\" -- NOT WRITTEN", filename); return FALSE; } /* write each text block to the file */ bytes = 0L; for (i = 1; i < MAXBLKS && (this = blkget(i)) && this->c[0]; i++) { for (len = 0; len < BLKSIZE && this->c[len]; len++) { } twrite(fd, this->c, len); bytes += len; } /* reset the "modified" flag */ clrflag(file, MODIFIED); significant = FALSE; /* report lines & characters */ #if MSDOS || TOS bytes += nlines; /* for the inserted carriage returns */ #endif if (strncmp(filename, o_directory, strlen(o_directory))) { msg("Wrote \"%s\" %ld lines, %ld characters", filename, nlines, bytes); } /* close the file */ close(fd); return TRUE; } /* This function deletes the temporary file. If the file has been modified * and "bang" is FALSE, then it returns FALSE without doing anything; else * it returns TRUE. * * If the "autowrite" option is set, then instead of returning FALSE when * the file has been modified and "bang" is false, it will call tmpend(). */ int tmpabort(bang) int bang; { /* if there is no file, return successfully */ if (tmpfd < 0) { return TRUE; } /* see if we must return FALSE -- can't quit */ if (!bang && tstflag(file, MODIFIED)) { /* if "autowrite" is set, then act like tmpend() */ if (*o_autowrite) return tmpend(bang); else return FALSE; } /* delete the tmp file */ cutswitch(tmpname); close(tmpfd); tmpfd = -1; unlink(tmpname); strcpy(prevorig, origname); prevline = markline(cursor); *origname = '\0'; origtime = 0L; blkinit(); nlines = 0; initflags(); return TRUE; } /* This function saves the file if it has been modified, and then deletes * the temporary file. Returns TRUE if successful, or FALSE if the file * needs to be saved but can't be. When it returns FALSE, it will not have * deleted the tmp file, either. */ int tmpend(bang) int bang; { /* save the file if it has been modified */ if (tstflag(file, MODIFIED) && !tmpsave((char *)0, FALSE) && !bang) { return FALSE; } /* delete the tmp file */ tmpabort(TRUE); return TRUE; } /* If the tmp file has been changed, then this function will force those * changes to be written to the disk, so that the tmp file will survive a * system crash or power failure. */ #if MSDOS || TOS || OSK sync() { # if OSK /* OS9 doesn't need an explicit sync operation, but the linker * demands something called sync(), so this is a dummy function. */ #else /* MS-DOS and TOS don't flush their buffers until the file is closed, * so here we close the tmp file and then immediately reopen it. */ close(tmpfd); tmpfd = open(tmpname, O_RDWR | O_BINARY); #endif } #endif SHAR_EOF fi # end of overwriting check if test -f 'tnamerec.c' then echo shar: will not over-write existing file "'tnamerec.c'" else cat << \SHAR_EOF > 'tnamerec.c' #include "config.h" # if SUNOS || UNIXV /* systems using X/OPEN type directory routines */ # define USING_DIRENT 1 # define USING_DIRECT 0 # include # endif /* not implemented yet, should be real easy to do though just hack the X/OPEN style version */ # if 0 /* put systems using struct direct here, 4.2 etc.. */ # define USING_DIRENT 0 # define USING_DIRECT 1 # endif # endif #if MSDOS || TOS # define NO_PID_IN_TMP_NAME 1 # define USING_DIRENT 0 # define USING_DIRECT 0 #endif /* int tnamerec(template) * char *template; * ==== * Find the true name of a temp file given a template which has nonsense * in the pid portion (the part after the dash) * This is mainly for use by virec program * ==== * -2 indicates the argument supplied is malformed * -1 indicates tmp file with the supplied template was not found * 0 indicates the argument has been converted properly * >0 indicates an argument has been converted OK but there is more * than one tmp file which matches the template * ==== * As a side effect , template is modified to contain the last filename * that matched template. * ==== * note: this module is highly dependent on TMPNAME #define in config.h */ #ifdef NO_PID_IN_TMPNAME int tnamerec(template) char *template; { return 0; } #endif #if USING_DIRENT || USING_DIRECT int tnamerec(template) char *template; { # if USING_DIRECT {{{{{{{{ to be done # endif # if USING_DIRENT DIR *dirp; struct dirent *entry; # endif extern char *strrchr(); int c; char *p; char *suff; int count = -1; int cmplen; if ( !(p = strrchr(template, '/'))) return -2; if (!(suff = strrchr(p, '-'))) return -2; cmplen = suff - p; c = *p; *p = '\0'; /* temporarily truncate off the filename */ if (!(dirp = opendir(template))) { *p = c; return -1; } *p++ = c; /* put filename back on */ /* scan the directory looking for a file which matches 'template' if the two are the same length and the stuff up to the dash is the same and the suffix is a number it's a match */ # if USING_DIRECT {{{{{to_be_done{{{{ # endif # if USING_DIRENT for (entry = readdir(dirp); entry; entry = readdir(dirp)) { if ( !strncmp(entry->d_name, p, cmplen) && (strlen(p) == strlen(entry->d_name)) ) { char *ext_suff = strchr(entry->d_name, '-'); if (ext_suff && atoi((ext_suff+1)) > 0) { strcpy(p, entry->d_name); count++; } } } return count; # endif } #endif SHAR_EOF fi # end of overwriting check # End of shell archive exit 0