diff options
Diffstat (limited to 'ex_io.c')
-rw-r--r-- | ex_io.c | 1125 |
1 files changed, 1125 insertions, 0 deletions
@@ -0,0 +1,1125 @@ +/* + * This code contains changes by + * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved. + * + * Conditions 1, 2, and 4 and the no-warranty notice below apply + * to these changes. + * + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * Redistributions of source code and documentation must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed or owned by Caldera + * International, Inc. + * Neither the name of Caldera International, Inc. nor the names of + * other contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA + * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE + * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +#ifdef DOSCCS +static char sccsid[] = "@(#)ex_io.c 1.40 (gritter) 2/17/05"; +#endif +#endif + +/* from ex_io.c 7.11.1.1 (Berkeley) 8/12/86 */ + +#include "ex.h" +#include "ex_argv.h" +#include "ex_temp.h" +#include "ex_tty.h" +#include "ex_vis.h" + +/* + * File input/output, source, preserve and recover + */ + +/* + * Following remember where . was in the previous file for return + * on file switching. + */ +int altdot; +int oldadot; +bool wasalt; +short isalt; + +long cntch; /* Count of characters on unit io */ +#ifndef VMUNIX +short cntln; /* Count of lines " */ +#else +int cntln; +#endif +long cntnull; /* Count of nulls " */ +#ifndef BIT8 +long cntodd; /* Count of non-ascii characters " */ +#endif + +/* + * Parse file name for command encoded by comm. + * If comm is E then command is doomed and we are + * parsing just so user won't have to retype the name. + */ +void +filename(int comm) +{ + register int c = comm, d; + register int i; + + d = getchar(); + if (endcmd(d)) { + if (savedfile[0] == 0 && comm != 'f') + error(catgets(catd, 1, 72, + "No file|No current filename")); + CP(file, savedfile); + wasalt = (isalt > 0) ? isalt-1 : 0; + isalt = 0; + oldadot = altdot; + if (c == 'e' || c == 'E') + altdot = lineDOT(); + if (d == EOF) + ungetchar(d); + } else { + ungetchar(d); + getone(); + eol(); + if (savedfile[0] == 0 && c != 'E' && c != 'e') { + c = 'e'; + edited = 0; + } + wasalt = strcmp(file, altfile) == 0; + oldadot = altdot; + switch (c) { + + case 'f': + edited = 0; + /* fall into ... */ + + case 'e': + if (savedfile[0]) { + altdot = lineDOT(); + CP(altfile, savedfile); + } + CP(savedfile, file); + break; + + default: + if (file[0]) { + if (c != 'E') + altdot = lineDOT(); + CP(altfile, file); + } + break; + } + } + if (hush && comm != 'f' || comm == 'E') + return; + if (file[0] != 0) { + lprintf("\"%s\"", file); + if (comm == 'f') { + if (value(READONLY)) + printf(catgets(catd, 1, 73, " [Read only]")); + if (!edited) + printf(catgets(catd, 1, 74, " [Not edited]")); + if (tchng) + printf(catgets(catd, 1, 75, " [Modified]")); + } + flush(); + } else + printf(catgets(catd, 1, 76, "No file ")); + if (comm == 'f') { + if (!(i = lineDOL())) + i++; + printf(catgets(catd, 1, 77, + " line %d of %d --%ld%%--"), lineDOT(), lineDOL(), + (long) 100 * lineDOT() / i); + } +} + +/* + * Get the argument words for a command into genbuf + * expanding # and %. + */ +int +getargs(void) +{ + register int c; + register char *cp, *fp; + static char fpatbuf[32]; /* hence limit on :next +/pat */ + + pastwh(); + if (peekchar() == '+') { + for (cp = fpatbuf;;) { + c = *cp++ = getchar(); + if (cp >= &fpatbuf[sizeof(fpatbuf)]) + error(catgets(catd, 1, 78, "Pattern too long")); + if (c == '\\' && isspace(peekchar())) + c = getchar(); + if (c == EOF || isspace(c)) { + ungetchar(c); + *--cp = 0; + firstpat = &fpatbuf[1]; + break; + } + } + } + if (skipend()) + return (0); + CP(genbuf, "echo "); cp = &genbuf[5]; + for (;;) { + c = getchar(); + if (endcmd(c)) { + ungetchar(c); + break; + } + switch (c) { + + case '\\': + if (any(peekchar(), "#%|")) + c = getchar(); + /* fall into... */ + + default: + if (cp > &genbuf[LBSIZE - 2]) +flong: + error(catgets(catd, 1, 79, + "Argument buffer overflow")); + *cp++ = c; + break; + + case '#': + fp = altfile; + if (*fp == 0) + error(catgets(catd, 1, 80, + "No alternate filename@to substitute for #")); + goto filexp; + + case '%': + fp = savedfile; + if (*fp == 0) + error(catgets(catd, 1, 81, + "No current filename@to substitute for %%")); +filexp: + while (*fp) { + if (cp > &genbuf[LBSIZE - 2]) + goto flong; + *cp++ = *fp++; + } + break; + } + } + *cp = 0; + return (1); +} + +/* + * Scan genbuf for shell metacharacters. + * Set is union of v7 shell and csh metas. + */ +int +gscan(void) +{ + register char *cp; + + for (cp = genbuf; *cp; cp++) + if (any(*cp, "~{[*?$`'\"\\")) + return (1); + return (0); +} + +/* + * Glob the argument words in genbuf, or if no globbing + * is implied, just split them up directly. + */ +void +gglob(struct glob *gp) +{ + int pvec[2]; + register char **argv = gp->argv; + register char *cp = gp->argspac; + register int c; + char ch; + int nleft = NCARGS; + + gp->argc0 = 0; + if (gscan() == 0) { + register char *v = genbuf + 5; /* strlen("echo ") */ + + for (;;) { + while (isspace(*v&0377)) + v++; + if (!*v) + break; + *argv++ = cp; + while (*v && !isspace(*v&0377)) + *cp++ = *v++; + *cp++ = 0; + gp->argc0++; + } + *argv = 0; + return; + } + if (pipe(pvec) < 0) + error(catgets(catd, 1, 82, "Can't make pipe to glob")); + pid = fork(); + io = pvec[0]; + if (pid < 0) { + close(pvec[1]); + error(catgets(catd, 1, 83, "Can't fork to do glob")); + } + if (pid == 0) { + int oerrno; + + close(1); + dup(pvec[1]); + close(pvec[0]); + close(2); /* so errors don't mess up the screen */ + open("/dev/null", O_WRONLY); + execl(svalue(SHELL), "sh", "-c", genbuf, (char *)0); + oerrno = errno; close(1); dup(2); errno = oerrno; + filioerr(svalue(SHELL)); + } + close(pvec[1]); + do { + *argv = cp; + for (;;) { + if (read(io, &ch, 1) != 1) { + close(io); + c = -1; + } else + c = ch & TRIM; + if (c <= 0 || isspace(c)) + break; + *cp++ = c; + if (--nleft <= 0) + error(catgets(catd, 1, 84, + "Arg list too long")); + } + if (cp != *argv) { + --nleft; + *cp++ = 0; + gp->argc0++; + if (gp->argc0 >= NARGS) + error(catgets(catd, 1, 85, + "Arg list too long")); + argv++; + } + } while (c >= 0); + waitfor(); + if (gp->argc0 == 0) + error(catgets(catd, 1, 86, "No match")); +} + +/* + * Parse one filename into file. + */ +struct glob G; +void +getone(void) +{ + register char *str; + + if (getargs() == 0) +missing: + error(catgets(catd, 1, 87, "Missing filename")); + gglob(&G); + if (G.argc0 > 1) + error(catgets(catd, 1, 88, "Ambiguous|Too many file names")); + if ((str = G.argv[G.argc0 - 1]) == NULL) + goto missing; + if (strlen(str) > FNSIZE - 4) + error(catgets(catd, 1, 89, "Filename too long")); +/* samef: */ + CP(file, str); +} + +/* + * Are these two really the same inode? + */ +int +samei(struct stat *sp, char *cp) +{ + struct stat stb; + + if (stat(cp, &stb) < 0 || sp->st_dev != stb.st_dev) + return (0); + return (sp->st_ino == stb.st_ino); +} + +/* + * Read a file from the world. + * C is command, 'e' if this really an edit (or a recover). + */ +void +rop(int c) +{ + register int i; + struct stat stbuf; + char magic[4]; + static int ovro; /* old value(READONLY) */ + static int denied; /* 1 if READONLY was set due to file permissions */ + + io = open(file, O_RDONLY); + if (io < 0) { + if (c == 'e' && errno == ENOENT) { + edited++; + /* + * If the user just did "ex foo" he is probably + * creating a new file. Don't be an error, since + * this is ugly, and it screws up the + option. + * + * POSIX.2 specifies that this be done for all + * "edit" commands, not just for the first one. + */ + if (1 || !seenprompt) { + printf(catgets(catd, 1, 90, " [New file]")); + noonl(); + return; + } + } + failed = 1; + syserror(); + } + if (fstat(io, &stbuf)) + syserror(); + switch (stbuf.st_mode & S_IFMT) { + + case S_IFBLK: + error(catgets(catd, 1, 91, " Block special file")); + + case S_IFCHR: + if (isatty(io)) + error(catgets(catd, 1, 92, " Teletype")); + if (samei(&stbuf, "/dev/null")) + break; + error(catgets(catd, 1, 93, " Character special file")); + + case S_IFDIR: + error(catgets(catd, 1, 94, " Directory")); + +#ifdef S_IFSOCK + case S_IFSOCK: + error(catgets(catd, 1, 95, " Socket")); +#endif +#ifdef S_IFIFO + case S_IFIFO: + error(catgets(catd, 1, 96, " Named pipe")); +#endif + + case S_IFREG: + /* + * The magics are checked byte-wise now to avoid + * endianness problems. Some quite old types + * were omitted. + * + * Feel free too add more magics here, but do not + * make this a copy of the `file' program. + * + * GR + */ + i = read(io, magic, sizeof(magic)); + lseek(io, (off_t) 0, SEEK_SET); + if (i != sizeof(magic)) + break; + switch (magic[0]&0377) { + + case 01: /* big endian a.out */ + if (magic[1] != 05 && magic[1] != 07 + && magic[1] != 010 && magic[1] != 011 + && magic[1] != 013 && magic[1] != 030 + && magic[1] != 031) + break; + goto is_exec; + case 0314: /* Linux/ia32 QMAGIC */ + if (magic[1] != 0 || magic[2] != 0144) + break; + goto is_exec; + case 05: /* data overlay on exec */ + case 07: /* unshared */ + case 010: /* shared text */ + case 011: /* separate I/D */ + case 013: /* VM/Unix demand paged */ + case 030: /* PDP-11 Overlay shared */ + case 031: /* PDP-11 Overlay sep I/D */ + if (magic[1] == 01) +is_exec: + error(catgets(catd, 1, 97, " Executable")); + break; + + case 037: + switch (magic[1]&0377) { + case 036: /* pack */ + case 037: /* compact */ + case 0235: /* compress */ + case 0213: /* gzip */ + /* + * We omit bzip2 here since it has + * an ASCII header. + */ + error(catgets(catd, 1, 98, " Compressed Data")); + } + break; + + case 0177: + if (magic[1] == 'E' && magic[2] == 'L' + && magic[3] == 'F') + error(catgets(catd, 1, 99, " ELF object")); + break; + + default: + break; + } +#ifdef notdef + /* + * We do not forbid the editing of portable archives + * because it is reasonable to edit them, especially + * if they are archives of text files. This is + * especially useful if you archive source files together + * and copy them to another system with ~%take, since + * the files sometimes show up munged and must be fixed. + */ + case 0177545: + case 0177555: + error(catgets(catd, 1, 100, " Archive")); + + default: +#ifdef mbb + /* C/70 has a 10 bit byte */ + if (magic & 03401600) +#else + /* Everybody else has an 8 bit byte */ + if (magic & 0100200) +#endif + error(catgets(catd, 1, 101, " Non-ascii file")); + break; + } +#endif /* notdef */ + } + if (c != 'r') { + if (value(READONLY) && denied) { + value(READONLY) = ovro; + denied = 0; + } + if ((stbuf.st_mode & 0222) == 0 || access(file, W_OK) < 0) { + ovro = value(READONLY); + denied = 1; + value(READONLY) = 1; + } + } + if (value(READONLY) && !hush) { + printf(catgets(catd, 1, 102, " [Read only]")); + flush(); + } + if (c == 'r') + setdot(); + else + setall(); + if (FIXUNDO && inopen && c == 'r') + undap1 = undap2 = addr1 + 1; + rop2(); + rop3(c); +} + +void +rop2(void) +{ + line *first, *last, *a; + struct stat statb; + + deletenone(); + clrstats(); + first = addr2 + 1; + if (fstat(io, &statb) < 0 || statb.st_blksize > LBSIZE) + bsize = LBSIZE; + else { + bsize = statb.st_blksize; + if (bsize <= 0) + bsize = LBSIZE; + } + ignore(append(getfile, addr2)); + last = dot; + /* + * if the modelines variable is set, + * check the first and last five lines of the file + * for a mode line. + */ + if (value(MODELINES)) { + for (a=first; a<=last; a++) { + if (a==first+5 && last-first > 10) + a = last - 4; + getline(*a); + checkmodeline(linebuf); + } + } +} + +/* + * Io is finished, close the unit and print statistics. + */ +int +iostats(void) +{ + + fsync(io); + close(io); + io = -1; + if (hush == 0) { + if (value(TERSE)) + printf(catgets(catd, 1, 103, + " %d/%d"), cntln, (int)cntch); + else + printf(catgets(catd, 1, 104, + " %d line%s, %d character%s"), cntln, plural((long) cntln), + (int)cntch, plural((int)cntch)); + if (cntnull +#ifndef BIT8 + || cntodd +#endif + ) { + printf(catgets(catd, 1, 105, " (")); + if (cntnull) { + printf(catgets(catd, 1, 106, + "%d null"), (int)cntnull); +#ifndef BIT8 + if (cntodd) + printf(catgets(catd, 1, 107, ", ")); +#endif + } +#ifndef BIT8 + if (cntodd) + printf(catgets(catd, 1, 108, + "%d non-ASCII"), (int)cntodd); +#endif + putchar(')'); + } + noonl(); + flush(); + } + return (cntnull != 0 +#ifndef BIT8 + || cntodd != 0 +#endif + ); +} + +void +rop3(int c) +{ + + if (iostats() == 0 && c == 'e') + edited++; + if (c == 'e') { + if (wasalt || firstpat) { + register line *addr = zero + oldadot; + + if (addr > dol) + addr = dol; + if (firstpat) { + globp = (*firstpat) ? firstpat : "$"; + commands(1,1); + firstpat = 0; + } else if (addr >= one) { + if (inopen) + dot = addr; + markpr(addr); + } else + goto other; + } else +other: + if (dol > zero) { + if (inopen) + dot = one; + markpr(one); + } + if(FIXUNDO) + undkind = UNDNONE; + if (inopen) { + vcline = 0; + vreplace(0, TLINES, lineDOL()); + } + } +} + +/* Returns from edited() */ +#define EDF 0 /* Edited file */ +#define NOTEDF -1 /* Not edited file */ +#define PARTBUF 1 /* Write of partial buffer to Edited file */ + +/* + * Is file the edited file? + * Work here is that it is not considered edited + * if this is a partial buffer, and distinguish + * all cases. + */ +int +edfile(void) +{ + + if (!edited || !eq(file, savedfile)) + return (NOTEDF); + return (addr1 == one && addr2 == dol ? EDF : PARTBUF); +} + +/* + * Write a file. + */ +void +wop(bool dofname) +/*bool dofname; /\* if 1 call filename, else use savedfile */ +{ + register int c, exclam, nonexist; + line *saddr1 = NULL, *saddr2 = NULL; + struct stat stbuf; + + c = 0; + exclam = 0; + if (dofname) { + if (peekchar() == '!') + exclam++, ignchar(); + ignore(skipwh()); + while (peekchar() == '>') + ignchar(), c++, ignore(skipwh()); + if (c != 0 && c != 2) + error(catgets(catd, 1, 109, + "Write forms are 'w' and 'w>>'")); + filename('w'); + } else { + if (savedfile[0] == 0) + error(catgets(catd, 1, 110, + "No file|No current filename")); + saddr1=addr1; + saddr2=addr2; + addr1=one; + addr2=dol; + CP(file, savedfile); + if (inopen) { + vclrech(0); + splitw++; + } + lprintf("\"%s\"", file); + } + nonexist = stat(file, &stbuf); + switch (c) { + + case 0: + if (!exclam && (!value(WRITEANY) || value(READONLY))) + switch (edfile()) { + + case NOTEDF: + if (nonexist) + break; + if ((stbuf.st_mode & S_IFMT) == S_IFCHR) { + if (samei(&stbuf, "/dev/null")) + break; + if (samei(&stbuf, "/dev/tty")) + break; + } + io = open(file, O_WRONLY); + if (io < 0) + syserror(); + if (!isatty(io)) + serror(catgets(catd, 1, 111, + " File exists| File exists - use \"w! %s\" to overwrite"), file); + close(io); + break; + + case EDF: + if (value(READONLY)) + error(catgets(catd, 1, 112, + " File is read only")); + break; + + case PARTBUF: + if (value(READONLY)) + error(catgets(catd, 1, 113, + " File is read only")); + error(catgets(catd, 1, 114, + " Use \"w!\" to write partial buffer")); + } +cre: +/* + synctmp(); +*/ + io = creat(file, 0666); + if (io < 0) + syserror(); + writing = 1; + if (hush == 0) + if (nonexist) + printf(catgets(catd, 1, 115, " [New file]")); + else if (value(WRITEANY) && edfile() != EDF) + printf(catgets(catd, 1, 116, + " [Existing file]")); + break; + + case 2: + io = open(file, O_WRONLY); + if (io < 0) { + if (exclam || value(WRITEANY)) + goto cre; + syserror(); + } + lseek(io, (off_t) 0, SEEK_END); + break; + } + putfile(0); + ignore(iostats()); + if (c != 2 && addr1 == one && addr2 == dol) { + if (eq(file, savedfile)) + edited = 1; + synced(); + } + if (!dofname) { + addr1 = saddr1; + addr2 = saddr2; + } + writing = 0; +} + +/* + * Extract the next line from the io stream. + */ +char *nextip; + +int +getfile(void) +{ + register short c; + register char *lp, *fp; + + lp = linebuf; + fp = nextip; + do { + if (--ninbuf < 0) { + ninbuf = read(io, genbuf, bsize) - 1; + if (ninbuf < 0) { + if (lp != linebuf) { + lp++; + printf(catgets(catd, 1, 117, + " [Incomplete last line]")); + break; + } + return (EOF); + } + fp = genbuf; + cntch += ninbuf+1; + } + if (lp >= &linebuf[LBSIZE]) { + synced(); + error(catgets(catd, 1, 118, " Line too long")); + } + c = *fp++; + if (c == 0) { + cntnull++; +#ifndef BIT8 + continue; +#else + c = 0200; +#endif + } +#ifndef BIT8 + if (c & QUOTE) { + cntodd++; + c &= TRIM; + if (c == 0) + continue; + } +#endif + *lp++ = c; + } while (c != '\n'); + *--lp = 0; + nextip = fp; + cntln++; + return (0); +} + +/* + * Write a range onto the io stream. + */ +void +putfile(int isfilter) +{ + line *a1; + register char *fp, *lp; + register int nib; + struct stat statb; + + a1 = addr1; + clrstats(); + cntln = fixedzero ? 0 : addr2 - a1 + 1; + if (cntln == 0 || fixedzero) + return; + if (fstat(io, &statb) < 0 || statb.st_blksize > LBSIZE) + bsize = LBSIZE; + else { + bsize = statb.st_blksize; + if (bsize <= 0) + bsize = LBSIZE; + } + nib = bsize; + fp = genbuf; + do { + getline(*a1++); + lp = linebuf; + for (;;) { + if (--nib < 0) { + nib = fp - genbuf; + if (write(io, genbuf, nib) != nib) { + wrerror(); + } + cntch += nib; + nib = bsize - 1; + fp = genbuf; + } + if ((*fp++ = *lp++) == 0) { + fp[-1] = '\n'; + break; + } + } + } while (a1 <= addr2); + nib = fp - genbuf; + if (write(io, genbuf, nib) != nib) { + wrerror(); + } + cntch += nib; +} + +/* + * A write error has occurred; if the file being written was + * the edited file then we consider it to have changed since it is + * now likely scrambled. + */ +void +wrerror(void) +{ + + if (eq(file, savedfile) && edited) + change(); + syserror(); +} + +/* + * Source command, handles nested sources. + * Traps errors since it mungs unit 0 during the source. + */ +short slevel; +short ttyindes; + +void +source(char *fil, bool okfail) +{ + JMP_BUF osetexit; + register int saveinp, ointty, oerrno; + char *saveglobp, *saveinput; + char saveinline[BUFSIZ]; + int savepeekc, savelastc; + + signal(SIGINT, SIG_IGN); + saveinp = dup(0); + savepeekc = peekc; + savelastc = lastc; + saveglobp = globp; + saveinput = input; + if (input) + strcpy(saveinline, input); + peekc = 0; lastc = 0; globp = 0; input = 0; + if (saveinp < 0) + error(catgets(catd, 1, 119, "Too many nested sources")); + if (slevel <= 0) + ttyindes = saveinp; + close(0); + if (open(fil, O_RDONLY) < 0) { + oerrno = errno; + setrupt(); + dup(saveinp); + close(saveinp); + input = saveinput; + if (input) + strcpy(input, saveinline); + lastc = savelastc; + errno = oerrno; + if (!okfail) + filioerr(fil); + return; + } + slevel++; + ointty = intty; + intty = isatty(0); + oprompt = value(PROMPT); + value(PROMPT) &= intty; + getexit(osetexit); + setrupt(); + if (setexit() == 0) + commands(1, 1); + else if (slevel > 1) { + close(0); + dup(saveinp); + close(saveinp); + input = saveinput; + if (input) + strcpy(input, saveinline); + lastc = savelastc; + slevel--; + resexit(osetexit); + reset(); + } + intty = ointty; + value(PROMPT) = oprompt; + close(0); + dup(saveinp); + close(saveinp); + globp = saveglobp; + input = saveinput; + if (input) + strcpy(input, saveinline); + peekc = savepeekc; + lastc = savelastc; + slevel--; + resexit(osetexit); +} + +/* + * Clear io statistics before a read or write. + */ +void +clrstats(void) +{ + + ninbuf = 0; + cntch = 0; + cntln = 0; + cntnull = 0; +#ifndef BIT8 + cntodd = 0; +#endif +} + +/* It's so wonderful how we all speak the same language... */ +# define index strchr +# define rindex strrchr + +void +checkmodeline(char *lin) +{ + char *beg, *end; + char cmdbuf[BUFSIZ]; + + beg = index(lin, ':'); + if (beg == NULL) + return; + if (&beg[-2] < lin) + return; + if (!((beg[-2] == 'e' && beg[-1] == 'x') + || (beg[-2] == 'v' && beg[-1] == 'i'))) return; + strncpy(cmdbuf, beg+1, sizeof cmdbuf); + end = rindex(cmdbuf, ':'); + if (end == NULL) + return; + *end = 0; + globp = cmdbuf; + commands(1, 1); +} + +#ifdef MB +int +mbtowi(int *cp, const char *s, size_t n) +{ + wchar_t wc; + int i; + + i = mbtowc(&wc, s, n); + if (i >= 0 && widthok(wc) && !(wc & 0x70000000)) + *cp = wc; + else { + *cp = *s&0377 | INVBIT; + i = 1; + } + return i; +} + +int +widthok(int c) +{ + return inopen ? wcwidth(c) <= 2 : 1; +} +#endif /* MB */ + +int +GETWC(char *mb) +{ + int c, n; + + n = 1; + mb[0] = c = getchar(); + mb[1] = '\0'; +#ifdef MB + if (mb_cur_max > 1 && c & 0200 && c != EOF) { + int m; + wchar_t wc; + while ((m = mbtowc(&wc, mb, mb_cur_max)) < 0 && n<mb_cur_max) { + mb[n++] = c = getchar(); + mb[n] = '\0'; + if (c == '\n' || c == EOF) + break; + } + if (m != n || c & 0x70000000) + error("illegal multibyte sequence"); + return wc; + } else +#endif /* MB */ + return c; +} |