bfs.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <setjmp.h>
#include <signal.h>
#include <stdlib.h>
#include <regexpr.h>
#include <limits.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <wait.h>
#include <fcntl.h>
int setjmp();
static jmp_buf env;
extern int scrwidth(wchar_t);
#define BRKTYP char
#define BRKSIZ 8192
#define BRKTWO 4
#define BFSAND
#define BFSLIM 511
#define BFSTRU 511
#define BFSBUF 512
struct Comd {
int Cnumadr;
int Cadr[2];
char Csep;
char Cop;
};
static int Dot, Dollar;
static int markarray[26], *mark;
static int fstack[15] = {1, -1};
static int infildes = 0;
static int outfildes = 1;
static char internal[512], *intptr;
static char comdlist[100];
static char *endds;
static char charbuf = '\n';
static int peeked;
static char currex[100];
static int trunc = BFSTRU;
static int crunch = -1;
static int segblk[512], segoff[512], txtfd, prevblk, prevoff;
static int oldfd = 0;
static int flag4 = 0;
static int flag3 = 0;
static int flag2 = 0;
static int flag1 = 0;
static int flag = 0;
static int lprev = 1;
static int status[1];
static BRKTYP *lincnt;
static char *perbuf;
static char *rebuf;
static char *glbuf;
static char tty, *bigfile;
static char fle[80];
static char prompt = 1;
static char verbose = 1; /* 1=print # of bytes read in; 0=silent. */
static char varray[10][100]; /* Holds xv cmd parameters. */
static double outcnt;
static char strtmp[32];
static void reset();
static void begin(struct Comd *p);
static int bigopen(char file[]);
static void sizeprt(int blk, int off);
static void bigread(int l, char rec[]);
static int gcomd(struct Comd *p, int k);
static int fcomd(struct Comd *p);
static void ecomd();
static int kcomd(struct Comd *p);
static int xncomd(struct Comd *p);
static int pcomd(struct Comd *p);
static int qcomd();
static int xcomds(struct Comd *p);
static int xbcomd(struct Comd *p);
static int xccomd(struct Comd *p);
static int xfcomd(struct Comd *p);
static int xocomd(struct Comd *p);
static int xtcomd(struct Comd *p);
static int xvcomd();
static int wcomd(struct Comd *p);
static int nlcomd(struct Comd *p);
static int eqcomd(struct Comd *p);
static int colcomd(struct Comd *p);
static int excomd();
static int xcomdlist(struct Comd *p);
static int defaults(struct Comd *p, int prt, int max,
int def1, int def2, int setdot, int errsok);
static int getcomd(struct Comd *p, int prt);
static int getadrs(struct Comd *p, int prt);
static int getadr(struct Comd *p, int prt);
static int getnumb(struct Comd *p, int prt);
static int rdnumb(int prt);
static int getrel(struct Comd *p, int prt);
static int getmark(struct Comd *p, int prt);
static int getrex(struct Comd *p, int prt, char c);
static int hunt(int prt, char rex[], int start, int down, int wrap, int errsok);
static int jump(int prt, char label[]);
static int getstr(int prt, char buf[], char brk, char ignr, int nonl);
static int regerr(int c);
static int err(int prt, char msg[]);
static char mygetc();
static int readc(int f, char *c);
static int percent(char line[256]);
static int newfile(int prt, char f[]);
static void push(int s[], int d);
static int pop(int s[]);
static int peekc();
static void eat();
static int more();
static void quit();
static void out(char *ln);
static char *untab(char l[]);
static int patoi(char *b);
static int equal(char *a, char *b);
void
main(int argc, char *argv[])
{
struct Comd comdstruct, *p;
(void) setlocale(LC_ALL, "");
if (argc < 2 || argc > 3) {
(void) err(1, "arg count");
quit();
}
mark = markarray-'a';
if (argc == 3) {
verbose = 0;
}
setbuf(stdout, 0);
if (bigopen(bigfile = argv[argc-1]))
quit();
tty = isatty(0);
p = &comdstruct;
/* Look for 0 or more non-'%' char followed by a '%' */
perbuf = compile("[^%]*%", (char *)0, (char *)0);
if (regerrno)
(void) regerr(regerrno);
(void) setjmp(env);
#if defined(__STDC__)
(void) signal(SIGINT, (void (*)(int))reset);
#else
(void) signal(SIGINT, reset);
#endif
(void) err(0, "");
(void) printf("\n");
flag = 0;
prompt = 0;
/*CONSTCOND*/ for (;;)
begin(p);
}
static void
reset() /* for longjmp on signal */
{
longjmp(env, 1);
}
static void
begin(struct Comd *p)
{
char line[256];
strtagn:
if (flag == 0)
eat();
if (infildes != 100) {
if (infildes == 0 && prompt)
(void) printf("*");
flag3 = 1;
if (getstr(1, line, 0, 0, 0))
exit(1);
flag3 = 0;
if (percent(line) < 0)
goto strtagn;
(void) newfile(1, "");
}
if (!(getcomd(p, 1) < 0)) {
switch (p->Cop) {
case 'e':
if (!flag)
ecomd();
else
(void) err(0, "");
break;
case 'f':
(void) fcomd(p);
break;
case 'g':
if (flag == 0)
(void) gcomd(p, 1);
else
(void) err(0, "");
break;
case 'k':
(void) kcomd(p);
break;
case 'p':
(void) pcomd(p);
break;
case 'q':
(void) qcomd();
break;
case 'v':
if (flag == 0)
(void) gcomd(p, 0);
else
(void) err(0, "");
break;
case 'x':
if (!flag)
(void) xcomds(p);
else
(void) err(0, "");
break;
case 'w':
(void) wcomd(p);
break;
case '\n':
(void) nlcomd(p);
break;
case '=':
(void) eqcomd(p);
break;
case ':':
(void) colcomd(p);
break;
case '!':
(void) excomd();
break;
case 'P':
prompt = !prompt;
break;
default:
if (flag)
(void) err(0, "");
else
(void) err(1, "bad command");
break;
}
}
}
static int
bigopen(char file[])
{
int l, off, cnt;
int blk, newline, n, s;
char block[512];
size_t totsiz;
BRKTYP *tptr;
if ((txtfd = open(file, 0)) < 0)
return (err(1, "can't open"));
blk = -1;
newline = 1;
l = cnt = s = 0;
off = 512;
totsiz = 0;
if ((lincnt = (BRKTYP *)malloc(BRKSIZ)) == (BRKTYP *)NULL)
return (err(1, "too many lines"));
endds = (BRKTYP *)lincnt;
totsiz += BRKSIZ;
while ((n = read(txtfd, block, 512)) > 0) {
blk++;
for (off = 0; off < n; off++) {
if (newline) {
newline = 0;
if (l > 0 && !(l&07777)) {
totsiz += BRKSIZ;
tptr = (BRKTYP *)
realloc(lincnt, totsiz);
if (tptr == NULL)
return
(err(1, "too many lines"));
else
lincnt = tptr;
}
lincnt[l] = (char)cnt;
cnt = 0;
if (!(l++ & 077)) {
segblk[s] = blk;
segoff[s++] = off;
}
if (l < 0 || l > 32767)
return (err(1, "too many lines"));
}
if (block[off] == '\n') newline = 1;
cnt++;
}
}
if (!(l&07777)) {
totsiz += BRKTWO;
tptr = (BRKTYP *)realloc(lincnt, totsiz);
if (tptr == NULL)
return (err(1, "too many lines"));
else
lincnt = tptr;
}
lincnt[Dot = Dollar = l] = (char)cnt;
sizeprt(blk, off);
return (0);
}
static void
sizeprt(int blk, int off)
{
if (verbose)
(void) printf("%.0f", 512.*blk+off);
}
static int saveblk = -1;
static void
bigread(int l, char rec[])
{
int i;
char *r, *b;
int off;
static char savetxt[512];
if ((i = l-lprev) == 1) prevoff += lincnt[lprev]BFSAND;
else if (i >= 0 && i <= 32)
for (i = lprev; i < l; i++) prevoff += lincnt[i]BFSAND;
else if (i < 0 && i >= -32)
for (i = lprev-1; i >= l; i--) prevoff -= lincnt[i]BFSAND;
else {
prevblk = segblk[i = (l-1)>>6];
prevoff = segoff[i];
for (i = (i<<6)+1; i < l; i++) prevoff += lincnt[i]BFSAND;
}
prevblk += prevoff>>9;
prevoff &= 0777;
lprev = l;
if (prevblk != saveblk) {
(void) lseek(txtfd, ((long)(saveblk = prevblk))<<9, 0);
(void) read(txtfd, savetxt, 512);
}
r = rec;
off = prevoff;
/*CONSTCOND*/while (1) {
for (b = savetxt+off; b < savetxt+512; b++) {
if ((*r++ = *b) == '\n') {
*(r-1) = '\0';
return;
}
if (((unsigned)r - (unsigned)rec) > BFSLIM) {
(void) write(2,
"Line too long--output truncated\n", 32);
return;
}
}
(void) read(txtfd, savetxt, 512);
off = 0;
saveblk++;
}
}
static void
ecomd()
{
int i = 0;
while (peekc() == ' ')
(void) mygetc();
while ((fle[i++] = mygetc()) != '\n');
fle[--i] = '\0';
/* Without this, ~20 "e" cmds gave "can't open" msg. */
(void) close(txtfd);
free(endds);
/* Reset parameters. */
lprev = 1;
prevblk = 0;
prevoff = 0;
saveblk = -1;
if (bigopen(bigfile = fle))
quit();
(void) printf("\n");
}
static int
fcomd(struct Comd *p)
{
if (more() || defaults(p, 1, 0, 0, 0, 0, 0))
return (-1);
(void) printf("%s\n", bigfile);
return (0);
}
static int
gcomd(struct Comd *p, int k)
{
char d;
int i, end;
char line[BFSBUF];
if (defaults(p, 1, 2, 1, Dollar, 0, 0))
return (-1);
if ((d = mygetc()) == '\n')
return (err(1, "syntax"));
if (peekc() == d)
(void) mygetc();
else
if (getstr(1, currex, d, 0, 1))
return (-1);
glbuf = compile(currex, (char *)0, (char *)0);
if (regerrno) {
(void) regerr(regerrno);
return (-1);
} else {
if (glbuf)
free(glbuf);
}
if (getstr(1, comdlist, 0, 0, 0))
return (-1);
i = p->Cadr[0];
end = p->Cadr[1];
while (i <= end) {
bigread(i, line);
if (!(step(line, glbuf))) {
if (!k) {
Dot = i;
if (xcomdlist(p))
return (err(1, "bad comd list"));
}
i++;
} else {
if (k) {
Dot = i;
if (xcomdlist(p))
return (err(1, "bad comd list"));
}
i++;
}
}
return (0);
}
static int
kcomd(struct Comd *p)
{
char c;
if ((c = peekc()) < 'a' || c > 'z')
return (err(1, "bad mark"));
(void) mygetc();
if (more() || defaults(p, 1, 1, Dot, 0, 1, 0))
return (-1);
mark[c] = Dot = p->Cadr[0];
return (0);
}
static int
xncomd(struct Comd *p)
{
char c;
if (more() || defaults(p, 1, 0, 0, 0, 0, 0))
return (-1);
for (c = 'a'; c <= 'z'; c++)
if (mark[c])
(void) printf("%c\n", c);
return (0);
}
static int
pcomd(struct Comd *p)
{
int i;
char line[BFSBUF];
if (more() || defaults(p, 1, 2, Dot, Dot, 1, 0))
return (-1);
for (i = p->Cadr[0]; i <= p->Cadr[1] && i > 0; i++) {
bigread(i, line);
out(line);
}
return (0);
}
static int
qcomd()
{
if (more())
return (-1);
quit();
return (0);
}
static int
xcomds(struct Comd *p)
{
switch (mygetc()) {
case 'b': return (xbcomd(p));
case 'c': return (xccomd(p));
case 'f': return (xfcomd(p));
case 'n': return (xncomd(p));
case 'o': return (xocomd(p));
case 't': return (xtcomd(p));
case 'v': return (xvcomd());
default: return (err(1, "bad command"));
}
}
static int
xbcomd(struct Comd *p)
{
int fail, n;
char d;
char str[50];
fail = 0;
if (defaults(p, 0, 2, Dot, Dot, 0, 1))
fail = 1;
else {
if ((d = mygetc()) == '\n')
return (err(1, "syntax"));
if (d == 'z') {
if (status[0] != 0)
return (0);
(void) mygetc();
if (getstr(1, str, 0, 0, 0))
return (-1);
return (jump(1, str));
}
if (d == 'n') {
if (status[0] == 0)
return (0);
(void) mygetc();
if (getstr(1, str, 0, 0, 0))
return (-1);
return (jump(1, str));
}
if (getstr(1, str, d, ' ', 0))
return (-1);
if ((n = hunt(0, str, p->Cadr[0]-1, 1, 0, 1)) < 0)
fail = 1;
if (getstr(1, str, 0, 0, 0))
return (-1);
if (more())
return (err(1, "syntax"));
}
if (!fail) {
Dot = n;
return (jump(1, str));
}
return (0);
}
static int
xccomd(struct Comd *p)
{
char arg[100];
if (getstr(1, arg, 0, ' ', 0) || defaults(p, 1, 0, 0, 0, 0, 0))
return (-1);
if (equal(arg, ""))
crunch = -crunch;
else if (equal(arg, "0"))
crunch = -1;
else if (equal(arg, "1"))
crunch = 1;
else
return (err(1, "syntax"));
return (0);
}
static int
xfcomd(struct Comd *p)
{
char fl[100];
char *f;
if (defaults(p, 1, 0, 0, 0, 0, 0))
return (-1);
while (peekc() == ' ')
(void) mygetc();
for (f = fl; (*f = mygetc()) != '\n'; f++);
if (f == fl)
return (err(1, "no file"));
*f = '\0';
return (newfile(1, fl));
}
static int
xocomd(struct Comd *p)
{
int fd;
char arg[100];
if (getstr(1, arg, 0, ' ', 0) || defaults(p, 1, 0, 0, 0, 0, 0))
return (-1);
if (!arg[0]) {
if (outfildes == 1)
return (err(1, "no diversion"));
(void) close(outfildes);
outfildes = 1;
} else {
if (outfildes != 1)
return (err(1, "already diverted"));
if ((fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC,
(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))) < 0)
return (err(1, "can't create"));
outfildes = fd;
}
return (0);
}
static int
xtcomd(struct Comd *p)
{
int t;
while (peekc() == ' ')
(void) mygetc();
if ((t = rdnumb(1)) < 0 || more() || defaults(p, 1, 0, 0, 0, 0, 0))
return (-1);
trunc = t;
return (0);
}
static int
xvcomd()
{
char c;
int i;
int temp0, temp1, temp2;
int fildes[2];
if ((c = peekc()) < '0' || c > '9')
return (err(1, "digit required"));
(void) mygetc();
c -= '0';
while (peekc() == ' ')
(void) mygetc();
if (peekc() == '\\')
(void) mygetc();
else if (peekc() == '!') {
if (pipe(fildes) < 0) {
(void) printf("Try again");
return (-1);
}
temp0 = dup(0);
temp1 = dup(1);
temp2 = infildes;
(void) close(0);
(void) dup(fildes[0]);
(void) close(1);
(void) dup(fildes[1]);
(void) close(fildes[0]);
(void) close(fildes[1]);
(void) mygetc();
flag4 = 1;
(void) excomd();
(void) close(1);
infildes = 0;
}
for (i = 0; (varray[c][i] = mygetc()) != '\n'; i++);
varray[c][i] = '\0';
if (flag4) {
infildes = temp2;
(void) close(0);
(void) dup(temp0);
(void) close(temp0);
(void) dup(temp1);
(void) close(temp1);
flag4 = 0;
charbuf = ' ';
}
return (0);
}
static int
wcomd(struct Comd *p)
{
int i, fd, savefd;
int savecrunch, savetrunc;
char arg[100], line[BFSBUF];
if (getstr(1, arg, 0, ' ', 0) || defaults(p, 1, 2, 1, Dollar, 1, 0))
return (-1);
if (!arg[0])
return (err(1, "no file name"));
if (equal(arg, bigfile))
return (err(1, "no change indicated"));
if ((fd = open(arg, O_WRONLY|O_CREAT|O_TRUNC,
(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH))) < 0)
return (err(1, "can't create"));
savefd = outfildes;
savetrunc = trunc;
savecrunch = crunch;
outfildes = fd;
trunc = BFSTRU;
crunch = -1;
outcnt = 0;
for (i = p->Cadr[0]; i <= p->Cadr[1] && i > 0; i++) {
bigread(i, line);
out(line);
}
if (verbose)
(void) printf("%.0f\n", outcnt);
(void) close(fd);
outfildes = savefd;
trunc = savetrunc;
crunch = savecrunch;
return (0);
}
static int
nlcomd(struct Comd *p)
{
if (defaults(p, 1, 2, Dot+1, Dot+1, 1, 0)) {
(void) mygetc();
return (-1);
}
return (pcomd(p));
}
static int
eqcomd(struct Comd *p)
{
if (more() || defaults(p, 1, 1, Dollar, 0, 0, 0))
return (-1);
(void) printf("%d\n", p->Cadr[0]);
return (0);
}
static int
colcomd(struct Comd *p)
{
return (defaults(p, 1, 0, 0, 0, 0, 0));
}
static int
xcomdlist(struct Comd *p)
{
flag = 1;
flag2 = 1;
(void) newfile(1, "");
while (flag2)
begin(p);
if (flag == 0)
return (1);
flag = 0;
return (0);
}
static int
excomd()
{
pid_t i;
int j;
if (infildes != 100)
charbuf = '\n';
while ((i = fork()) < (pid_t)0)
(void) sleep(10);
if (i == (pid_t)0) {
/* Guarantees child can be intr. */
(void) signal(SIGINT, SIG_DFL);
if (infildes == 100 || flag4) {
(void) execl("/usr/bin/sh", "sh", "-c", intptr, 0);
exit(0);
}
if (infildes != 0) {
(void) close(0);
(void) dup(infildes);
}
for (j = 3; j < 15; j++) (void) close(j);
(void) execl("/usr/bin/sh", "sh", "-t", 0);
exit(0);
}
(void) signal(SIGINT, SIG_IGN);
while (wait(status) != i);
status[0] = status[0] >> 8;
#if defined(__STDC__)
(void) signal(SIGINT, (void (*)(int))reset);
#else
(void) signal(SIGINT, reset); /* Restore signal to previous status */
#endif
if (((infildes == 0) || ((infildes == 100) &&
(fstack[fstack[0]] == 0)))&& verbose && (!flag4))
(void) printf("!\n");
return (0);
}
static int
defaults(struct Comd *p, int prt, int max,
int def1, int def2, int setdot, int errsok)
{
if (!def1)
def1 = Dot;
if (!def2)
def2 = def1;
if (p->Cnumadr >= max)
return (errsok?-1:err(prt, "adr count"));
if (p->Cnumadr < 0) {
p->Cadr[++p->Cnumadr] = def1;
p->Cadr[++p->Cnumadr] = def2;
} else if (p->Cnumadr < 1)
p->Cadr[++p->Cnumadr] = p->Cadr[0];
if (p->Cadr[0] < 1 || p->Cadr[0] > Dollar ||
p->Cadr[1] < 1 || p->Cadr[1] > Dollar)
return (errsok?-1:err(prt, "range"));
if (p->Cadr[0] > p->Cadr[1])
return (errsok?-1:err(prt, "adr1 > adr2"));
if (setdot)
Dot = p->Cadr[1];
return (0);
}
static int
getcomd(struct Comd *p, int prt)
{
int r;
int c;
p->Cnumadr = -1;
p->Csep = ' ';
switch (c = peekc()) {
case ',':
case ';': p->Cop = mygetc();
return (0);
}
if ((r = getadrs(p, prt)) < 0)
return (r);
if ((c = peekc()) < 0)
return (err(prt, "syntax"));
if (c == '\n')
p->Cop = '\n';
else
p->Cop = mygetc();
return (0);
}
static int
getadrs(struct Comd *p, int prt)
{
int r;
char c;
if ((r = getadr(p, prt)) < 0)
return (r);
switch (c = peekc()) {
case ';':
Dot = p->Cadr[0];
(void) mygetc();
p->Csep = c;
return (getadr(p, prt));
case ',':
(void) mygetc();
p->Csep = c;
return (getadr(p, prt));
}
return (0);
}
static int
getadr(struct Comd *p, int prt)
{
int r;
char c;
r = 0;
while (peekc() == ' ')
(void) mygetc(); /* Ignore leading spaces */
switch (c = peekc()) {
case '\n':
case ',':
case ';': return (0);
case '\'': (void) mygetc();
r = getmark(p, prt);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': r = getnumb(p, prt);
break;
case '.': (void) mygetc();
p->Cadr[++p->Cnumadr] = Dot;
break;
case '+':
case '-': p->Cadr[++p->Cnumadr] = Dot;
break;
case '$': (void) mygetc();
p->Cadr[++p->Cnumadr] = Dollar;
break;
case '^': (void) mygetc();
p->Cadr[++p->Cnumadr] = Dot - 1;
break;
case '/':
case '?':
case '>':
case '<': (void) mygetc();
r = getrex(p, prt, c);
break;
default: return (0);
}
if (r == 0)
r = getrel(p, prt);
return (r);
}
static int
getnumb(struct Comd *p, int prt)
{
int i;
if ((i = rdnumb(prt)) < 0)
return (-1);
p->Cadr[++p->Cnumadr] = i;
return (0);
}
static int
rdnumb(int prt)
{
char num[20], *n;
int i;
n = num;
while ((*n = peekc()) >= '0' && *n <= '9') {
n++;
(void) mygetc();
}
*n = '\0';
if ((i = patoi(num)) >= 0)
return (i);
return (err(prt, "bad num"));
}
static int
getrel(struct Comd *p, int prt)
{
int op, n;
char c;
int j;
n = 0;
op = 1;
while ((c = peekc()) == '+' || c == '-') {
if (c == '+')
n++;
else
n--;
(void) mygetc();
}
j = n;
if (n < 0)
op = -1;
if (c == '\n')
p->Cadr[p->Cnumadr] += n;
else {
if ((n = rdnumb(0)) > 0 && p->Cnumadr >= 0) {
p->Cadr[p->Cnumadr] += op*n;
(void) getrel(p, prt);
} else {
p->Cadr[p->Cnumadr] += j;
}
}
return (0);
}
static int
getmark(struct Comd *p, int prt)
{
char c;
if ((c = peekc()) < 'a' || c > 'z')
return (err(prt, "bad mark"));
(void) mygetc();
if (!mark[c])
return (err(prt, "undefined mark"));
p->Cadr[++p->Cnumadr] = mark[c];
return (0);
}
static int
getrex(struct Comd *p, int prt, char c)
{
int down, wrap, start;
if (peekc() == c)
(void) mygetc();
else if (getstr(prt, currex, c, 0, 1))
return (-1);
switch (c) {
case '/': down = 1; wrap = 1; break;
case '?': down = 0; wrap = 1; break;
case '>': down = 1; wrap = 0; break;
case '<': down = 0; wrap = 0; break;
}
if (p->Csep == ';')
start = p->Cadr[0];
else
start = Dot;
if ((p->Cadr[++p->Cnumadr] = hunt(prt, currex, start, down, wrap, 0))
< 0)
return (-1);
return (0);
}
static int
hunt(int prt, char rex[], int start, int down, int wrap, int errsok)
{
int i, end1, incr;
int start1, start2;
char line[BFSBUF];
if (down) {
start1 = start + 1;
end1 = Dollar;
start2 = 1;
incr = 1;
} else {
start1 = start - 1;
end1 = 1;
start2 = Dollar;
incr = -1;
}
rebuf = compile(rex, (char *)0, (char *)0);
if (regerrno)
(void) regerr(regerrno);
else
if (rebuf)
free(rebuf);
for (i = start1; i != end1+incr; i += incr) {
bigread(i, line);
if (step(line, rebuf)) {
return (i);
}
}
if (!wrap)
return (errsok?-1:err(prt, "not found"));
for (i = start2; i != start1; i += incr) {
bigread(i, line);
if (step(line, rebuf)) {
return (i);
}
}
return (errsok?-1:err(prt, "not found"));
}
static int
jump(int prt, char label[])
{
char *l;
char line[256];
if (infildes == 0 && tty)
return (err(prt, "jump on tty"));
if (infildes == 100)
intptr = internal;
else
(void) lseek(infildes, 0L, 0);
(void) snprintf(strtmp,
sizeof (strtmp) * sizeof (char), "^: *%s$", label);
rebuf = compile(strtmp, (char *)0, (char *)0);
if (regerrno) {
(void) regerr(regerrno);
return (-1);
}
for (l = line; readc(infildes, l); l++) {
if (*l == '\n') {
*l = '\0';
if (step(line, rebuf)) {
charbuf = '\n';
return (peeked = 0);
}
l = line - 1;
}
}
return (err(prt, "label not found"));
}
static int
getstr(int prt, char buf[], char brk, char ignr, int nonl)
{
char *b, c, prevc;
prevc = 0;
for (b = buf; c = peekc(); prevc = c) {
if (c == '\n') {
if (prevc == '\\' && (!flag3)) *(b-1) = mygetc();
else if (prevc == '\\' && flag3) {
*b++ = mygetc();
} else if (nonl)
break;
else
return (*b = '\0');
} else {
(void) mygetc();
if (c == brk) {
if (prevc == '\\') *(b-1) = c;
else return (*b = '\0');
} else if (b != buf || c != ignr) *b++ = c;
}
}
return (err(prt, "syntax"));
}
static int
regerr(int c)
{
if (prompt) {
switch (c) {
case 11: (void) printf("Range endpoint too large.\n");
break;
case 16: (void) printf("Bad number.\n");
break;
case 25: (void) printf("``\\digit'' out of range.\n");
break;
case 41: (void) printf("No remembered search string.\n");
break;
case 42: (void) printf("() imbalance.\n");
break;
case 43: (void) printf("Too many (.\n");
break;
case 44: (void) printf("More than 2 numbers given in { }.\n");
break;
case 45: (void) printf("} expected after \\.\n");
break;
case 46: (void) printf("First number exceeds second in { }.\n");
break;
case 49: (void) printf("[] imbalance.\n");
break;
case 50: (void) printf("Regular expression overflow.\n");
break;
case 67: (void) printf("Illegal byte sequence.\n");
break;
default: (void) printf("RE error.\n");
break;
}
} else {
(void) printf("?\n");
}
return (-1);
}
static int
err(int prt, char msg[])
{
if (prt) (prompt? (void) printf("%s\n", msg): (void) printf("?\n"));
if (infildes != 0) {
infildes = pop(fstack);
charbuf = '\n';
peeked = 0;
flag3 = 0;
flag2 = 0;
flag = 0;
}
return (-1);
}
static char
mygetc()
{
if (!peeked) {
while ((!(infildes == oldfd && flag)) && (!flag1) &&
(!readc(infildes, &charbuf))) {
if (infildes == 100 && (!flag)) flag1 = 1;
if ((infildes = pop(fstack)) == -1) quit();
if ((!flag1) && infildes == 0 && flag3 && prompt)
(void) printf("*");
}
if (infildes == oldfd && flag) flag2 = 0;
flag1 = 0;
} else peeked = 0;
return (charbuf);
}
static int
readc(int f, char *c)
{
if (f == 100) {
if (!(*c = *intptr++)) {
intptr--;
charbuf = '\n';
return (0);
}
} else if (read(f, c, 1) != 1) {
(void) close(f);
charbuf = '\n';
return (0);
}
return (1);
}
static int
percent(char line[256])
{
char *lp, *var;
char *front, *per, c[2], *olp, p[2], fr[256];
int i, j;
per = p;
var = c;
front = fr;
j = 0;
while (!j) {
j = 1;
olp = line;
intptr = internal;
while (step(olp, perbuf)) {
while (loc1 < loc2) *front++ = *loc1++;
*(--front) = '\0';
front = fr;
*per++ = '%';
*per = '\0';
per = p;
*var = *loc2;
if ((i = 1 + strlen(front)) >= 2 && fr[i-2] == '\\') {
(void) strcat(front, "");
--intptr;
(void) strcat(per, "");
} else {
if (!(*var >= '0' && *var <= '9'))
return (err(1, "usage: %digit"));
(void) strcat(front, "");
(void) strcat(varray[*var-'0'], "");
j = 0;
loc2++; /* Compensate for removing --lp above */
}
olp = loc2;
}
(void) strcat(olp, "");
*intptr = '\0';
if (!j) {
intptr = internal;
lp = line;
(void)
strncpy(intptr, lp, sizeof (intptr)*sizeof (char));
}
}
return (0);
}
static int
newfile(int prt, char f[])
{
int fd;
if (!*f) {
if (flag != 0) {
oldfd = infildes;
intptr = comdlist;
} else intptr = internal;
fd = 100;
} else if ((fd = open(f, 0)) < 0) {
(void) snprintf(strtmp, sizeof (strtmp) * sizeof (char),
"cannot open %s", f);
return (err(prt, strtmp));
}
push(fstack, infildes);
if (flag4) oldfd = fd;
infildes = fd;
return (peeked = 0);
}
static void
push(int s[], int d)
{
s[++s[0]] = d;
}
static int
pop(int s[])
{
return (s[s[0]--]);
}
static int
peekc()
{
int c;
c = mygetc();
peeked = 1;
return (c);
}
static void
eat()
{
if (charbuf != '\n')
while (mygetc() != '\n');
peeked = 0;
}
static int
more()
{
if (mygetc() != '\n')
return (err(1, "syntax"));
return (0);
}
static void
quit()
{
exit(0);
}
static void
out(char *ln)
{
char *rp, *wp, prev;
int w, width;
char *oldrp;
wchar_t cl;
int p;
ptrdiff_t lim;
if (crunch > 0) {
ln = untab(ln);
rp = wp = ln - 1;
prev = ' ';
while (*++rp) {
if (prev != ' ' || *rp != ' ')
*++wp = *rp;
prev = *rp;
}
*++wp = '\n';
lim = (ptrdiff_t)wp - (ptrdiff_t)ln;
*++wp = '\0';
if (*ln == '\n')
return;
} else
ln[lim = strlen(ln)] = '\n';
if (MB_CUR_MAX <= 1) {
if (lim > trunc)
ln[lim = trunc] = '\n';
} else {
if ((trunc < (BFSBUF -1)) || (lim > trunc)) {
w = 0;
oldrp = rp = ln;
/*CONSTCOND*/while (1) {
if ((p = mbtowc(&cl, rp, MB_LEN_MAX)) == 0) {
break;
}
if (p == -1) {
width = p = 1;
} else {
width = scrwidth(cl);
if (width == 0)
width = 1;
}
if ((w += width) > trunc)
break;
rp += p;
}
*rp = '\n';
lim = (ptrdiff_t)rp - (ptrdiff_t)oldrp;
}
}
outcnt += write(outfildes, ln, lim+1);
}
static char *
untab(char l[])
{
static char line[BFSBUF];
char *q, *s;
s = l;
q = line;
do {
if (*s == '\t')
do
*q++ = ' ';
while (((ptrdiff_t)q-(ptrdiff_t)line)%8);
else *q++ = *s;
} while (*s++);
return (line);
}
/*
* Function to convert ascii string to integer. Converts
* positive numbers only. Returns -1 if non-numeric
* character encountered.
*/
static int
patoi(char *b)
{
int i;
char *a;
a = b;
i = 0;
while (*a >= '0' && *a <= '9') i = 10 * i + *a++ - '0';
if (*a)
return (-1);
return (i);
}
/*
* Compares 2 strings. Returns 1 if equal, 0 if not.
*/
static int
equal(char *a, char *b)
{
char *x, *y;
x = a;
y = b;
while (*x == *y++)
if (*x++ == 0)
return (1);
return (0);
}