10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*802Scf46844 /* 23*802Scf46844 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*802Scf46844 * Use is subject to license terms. 25*802Scf46844 */ 26*802Scf46844 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate 310Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include "ex.h" 360Sstevel@tonic-gate #include "ex_argv.h" 370Sstevel@tonic-gate #include "ex_temp.h" 380Sstevel@tonic-gate #include "ex_tty.h" 390Sstevel@tonic-gate #include "ex_vis.h" 400Sstevel@tonic-gate #include <stdlib.h> 41*802Scf46844 #include <unistd.h> 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * File input/output, source, preserve and recover 450Sstevel@tonic-gate */ 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * Following remember where . was in the previous file for return 490Sstevel@tonic-gate * on file switching. 500Sstevel@tonic-gate */ 510Sstevel@tonic-gate int altdot; 520Sstevel@tonic-gate int oldadot; 530Sstevel@tonic-gate bool wasalt; 540Sstevel@tonic-gate short isalt; 550Sstevel@tonic-gate 560Sstevel@tonic-gate long cntch; /* Count of characters on unit io */ 570Sstevel@tonic-gate #ifndef VMUNIX 580Sstevel@tonic-gate short cntln; /* Count of lines " */ 590Sstevel@tonic-gate #else 600Sstevel@tonic-gate int cntln; 610Sstevel@tonic-gate #endif 620Sstevel@tonic-gate long cntnull; /* Count of nulls " */ 630Sstevel@tonic-gate long cntodd; /* Count of non-ascii characters " */ 640Sstevel@tonic-gate 650Sstevel@tonic-gate static void chkmdln(); 66*802Scf46844 extern int getchar(); 670Sstevel@tonic-gate 680Sstevel@tonic-gate /* 690Sstevel@tonic-gate * Parse file name for command encoded by comm. 700Sstevel@tonic-gate * If comm is E then command is doomed and we are 710Sstevel@tonic-gate * parsing just so user won't have to retype the name. 720Sstevel@tonic-gate */ 73*802Scf46844 void 74*802Scf46844 filename(int comm) 750Sstevel@tonic-gate { 76*802Scf46844 int c = comm, d; 77*802Scf46844 int i; 780Sstevel@tonic-gate 790Sstevel@tonic-gate d = getchar(); 800Sstevel@tonic-gate if (endcmd(d)) { 810Sstevel@tonic-gate if (savedfile[0] == 0 && comm != 'f') 820Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No file") : 830Sstevel@tonic-gate gettext("No current filename")); 840Sstevel@tonic-gate CP(file, savedfile); 850Sstevel@tonic-gate wasalt = (isalt > 0) ? isalt-1 : 0; 860Sstevel@tonic-gate isalt = 0; 870Sstevel@tonic-gate oldadot = altdot; 880Sstevel@tonic-gate if (c == 'e' || c == 'E') 890Sstevel@tonic-gate altdot = lineDOT(); 900Sstevel@tonic-gate if (d == EOF) 910Sstevel@tonic-gate ungetchar(d); 920Sstevel@tonic-gate } else { 930Sstevel@tonic-gate ungetchar(d); 940Sstevel@tonic-gate getone(); 950Sstevel@tonic-gate eol(); 960Sstevel@tonic-gate if (savedfile[0] == 0 && c != 'E' && c != 'e') { 970Sstevel@tonic-gate c = 'e'; 980Sstevel@tonic-gate edited = 0; 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate wasalt = strcmp(file, altfile) == 0; 1010Sstevel@tonic-gate oldadot = altdot; 1020Sstevel@tonic-gate switch (c) { 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate case 'f': 1050Sstevel@tonic-gate edited = 0; 1060Sstevel@tonic-gate /* fall into ... */ 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate case 'e': 1090Sstevel@tonic-gate if (savedfile[0]) { 1100Sstevel@tonic-gate altdot = lineDOT(); 1110Sstevel@tonic-gate CP(altfile, savedfile); 1120Sstevel@tonic-gate } 1130Sstevel@tonic-gate CP(savedfile, file); 1140Sstevel@tonic-gate break; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate default: 1170Sstevel@tonic-gate if (file[0]) { 1180Sstevel@tonic-gate if (c != 'E') 1190Sstevel@tonic-gate altdot = lineDOT(); 1200Sstevel@tonic-gate CP(altfile, file); 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate break; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate if (hush && comm != 'f' || comm == 'E') 1260Sstevel@tonic-gate return; 1270Sstevel@tonic-gate if (file[0] != 0) { 1280Sstevel@tonic-gate lprintf("\"%s\"", file); 1290Sstevel@tonic-gate if (comm == 'f') { 1300Sstevel@tonic-gate if (value(vi_READONLY)) 131*802Scf46844 viprintf(gettext(" [Read only]")); 1320Sstevel@tonic-gate if (!edited) 133*802Scf46844 viprintf(gettext(" [Not edited]")); 1340Sstevel@tonic-gate if (tchng) 135*802Scf46844 viprintf(gettext(" [Modified]")); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate flush(); 1380Sstevel@tonic-gate } else 139*802Scf46844 viprintf(gettext("No file ")); 1400Sstevel@tonic-gate if (comm == 'f') { 1410Sstevel@tonic-gate if (!(i = lineDOL())) 1420Sstevel@tonic-gate i++; 1430Sstevel@tonic-gate /* 1440Sstevel@tonic-gate * TRANSLATION_NOTE 1450Sstevel@tonic-gate * Reference order of arguments must not 1460Sstevel@tonic-gate * be changed using '%digit$', since vi's 147*802Scf46844 * viprintf() does not support it. 1480Sstevel@tonic-gate */ 149*802Scf46844 viprintf(gettext(" line %d of %d --%ld%%--"), lineDOT(), 150*802Scf46844 lineDOL(), (long)(100 * lineDOT() / i)); 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate /* 1550Sstevel@tonic-gate * Get the argument words for a command into genbuf 1560Sstevel@tonic-gate * expanding # and %. 1570Sstevel@tonic-gate */ 158*802Scf46844 int 159*802Scf46844 getargs(void) 1600Sstevel@tonic-gate { 161*802Scf46844 int c; 162*802Scf46844 unsigned char *cp, *fp; 1630Sstevel@tonic-gate static unsigned char fpatbuf[32]; /* hence limit on :next +/pat */ 1640Sstevel@tonic-gate char multic[MB_LEN_MAX + 1]; 1650Sstevel@tonic-gate int len; 1660Sstevel@tonic-gate wchar_t wc; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate pastwh(); 1690Sstevel@tonic-gate if (peekchar() == '+') { 1700Sstevel@tonic-gate for (cp = fpatbuf;;) { 1710Sstevel@tonic-gate if (!isascii(c = peekchar()) && (c != EOF)) { 1720Sstevel@tonic-gate if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) { 1730Sstevel@tonic-gate if ((cp + len) >= &fpatbuf[sizeof(fpatbuf)]) 1740Sstevel@tonic-gate error(gettext("Pattern too long")); 1750Sstevel@tonic-gate strncpy(cp, multic, len); 1760Sstevel@tonic-gate cp += len; 1770Sstevel@tonic-gate continue; 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate c = getchar(); 1820Sstevel@tonic-gate *cp++ = c; 1830Sstevel@tonic-gate if (cp >= &fpatbuf[sizeof(fpatbuf)]) 1840Sstevel@tonic-gate error(gettext("Pattern too long")); 1850Sstevel@tonic-gate if (c == '\\' && isspace(peekchar())) 1860Sstevel@tonic-gate c = getchar(); 1870Sstevel@tonic-gate if (c == EOF || isspace(c)) { 1880Sstevel@tonic-gate ungetchar(c); 1890Sstevel@tonic-gate *--cp = 0; 1900Sstevel@tonic-gate firstpat = &fpatbuf[1]; 1910Sstevel@tonic-gate break; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate if (skipend()) 1960Sstevel@tonic-gate return (0); 1970Sstevel@tonic-gate CP(genbuf, "echo "); cp = &genbuf[5]; 1980Sstevel@tonic-gate for (;;) { 1990Sstevel@tonic-gate if (!isascii(c = peekchar())) { 2000Sstevel@tonic-gate if (endcmd(c) && c != '"') 2010Sstevel@tonic-gate break; 2020Sstevel@tonic-gate if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) { 2030Sstevel@tonic-gate if ((cp + len) > &genbuf[LBSIZE - 2]) 2040Sstevel@tonic-gate error(gettext("Argument buffer overflow")); 2050Sstevel@tonic-gate strncpy(cp, multic, len); 2060Sstevel@tonic-gate cp += len; 2070Sstevel@tonic-gate continue; 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate if (endcmd(c) && c != '"') 2120Sstevel@tonic-gate break; 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate c = getchar(); 2150Sstevel@tonic-gate switch (c) { 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate case '\\': 2180Sstevel@tonic-gate if (any(peekchar(), "#%|")) 2190Sstevel@tonic-gate c = getchar(); 2200Sstevel@tonic-gate /* fall into... */ 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate default: 2230Sstevel@tonic-gate if (cp > &genbuf[LBSIZE - 2]) 2240Sstevel@tonic-gate flong: 2250Sstevel@tonic-gate error(gettext("Argument buffer overflow")); 2260Sstevel@tonic-gate *cp++ = c; 2270Sstevel@tonic-gate break; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate case '#': 2300Sstevel@tonic-gate fp = (unsigned char *)altfile; 2310Sstevel@tonic-gate if (*fp == 0) 2320Sstevel@tonic-gate error(value(vi_TERSE) ? 2330Sstevel@tonic-gate gettext("No alternate filename") : 2340Sstevel@tonic-gate gettext("No alternate filename to substitute for #")); 2350Sstevel@tonic-gate goto filexp; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate case '%': 2380Sstevel@tonic-gate fp = savedfile; 2390Sstevel@tonic-gate if (*fp == 0) 2400Sstevel@tonic-gate error(value(vi_TERSE) ? 2410Sstevel@tonic-gate gettext("No current filename") : 2420Sstevel@tonic-gate gettext("No current filename to substitute for %%")); 2430Sstevel@tonic-gate filexp: 2440Sstevel@tonic-gate while (*fp) { 2450Sstevel@tonic-gate if (cp > &genbuf[LBSIZE - 2]) 2460Sstevel@tonic-gate goto flong; 2470Sstevel@tonic-gate *cp++ = *fp++; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate break; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate *cp = 0; 2530Sstevel@tonic-gate return (1); 2540Sstevel@tonic-gate } 2550Sstevel@tonic-gate 2560Sstevel@tonic-gate /* 2570Sstevel@tonic-gate * Glob the argument words in genbuf, or if no globbing 2580Sstevel@tonic-gate * is implied, just split them up directly. 2590Sstevel@tonic-gate */ 260*802Scf46844 void 261*802Scf46844 glob(struct glob *gp) 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate int pvec[2]; 264*802Scf46844 unsigned char **argv = gp->argv; 265*802Scf46844 unsigned char *cp = gp->argspac; 266*802Scf46844 int c; 2670Sstevel@tonic-gate unsigned char ch; 2680Sstevel@tonic-gate int nleft = NCARGS; 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate gp->argc0 = 0; 2710Sstevel@tonic-gate if (gscan() == 0) { 272*802Scf46844 unsigned char *v = genbuf + 5; /* strlen("echo ") */ 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate for (;;) { 2750Sstevel@tonic-gate while (isspace(*v)) 2760Sstevel@tonic-gate v++; 2770Sstevel@tonic-gate if (!*v) 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate *argv++ = cp; 2800Sstevel@tonic-gate while (*v && !isspace(*v)) 2810Sstevel@tonic-gate *cp++ = *v++; 2820Sstevel@tonic-gate *cp++ = 0; 2830Sstevel@tonic-gate gp->argc0++; 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate *argv = 0; 2860Sstevel@tonic-gate return; 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate if (pipe(pvec) < 0) 2890Sstevel@tonic-gate error(gettext("Can't make pipe to glob")); 2900Sstevel@tonic-gate pid = fork(); 2910Sstevel@tonic-gate io = pvec[0]; 2920Sstevel@tonic-gate if (pid < 0) { 2930Sstevel@tonic-gate close(pvec[1]); 2940Sstevel@tonic-gate error(gettext("Can't fork to do glob")); 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate if (pid == 0) { 2970Sstevel@tonic-gate int oerrno; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate close(1); 3000Sstevel@tonic-gate dup(pvec[1]); 3010Sstevel@tonic-gate close(pvec[0]); 3020Sstevel@tonic-gate close(2); /* so errors don't mess up the screen */ 3030Sstevel@tonic-gate open("/dev/null", 1); 304*802Scf46844 execlp((char *)svalue(vi_SHELL), "sh", "-c", genbuf, (char *)0); 3050Sstevel@tonic-gate oerrno = errno; close(1); dup(2); errno = oerrno; 3060Sstevel@tonic-gate filioerr(svalue(vi_SHELL)); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate close(pvec[1]); 3090Sstevel@tonic-gate do { 3100Sstevel@tonic-gate *argv = cp; 3110Sstevel@tonic-gate for (;;) { 3120Sstevel@tonic-gate if (read(io, &ch, 1) != 1) { 3130Sstevel@tonic-gate close(io); 3140Sstevel@tonic-gate c = -1; 3150Sstevel@tonic-gate } else 3160Sstevel@tonic-gate c = ch; 3170Sstevel@tonic-gate if (c <= 0 || isspace(c)) 3180Sstevel@tonic-gate break; 3190Sstevel@tonic-gate *cp++ = c; 3200Sstevel@tonic-gate if (--nleft <= 0) 3210Sstevel@tonic-gate error(gettext("Arg list too long")); 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate if (cp != *argv) { 3240Sstevel@tonic-gate --nleft; 3250Sstevel@tonic-gate *cp++ = 0; 3260Sstevel@tonic-gate gp->argc0++; 3270Sstevel@tonic-gate if (gp->argc0 >= NARGS) 3280Sstevel@tonic-gate error(gettext("Arg list too long")); 3290Sstevel@tonic-gate argv++; 3300Sstevel@tonic-gate } 3310Sstevel@tonic-gate } while (c >= 0); 3320Sstevel@tonic-gate waitfor(); 3330Sstevel@tonic-gate if (gp->argc0 == 0) 3340Sstevel@tonic-gate error(gettext("No match")); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate /* 3380Sstevel@tonic-gate * Scan genbuf for shell metacharacters. 3390Sstevel@tonic-gate * Set is union of v7 shell and csh metas. 3400Sstevel@tonic-gate */ 341*802Scf46844 int 342*802Scf46844 gscan(void) 3430Sstevel@tonic-gate { 344*802Scf46844 unsigned char *cp; 3450Sstevel@tonic-gate int len; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate for (cp = genbuf; *cp; cp += len) { 3480Sstevel@tonic-gate if (any(*cp, "~{[*?$`'\"\\")) 3490Sstevel@tonic-gate return (1); 3500Sstevel@tonic-gate if ((len = mblen((char *)cp, MB_CUR_MAX)) <= 0) 3510Sstevel@tonic-gate len = 1; 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate return (0); 3540Sstevel@tonic-gate } 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate /* 3570Sstevel@tonic-gate * Parse one filename into file. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate struct glob G; 360*802Scf46844 void 361*802Scf46844 getone(void) 3620Sstevel@tonic-gate { 363*802Scf46844 unsigned char *str; 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate if (getargs() == 0) 3660Sstevel@tonic-gate error(gettext("Missing filename")); 3670Sstevel@tonic-gate glob(&G); 3680Sstevel@tonic-gate if (G.argc0 > 1) 3690Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Ambiguous") : 3700Sstevel@tonic-gate gettext("Too many file names")); 3710Sstevel@tonic-gate if (G.argc0 < 1) 3720Sstevel@tonic-gate error(gettext("Missing filename")); 3730Sstevel@tonic-gate str = G.argv[G.argc0 - 1]; 3740Sstevel@tonic-gate if (strlen(str) > FNSIZE - 4) 3750Sstevel@tonic-gate error(gettext("Filename too long")); 3760Sstevel@tonic-gate samef: 3770Sstevel@tonic-gate CP(file, str); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate /* 3810Sstevel@tonic-gate * Read a file from the world. 3820Sstevel@tonic-gate * C is command, 'e' if this really an edit (or a recover). 3830Sstevel@tonic-gate */ 384*802Scf46844 void 385*802Scf46844 rop(int c) 3860Sstevel@tonic-gate { 387*802Scf46844 int i; 3880Sstevel@tonic-gate struct stat64 stbuf; 3890Sstevel@tonic-gate short magic; 3900Sstevel@tonic-gate static int ovro; /* old value(vi_READONLY) */ 3910Sstevel@tonic-gate static int denied; /* 1 if READONLY was set due to file permissions */ 3920Sstevel@tonic-gate 3930Sstevel@tonic-gate io = open(file, 0); 3940Sstevel@tonic-gate if (io < 0) { 3950Sstevel@tonic-gate if (c == 'e' && errno == ENOENT) { 3960Sstevel@tonic-gate edited++; 3970Sstevel@tonic-gate /* 3980Sstevel@tonic-gate * If the user just did "ex foo" he is probably 3990Sstevel@tonic-gate * creating a new file. Don't be an error, since 4000Sstevel@tonic-gate * this is ugly, and it messes up the + option. 4010Sstevel@tonic-gate */ 4020Sstevel@tonic-gate if (!seenprompt) { 403*802Scf46844 viprintf(gettext(" [New file]")); 4040Sstevel@tonic-gate noonl(); 4050Sstevel@tonic-gate return; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (value(vi_READONLY) && denied) { 4100Sstevel@tonic-gate value(vi_READONLY) = ovro; 4110Sstevel@tonic-gate denied = 0; 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate syserror(0); 4140Sstevel@tonic-gate } 4150Sstevel@tonic-gate if (fstat64(io, &stbuf)) 4160Sstevel@tonic-gate syserror(0); 4170Sstevel@tonic-gate switch (FTYPE(stbuf) & S_IFMT) { 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate case S_IFBLK: 4200Sstevel@tonic-gate error(gettext(" Block special file")); 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate case S_IFCHR: 4230Sstevel@tonic-gate if (isatty(io)) 4240Sstevel@tonic-gate error(gettext(" Teletype")); 4250Sstevel@tonic-gate if (samei(&stbuf, "/dev/null")) 4260Sstevel@tonic-gate break; 4270Sstevel@tonic-gate error(gettext(" Character special file")); 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate case S_IFDIR: 4300Sstevel@tonic-gate error(gettext(" Directory")); 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate if (c != 'r') { 4340Sstevel@tonic-gate if (value(vi_READONLY) && denied) { 4350Sstevel@tonic-gate value(vi_READONLY) = ovro; 4360Sstevel@tonic-gate denied = 0; 4370Sstevel@tonic-gate } 438*802Scf46844 if ((FMODE(stbuf) & 0222) == 0 || access((char *)file, 2) < 0) { 4390Sstevel@tonic-gate ovro = value(vi_READONLY); 4400Sstevel@tonic-gate denied = 1; 4410Sstevel@tonic-gate value(vi_READONLY) = 1; 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate if (hush == 0 && value(vi_READONLY)) { 445*802Scf46844 viprintf(gettext(" [Read only]")); 4460Sstevel@tonic-gate flush(); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate if (c == 'r') 4490Sstevel@tonic-gate setdot(); 4500Sstevel@tonic-gate else 4510Sstevel@tonic-gate setall(); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate /* If it is a read command, then we must set dot to addr1 4540Sstevel@tonic-gate * (value of N in :Nr ). In the default case, addr1 will 4550Sstevel@tonic-gate * already be set to dot. 4560Sstevel@tonic-gate * 4570Sstevel@tonic-gate * Next, it is necessary to mark the beginning (undap1) and 4580Sstevel@tonic-gate * ending (undap2) addresses affected (for undo). Note that 4590Sstevel@tonic-gate * rop2() and rop3() will adjust the value of undap2. 4600Sstevel@tonic-gate */ 4610Sstevel@tonic-gate if (FIXUNDO && inopen && c == 'r') { 4620Sstevel@tonic-gate dot = addr1; 4630Sstevel@tonic-gate undap1 = undap2 = dot + 1; 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate rop2(); 4660Sstevel@tonic-gate rop3(c); 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate 469*802Scf46844 void 470*802Scf46844 rop2(void) 4710Sstevel@tonic-gate { 4720Sstevel@tonic-gate line *first, *last, *a; 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate deletenone(); 4750Sstevel@tonic-gate clrstats(); 4760Sstevel@tonic-gate first = addr2 + 1; 4770Sstevel@tonic-gate (void)append(getfile, addr2); 4780Sstevel@tonic-gate last = dot; 4790Sstevel@tonic-gate if (value(vi_MODELINES)) 4800Sstevel@tonic-gate for (a=first; a<=last; a++) { 4810Sstevel@tonic-gate if (a==first+5 && last-first > 10) 4820Sstevel@tonic-gate a = last - 4; 4830Sstevel@tonic-gate getline(*a); 4840Sstevel@tonic-gate chkmdln(linebuf); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate 488*802Scf46844 void 489*802Scf46844 rop3(int c) 4900Sstevel@tonic-gate { 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate if (iostats() == 0 && c == 'e') 4930Sstevel@tonic-gate edited++; 4940Sstevel@tonic-gate if (c == 'e') { 4950Sstevel@tonic-gate if (wasalt || firstpat) { 496*802Scf46844 line *addr = zero + oldadot; 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate if (addr > dol) 4990Sstevel@tonic-gate addr = dol; 5000Sstevel@tonic-gate if (firstpat) { 5010Sstevel@tonic-gate globp = (*firstpat) ? firstpat : (unsigned char *)"$"; 5020Sstevel@tonic-gate commands(1,1); 5030Sstevel@tonic-gate firstpat = 0; 5040Sstevel@tonic-gate } else if (addr >= one) { 5050Sstevel@tonic-gate if (inopen) 5060Sstevel@tonic-gate dot = addr; 5070Sstevel@tonic-gate markpr(addr); 5080Sstevel@tonic-gate } else 5090Sstevel@tonic-gate goto other; 5100Sstevel@tonic-gate } else 5110Sstevel@tonic-gate other: 5120Sstevel@tonic-gate if (dol > zero) { 5130Sstevel@tonic-gate if (inopen) 5140Sstevel@tonic-gate dot = one; 5150Sstevel@tonic-gate markpr(one); 5160Sstevel@tonic-gate } 5170Sstevel@tonic-gate if(FIXUNDO) 5180Sstevel@tonic-gate undkind = UNDNONE; 5190Sstevel@tonic-gate if (inopen) { 5200Sstevel@tonic-gate vcline = 0; 5210Sstevel@tonic-gate vreplace(0, lines, lineDOL()); 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate if (laste) { 5250Sstevel@tonic-gate #ifdef VMUNIX 5260Sstevel@tonic-gate tlaste(); 5270Sstevel@tonic-gate #endif 5280Sstevel@tonic-gate laste = 0; 5290Sstevel@tonic-gate sync(); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate /* 5340Sstevel@tonic-gate * Are these two really the same inode? 5350Sstevel@tonic-gate */ 536*802Scf46844 int 537*802Scf46844 samei(struct stat64 *sp, unsigned char *cp) 5380Sstevel@tonic-gate { 5390Sstevel@tonic-gate struct stat64 stb; 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (stat64((char *)cp, &stb) < 0) 5420Sstevel@tonic-gate return (0); 5430Sstevel@tonic-gate return (IDENTICAL((*sp), stb)); 5440Sstevel@tonic-gate } 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate /* Returns from edited() */ 5470Sstevel@tonic-gate #define EDF 0 /* Edited file */ 5480Sstevel@tonic-gate #define NOTEDF -1 /* Not edited file */ 5490Sstevel@tonic-gate #define PARTBUF 1 /* Write of partial buffer to Edited file */ 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate /* 5520Sstevel@tonic-gate * Write a file. 5530Sstevel@tonic-gate */ 554*802Scf46844 void 5550Sstevel@tonic-gate wop(dofname) 5560Sstevel@tonic-gate bool dofname; /* if 1 call filename, else use savedfile */ 5570Sstevel@tonic-gate { 558*802Scf46844 int c, exclam, nonexist; 5590Sstevel@tonic-gate line *saddr1, *saddr2; 5600Sstevel@tonic-gate struct stat64 stbuf; 5610Sstevel@tonic-gate char *messagep; 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate c = 0; 5640Sstevel@tonic-gate exclam = 0; 5650Sstevel@tonic-gate if (dofname) { 5660Sstevel@tonic-gate if (peekchar() == '!') 5670Sstevel@tonic-gate exclam++, ignchar(); 5680Sstevel@tonic-gate (void)skipwh(); 5690Sstevel@tonic-gate while (peekchar() == '>') 5700Sstevel@tonic-gate ignchar(), c++, (void)skipwh(); 5710Sstevel@tonic-gate if (c != 0 && c != 2) 5720Sstevel@tonic-gate error(gettext("Write forms are 'w' and 'w>>'")); 5730Sstevel@tonic-gate filename('w'); 5740Sstevel@tonic-gate } else { 5750Sstevel@tonic-gate if (savedfile[0] == 0) 5760Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("No file") : 5770Sstevel@tonic-gate gettext("No current filename")); 5780Sstevel@tonic-gate saddr1=addr1; 5790Sstevel@tonic-gate saddr2=addr2; 5800Sstevel@tonic-gate addr1=one; 5810Sstevel@tonic-gate addr2=dol; 5820Sstevel@tonic-gate CP(file, savedfile); 5830Sstevel@tonic-gate if (inopen) { 5840Sstevel@tonic-gate vclrech(0); 5850Sstevel@tonic-gate splitw++; 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate lprintf("\"%s\"", file); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate nonexist = stat64((char *)file, &stbuf); 5900Sstevel@tonic-gate switch (c) { 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate case 0: 5930Sstevel@tonic-gate if (!exclam && (!value(vi_WRITEANY) || value(vi_READONLY))) 5940Sstevel@tonic-gate switch (edfile()) { 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate case NOTEDF: 5970Sstevel@tonic-gate if (nonexist) 5980Sstevel@tonic-gate break; 5990Sstevel@tonic-gate if (ISCHR(stbuf)) { 600*802Scf46844 if (samei(&stbuf, (unsigned char *)"/dev/null")) 6010Sstevel@tonic-gate break; 602*802Scf46844 if (samei(&stbuf, (unsigned char *)"/dev/tty")) 6030Sstevel@tonic-gate break; 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate io = open(file, 1); 6060Sstevel@tonic-gate if (io < 0) 6070Sstevel@tonic-gate syserror(0); 6080Sstevel@tonic-gate if (!isatty(io)) 609*802Scf46844 serror(value(vi_TERSE) ? 610*802Scf46844 (unsigned char *)gettext(" File exists") : 611*802Scf46844 (unsigned char *)gettext(" File exists - use \"w! %s\" to overwrite"), 612*802Scf46844 file); 6130Sstevel@tonic-gate close(io); 6140Sstevel@tonic-gate break; 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate case EDF: 6170Sstevel@tonic-gate if (value(vi_READONLY)) 6180Sstevel@tonic-gate error(gettext(" File is read only")); 6190Sstevel@tonic-gate break; 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate case PARTBUF: 6220Sstevel@tonic-gate if (value(vi_READONLY)) 6230Sstevel@tonic-gate error(gettext(" File is read only")); 6240Sstevel@tonic-gate error(gettext(" Use \"w!\" to write partial buffer")); 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate cre: 6270Sstevel@tonic-gate /* 6280Sstevel@tonic-gate synctmp(); 6290Sstevel@tonic-gate */ 6300Sstevel@tonic-gate io = creat(file, 0666); 6310Sstevel@tonic-gate if (io < 0) 6320Sstevel@tonic-gate syserror(0); 6330Sstevel@tonic-gate writing = 1; 6340Sstevel@tonic-gate if (hush == 0) 6350Sstevel@tonic-gate if (nonexist) 636*802Scf46844 viprintf(gettext(" [New file]")); 6370Sstevel@tonic-gate else if (value(vi_WRITEANY) && edfile() != EDF) 638*802Scf46844 viprintf(gettext(" [Existing file]")); 6390Sstevel@tonic-gate break; 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate case 2: 6420Sstevel@tonic-gate io = open(file, 1); 6430Sstevel@tonic-gate if (io < 0) { 6440Sstevel@tonic-gate if (exclam || value(vi_WRITEANY)) 6450Sstevel@tonic-gate goto cre; 6460Sstevel@tonic-gate syserror(0); 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate lseek(io, 0l, 2); 6490Sstevel@tonic-gate break; 6500Sstevel@tonic-gate } 6510Sstevel@tonic-gate if (write_quit && inopen && (argc == 0 || morargc == argc)) 6520Sstevel@tonic-gate setty(normf); 6530Sstevel@tonic-gate putfile(0); 6540Sstevel@tonic-gate if (fsync(io) < 0) { 655*802Scf46844 /* 656*802Scf46844 * For NFS files write in putfile doesn't return error, but 657*802Scf46844 * fsync does. So, catch it here. 658*802Scf46844 */ 659*802Scf46844 messagep = (char *)gettext( 660*802Scf46844 "\r\nYour file has been preserved\r\n"); 661*802Scf46844 (void) preserve(); 662*802Scf46844 write(1, messagep, strlen(messagep)); 6630Sstevel@tonic-gate 664*802Scf46844 wrerror(); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate (void)iostats(); 6670Sstevel@tonic-gate if (c != 2 && addr1 == one && addr2 == dol) { 6680Sstevel@tonic-gate if (eq(file, savedfile)) 6690Sstevel@tonic-gate edited = 1; 6700Sstevel@tonic-gate sync(); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate if (!dofname) { 6730Sstevel@tonic-gate addr1 = saddr1; 6740Sstevel@tonic-gate addr2 = saddr2; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate writing = 0; 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /* 6800Sstevel@tonic-gate * Is file the edited file? 6810Sstevel@tonic-gate * Work here is that it is not considered edited 6820Sstevel@tonic-gate * if this is a partial buffer, and distinguish 6830Sstevel@tonic-gate * all cases. 6840Sstevel@tonic-gate */ 685*802Scf46844 int 686*802Scf46844 edfile(void) 6870Sstevel@tonic-gate { 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate if (!edited || !eq(file, savedfile)) 6900Sstevel@tonic-gate return (NOTEDF); 6910Sstevel@tonic-gate return (addr1 == one && addr2 == dol ? EDF : PARTBUF); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate 6940Sstevel@tonic-gate /* 6950Sstevel@tonic-gate * Extract the next line from the io stream. 6960Sstevel@tonic-gate */ 6970Sstevel@tonic-gate unsigned char *nextip; 6980Sstevel@tonic-gate 699*802Scf46844 int 700*802Scf46844 getfile(void) 7010Sstevel@tonic-gate { 702*802Scf46844 short c; 703*802Scf46844 unsigned char *lp; 704*802Scf46844 unsigned char *fp; 7050Sstevel@tonic-gate 7060Sstevel@tonic-gate lp = linebuf; 7070Sstevel@tonic-gate fp = nextip; 7080Sstevel@tonic-gate do { 7090Sstevel@tonic-gate if (--ninbuf < 0) { 7100Sstevel@tonic-gate ninbuf = read(io, genbuf, LBSIZE) - 1; 7110Sstevel@tonic-gate if (ninbuf < 0) { 7120Sstevel@tonic-gate if (lp != linebuf) { 7130Sstevel@tonic-gate lp++; 714*802Scf46844 viprintf( 715*802Scf46844 gettext(" [Incomplete last line]")); 7160Sstevel@tonic-gate break; 7170Sstevel@tonic-gate } 7180Sstevel@tonic-gate return (EOF); 7190Sstevel@tonic-gate } 7200Sstevel@tonic-gate if(crflag == -1) { 7210Sstevel@tonic-gate if(isencrypt(genbuf, ninbuf + 1)) 7220Sstevel@tonic-gate crflag = 2; 7230Sstevel@tonic-gate else 7240Sstevel@tonic-gate crflag = -2; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate if (crflag > 0 && run_crypt(cntch, genbuf, ninbuf+1, perm) == -1) { 7270Sstevel@tonic-gate smerror(gettext("Cannot decrypt block of text\n")); 7280Sstevel@tonic-gate break; 7290Sstevel@tonic-gate } 7300Sstevel@tonic-gate fp = genbuf; 7310Sstevel@tonic-gate cntch += ninbuf+1; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate if (lp >= &linebuf[LBSIZE]) { 7340Sstevel@tonic-gate error(gettext(" Line too long")); 7350Sstevel@tonic-gate } 7360Sstevel@tonic-gate c = *fp++; 7370Sstevel@tonic-gate if (c == 0) { 7380Sstevel@tonic-gate cntnull++; 7390Sstevel@tonic-gate continue; 7400Sstevel@tonic-gate } 7410Sstevel@tonic-gate *lp++ = c; 7420Sstevel@tonic-gate } while (c != '\n'); 7430Sstevel@tonic-gate *--lp = 0; 7440Sstevel@tonic-gate nextip = fp; 7450Sstevel@tonic-gate cntln++; 7460Sstevel@tonic-gate return (0); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate /* 7500Sstevel@tonic-gate * Write a range onto the io stream. 7510Sstevel@tonic-gate */ 752*802Scf46844 void 7530Sstevel@tonic-gate putfile(int isfilter) 7540Sstevel@tonic-gate { 7550Sstevel@tonic-gate line *a1; 756*802Scf46844 unsigned char *lp; 757*802Scf46844 unsigned char *fp; 758*802Scf46844 int nib; 759*802Scf46844 bool ochng = chng; 7600Sstevel@tonic-gate char *messagep; 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate chng = 1; /* set to force file recovery procedures in */ 7630Sstevel@tonic-gate /* the event of an interrupt during write */ 7640Sstevel@tonic-gate a1 = addr1; 7650Sstevel@tonic-gate clrstats(); 7660Sstevel@tonic-gate cntln = addr2 - a1 + 1; 7670Sstevel@tonic-gate nib = BUFSIZE; 7680Sstevel@tonic-gate fp = genbuf; 7690Sstevel@tonic-gate do { 7700Sstevel@tonic-gate getline(*a1++); 7710Sstevel@tonic-gate lp = linebuf; 7720Sstevel@tonic-gate for (;;) { 7730Sstevel@tonic-gate if (--nib < 0) { 7740Sstevel@tonic-gate nib = fp - genbuf; 7750Sstevel@tonic-gate if(kflag && !isfilter) 7760Sstevel@tonic-gate if (run_crypt(cntch, genbuf, nib, perm) == -1) 7770Sstevel@tonic-gate wrerror(); 7780Sstevel@tonic-gate if (write(io, genbuf, nib) != nib) { 779*802Scf46844 messagep = (char *)gettext( 780*802Scf46844 "\r\nYour file has been preserved\r\n"); 781*802Scf46844 (void) preserve(); 782*802Scf46844 write(1, messagep, strlen(messagep)); 7830Sstevel@tonic-gate 784*802Scf46844 if (!isfilter) 785*802Scf46844 wrerror(); 786*802Scf46844 return; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate cntch += nib; 7890Sstevel@tonic-gate nib = BUFSIZE - 1; 7900Sstevel@tonic-gate fp = genbuf; 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate if ((*fp++ = *lp++) == 0) { 7930Sstevel@tonic-gate fp[-1] = '\n'; 7940Sstevel@tonic-gate break; 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate } 7970Sstevel@tonic-gate } while (a1 <= addr2); 7980Sstevel@tonic-gate nib = fp - genbuf; 7990Sstevel@tonic-gate if(kflag && !isfilter) 8000Sstevel@tonic-gate if (run_crypt(cntch, genbuf, nib, perm) == -1) 8010Sstevel@tonic-gate wrerror(); 8020Sstevel@tonic-gate if ((cntch == 0) && (nib == 1)) { 8030Sstevel@tonic-gate cntln = 0; 8040Sstevel@tonic-gate return; 8050Sstevel@tonic-gate } 8060Sstevel@tonic-gate if (write(io, genbuf, nib) != nib) { 807*802Scf46844 messagep = (char *)gettext( 808*802Scf46844 "\r\nYour file has been preserved\r\n"); 809*802Scf46844 (void) preserve(); 810*802Scf46844 write(1, messagep, strlen(messagep)); 8110Sstevel@tonic-gate 8120Sstevel@tonic-gate if(!isfilter) 8130Sstevel@tonic-gate wrerror(); 8140Sstevel@tonic-gate return; 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate cntch += nib; 8170Sstevel@tonic-gate chng = ochng; /* reset chng to original value */ 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate /* 8210Sstevel@tonic-gate * A write error has occurred; if the file being written was 8220Sstevel@tonic-gate * the edited file then we consider it to have changed since it is 8230Sstevel@tonic-gate * now likely scrambled. 8240Sstevel@tonic-gate */ 825*802Scf46844 void 826*802Scf46844 wrerror(void) 8270Sstevel@tonic-gate { 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate if (eq(file, savedfile) && edited) 8300Sstevel@tonic-gate change(); 8310Sstevel@tonic-gate syserror(1); 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate /* 8350Sstevel@tonic-gate * Source command, handles nested sources. 8360Sstevel@tonic-gate * Traps errors since it mungs unit 0 during the source. 8370Sstevel@tonic-gate */ 8380Sstevel@tonic-gate short slevel; 8390Sstevel@tonic-gate short ttyindes; 8400Sstevel@tonic-gate 841*802Scf46844 void 8420Sstevel@tonic-gate source(fil, okfail) 8430Sstevel@tonic-gate unsigned char *fil; 8440Sstevel@tonic-gate bool okfail; 8450Sstevel@tonic-gate { 8460Sstevel@tonic-gate jmp_buf osetexit; 847*802Scf46844 int saveinp, ointty, oerrno; 8480Sstevel@tonic-gate unsigned char *saveglobp; 8490Sstevel@tonic-gate short savepeekc; 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate signal(SIGINT, SIG_IGN); 8520Sstevel@tonic-gate saveinp = dup(0); 8530Sstevel@tonic-gate savepeekc = peekc; 8540Sstevel@tonic-gate saveglobp = globp; 8550Sstevel@tonic-gate peekc = 0; globp = 0; 8560Sstevel@tonic-gate if (saveinp < 0) 8570Sstevel@tonic-gate error(gettext("Too many nested sources")); 8580Sstevel@tonic-gate if (slevel <= 0) 8590Sstevel@tonic-gate ttyindes = saveinp; 8600Sstevel@tonic-gate close(0); 8610Sstevel@tonic-gate if (open(fil, 0) < 0) { 8620Sstevel@tonic-gate oerrno = errno; 8630Sstevel@tonic-gate setrupt(); 8640Sstevel@tonic-gate dup(saveinp); 8650Sstevel@tonic-gate close(saveinp); 8660Sstevel@tonic-gate errno = oerrno; 8670Sstevel@tonic-gate if (!okfail) 8680Sstevel@tonic-gate filioerr(fil); 8690Sstevel@tonic-gate return; 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate slevel++; 8720Sstevel@tonic-gate ointty = intty; 8730Sstevel@tonic-gate intty = isatty(0); 8740Sstevel@tonic-gate oprompt = value(vi_PROMPT); 8750Sstevel@tonic-gate value(vi_PROMPT) &= intty; 8760Sstevel@tonic-gate getexit(osetexit); 8770Sstevel@tonic-gate setrupt(); 8780Sstevel@tonic-gate if (setexit() == 0) 8790Sstevel@tonic-gate commands(1, 1); 8800Sstevel@tonic-gate else if (slevel > 1) { 8810Sstevel@tonic-gate close(0); 8820Sstevel@tonic-gate dup(saveinp); 8830Sstevel@tonic-gate close(saveinp); 8840Sstevel@tonic-gate slevel--; 8850Sstevel@tonic-gate resexit(osetexit); 8860Sstevel@tonic-gate reset(); 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate intty = ointty; 8890Sstevel@tonic-gate value(vi_PROMPT) = oprompt; 8900Sstevel@tonic-gate close(0); 8910Sstevel@tonic-gate dup(saveinp); 8920Sstevel@tonic-gate close(saveinp); 8930Sstevel@tonic-gate globp = saveglobp; 8940Sstevel@tonic-gate peekc = savepeekc; 8950Sstevel@tonic-gate slevel--; 8960Sstevel@tonic-gate resexit(osetexit); 8970Sstevel@tonic-gate } 8980Sstevel@tonic-gate 8990Sstevel@tonic-gate /* 9000Sstevel@tonic-gate * Clear io statistics before a read or write. 9010Sstevel@tonic-gate */ 902*802Scf46844 void 903*802Scf46844 clrstats(void) 9040Sstevel@tonic-gate { 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate ninbuf = 0; 9070Sstevel@tonic-gate cntch = 0; 9080Sstevel@tonic-gate cntln = 0; 9090Sstevel@tonic-gate cntnull = 0; 9100Sstevel@tonic-gate cntodd = 0; 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate 9130Sstevel@tonic-gate /* 9140Sstevel@tonic-gate * Io is finished, close the unit and print statistics. 9150Sstevel@tonic-gate */ 916*802Scf46844 int 917*802Scf46844 iostats(void) 9180Sstevel@tonic-gate { 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate close(io); 9210Sstevel@tonic-gate io = -1; 9220Sstevel@tonic-gate if (hush == 0) { 9230Sstevel@tonic-gate if (value(vi_TERSE)) 924*802Scf46844 viprintf(" %d/%D", cntln, cntch); 9250Sstevel@tonic-gate else if (cntln == 1 && cntch == 1) { 926*802Scf46844 viprintf(gettext(" 1 line, 1 character")); 9270Sstevel@tonic-gate } else if (cntln == 1 && cntch != 1) { 928*802Scf46844 viprintf(gettext(" 1 line, %D characters"), cntch); 9290Sstevel@tonic-gate } else if (cntln != 1 && cntch != 1) { 9300Sstevel@tonic-gate /* 9310Sstevel@tonic-gate * TRANSLATION_NOTE 9320Sstevel@tonic-gate * Reference order of arguments must not 9330Sstevel@tonic-gate * be changed using '%digit$', since vi's 934*802Scf46844 * viprintf() does not support it. 9350Sstevel@tonic-gate */ 936*802Scf46844 viprintf(gettext(" %d lines, %D characters"), cntln, 9370Sstevel@tonic-gate cntch); 9380Sstevel@tonic-gate } else { 9390Sstevel@tonic-gate /* ridiculous */ 940*802Scf46844 viprintf(gettext(" %d lines, 1 character"), cntln); 9410Sstevel@tonic-gate } 9420Sstevel@tonic-gate if (cntnull || cntodd) { 943*802Scf46844 viprintf(" ("); 9440Sstevel@tonic-gate if (cntnull) { 945*802Scf46844 viprintf(gettext("%D null"), cntnull); 9460Sstevel@tonic-gate if (cntodd) 947*802Scf46844 viprintf(", "); 9480Sstevel@tonic-gate } 9490Sstevel@tonic-gate if (cntodd) 950*802Scf46844 viprintf(gettext("%D non-ASCII"), cntodd); 9510Sstevel@tonic-gate putchar(')'); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate noonl(); 9540Sstevel@tonic-gate flush(); 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate return (cntnull != 0 || cntodd != 0); 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate static void chkmdln(aline) 9610Sstevel@tonic-gate unsigned char *aline; 9620Sstevel@tonic-gate { 9630Sstevel@tonic-gate unsigned char *beg, *end; 9640Sstevel@tonic-gate unsigned char cmdbuf[1024]; 9650Sstevel@tonic-gate char *strchr(), *strrchr(); 9660Sstevel@tonic-gate bool savetty; 9670Sstevel@tonic-gate int savepeekc; 9680Sstevel@tonic-gate int savechng; 9690Sstevel@tonic-gate unsigned char *savefirstpat; 9700Sstevel@tonic-gate unsigned char *p; 9710Sstevel@tonic-gate int len; 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate beg = (unsigned char *)strchr((char *)aline, ':'); 9740Sstevel@tonic-gate if (beg == NULL) 9750Sstevel@tonic-gate return; 9760Sstevel@tonic-gate if ((len = beg - aline) < 2) 9770Sstevel@tonic-gate return; 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate if ((beg - aline) != 2) { 9800Sstevel@tonic-gate if ((p = beg - ((unsigned int)MB_CUR_MAX * 2) - 2) < aline) 9810Sstevel@tonic-gate p = aline; 9820Sstevel@tonic-gate for ( ; p < (beg - 2); p += len) { 9830Sstevel@tonic-gate if ((len = mblen((char *)p, MB_CUR_MAX)) <= 0) 9840Sstevel@tonic-gate len = 1; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate if (p != (beg - 2)) 9870Sstevel@tonic-gate return; 9880Sstevel@tonic-gate } 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate if (!((beg[-2] == 'e' && p[-1] == 'x') 9910Sstevel@tonic-gate || (beg[-2] == 'v' && beg[-1] == 'i'))) 9920Sstevel@tonic-gate return; 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate strncpy(cmdbuf, beg+1, sizeof cmdbuf); 9950Sstevel@tonic-gate end = (unsigned char *)strrchr(cmdbuf, ':'); 9960Sstevel@tonic-gate if (end == NULL) 9970Sstevel@tonic-gate return; 9980Sstevel@tonic-gate *end = 0; 9990Sstevel@tonic-gate globp = cmdbuf; 10000Sstevel@tonic-gate savepeekc = peekc; 10010Sstevel@tonic-gate peekc = 0; 10020Sstevel@tonic-gate savetty = intty; 10030Sstevel@tonic-gate intty = 0; 10040Sstevel@tonic-gate savechng = chng; 10050Sstevel@tonic-gate savefirstpat = firstpat; 10060Sstevel@tonic-gate firstpat = (unsigned char *)""; 10070Sstevel@tonic-gate commands(1, 1); 10080Sstevel@tonic-gate peekc = savepeekc; 10090Sstevel@tonic-gate globp = 0; 10100Sstevel@tonic-gate intty = savetty; 10110Sstevel@tonic-gate /* chng being increased indicates that text was changed */ 10120Sstevel@tonic-gate if (savechng < chng) 10130Sstevel@tonic-gate laste = 0; 10140Sstevel@tonic-gate firstpat = savefirstpat; 10150Sstevel@tonic-gate } 1016