Today's changes.

More changes.
This commit is contained in:
rsc 2004-03-25 23:03:57 +00:00
parent cb27443abf
commit 8ad517944e
73 changed files with 2865 additions and 1293 deletions

View file

@ -1150,7 +1150,7 @@ rewritehdr(Fcall *f, uchar *pkt)
}
}
#ifdef _LIB9_H_
#ifdef _LIBC_H_
/* unix select-based polling */
struct Ioproc
{

View file

@ -1,15 +1,24 @@
#include "9term.h"
#define fatal sysfatal
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <cursor.h>
#include <keyboard.h>
#include <frame.h>
#include <plumb.h>
#include <complete.h>
#include "term.h"
typedef struct Text Text;
typedef struct Readbuf Readbuf;
enum
{
/* these are chosen to use malloc()'s properties well */
HiWater = 640000, /* max size of history */
LoWater = 330000, /* min size of history after max'ed */
LoWater = 400000, /* min size of history after max'ed */
MinWater = 20000,
};
/* various geometric paramters */
@ -30,21 +39,22 @@ enum
Scroll,
};
#define SCROLLKEY Kdown
#define ESC 0x1B
#define CUT 0x18 /* ctrl-x */
#define COPY 0x03 /* crtl-c */
#define PASTE 0x16 /* crtl-v */
#define BACKSCROLLKEY Kup
#define CUT 0x18 /* ctrl-x */
#define COPY 0x03 /* crtl-c */
#define PASTE 0x16 /* crtl-v */
#define READBUFSIZE 8192
#define TRUE 1
#define FALSE 0
struct Text
{
Frame *f; /* frame ofr terminal */
Mouse m;
uint nr; /* num of runes in term */
uint maxr; /* max num of runes in r */
Rune *r; /* runes for term */
uint nraw; /* num of runes in raw buffer */
Rune *raw; /* raw buffer */
@ -72,7 +82,6 @@ void fill(void);
void tcheck(void);
void updatesel(void);
void doreshape(void);
void rcstart(int fd[2], int, char**);
void runewrite(Rune*, int);
void consread(void);
void conswrite(char*, int);
@ -99,11 +108,10 @@ void scrdraw(void);
void scroll(int);
void hostproc(void *arg);
void hoststart(void);
int getchildwd(int, char*, int);
void plumbstart(void);
void plumb(uint, uint);
void plumbclick(uint*, uint*);
int getpts(int fd[], char *slave);
uint insert(Rune*, int, uint, int);
#define runemalloc(n) malloc((n)*sizeof(Rune))
#define runerealloc(a, n) realloc(a, (n)*sizeof(Rune))
@ -115,7 +123,7 @@ int rawon; /* raw mode */
int scrolling; /* window scrolls */
int clickmsec; /* time of last click */
uint clickq0; /* point of last click */
int rcfd[2];
int rcfd;
int rcpid;
int maxtab;
int use9wm;
@ -211,7 +219,7 @@ threadmain(int argc, char *argv[])
mc = initmouse(nil, screen);
kc = initkeyboard(nil);
rcstart(rcfd, argc, argv);
rcpid = rcstart(argc, argv, &rcfd);
hoststart();
plumbstart();
@ -265,8 +273,9 @@ hostproc(void *arg)
i = 0;
for(;;){
/* Let typing have a go -- maybe there's a rubout waiting. */
i = 1-i; /* toggle */
n = threadread(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
n = threadread(rcfd, rcbuf[i].data, sizeof rcbuf[i].data);
if(n <= 0){
if(n < 0)
fprint(2, "9term: host read error: %r\n");
@ -308,7 +317,7 @@ loop(void)
a[2].op = CHANNOP;;
switch(alt(a)) {
default:
fatal("impossible");
sysfatal("impossible");
case 0:
t.m = mc->m;
mouse();
@ -330,23 +339,23 @@ void
doreshape(void)
{
if(getwindow(display, Refnone) < 0)
fatal("can't reattach to window");
sysfatal("can't reattach to window");
draw(screen, screen->r, cols[BACK], nil, ZP);
geom();
scrdraw();
}
struct winsize ows;
void
geom(void)
{
struct winsize ws;
Point p;
Rectangle r;
r = screen->r;
scrollr = screen->r;
r.min.y++;
r.max.y--;
scrollr = r;
scrollr.max.x = r.min.x+Scrollwid;
lastsr = Rect(0,0,0,0);
@ -362,13 +371,7 @@ geom(void)
if(p.x == 0 || p.y == 0)
return;
ws.ws_row = Dy(r)/p.y;
ws.ws_col = Dx(r)/p.x;
ws.ws_xpixel = Dx(r);
ws.ws_ypixel = Dy(r);
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
fprint(2, "ioctl: %r\n");
updatewinsize(Dy(r)/p.y, Dx(r)/p.x, Dx(r), Dy(r));
}
void
@ -585,7 +588,10 @@ domenu2(int but)
show(t.q0);
break;
case Send:
snarf();
if(t.q0 != t.q1)
snarf();
else
snarfupdate();
t.q0 = t.q1 = t.nr;
updatesel();
paste(t.snarf, t.nsnarf, 1);
@ -605,37 +611,182 @@ domenu2(int but)
plumb(t.q0, t.q1);
break;
default:
fatal("bad menu item");
sysfatal("bad menu item");
}
}
int
windfilewidth(uint q0, int oneelement)
{
uint q;
Rune r;
q = q0;
while(q > 0){
r = t.r[q-1];
if(r<=' ')
break;
if(oneelement && r=='/')
break;
--q;
}
return q0-q;
}
void
showcandidates(Completion *c)
{
int i;
Fmt f;
Rune *rp;
uint nr, qline, q0;
char *s;
runefmtstrinit(&f);
if (c->nmatch == 0)
s = "[no matches in ";
else
s = "[";
if(c->nfile > 32)
fmtprint(&f, "%s%d files]\n", s, c->nfile);
else{
fmtprint(&f, "%s", s);
for(i=0; i<c->nfile; i++){
if(i > 0)
fmtprint(&f, " ");
fmtprint(&f, "%s", c->filename[i]);
}
fmtprint(&f, "]\n");
}
/* place text at beginning of line before host point */
qline = t.qh;
while(qline>0 && t.r[qline-1] != '\n')
qline--;
rp = runefmtstrflush(&f);
nr = runestrlen(rp);
q0 = t.q0;
q0 += insert(rp, nr, qline, 0) - qline;
free(rp);
t.q0 = q0+nr;
t.q1 = q0+nr;
updatesel();
}
Rune*
namecomplete(void)
{
int nstr, npath;
Rune *rp, *path, *str;
Completion *c;
char *s, *dir, *root;
/* control-f: filename completion; works back to white space or / */
if(t.q0<t.nr && t.r[t.q0]>' ') /* must be at end of word */
return nil;
nstr = windfilewidth(t.q0, TRUE);
str = runemalloc(nstr);
runemove(str, t.r+(t.q0-nstr), nstr);
npath = windfilewidth(t.q0-nstr, FALSE);
path = runemalloc(npath);
runemove(path, t.r+(t.q0-nstr-npath), npath);
rp = nil;
/* is path rooted? if not, we need to make it relative to window path */
if(npath>0 && path[0]=='/'){
dir = malloc(UTFmax*npath+1);
sprint(dir, "%.*S", npath, path);
}else{
if(strcmp(wdir, "") == 0)
root = ".";
else
root = wdir;
dir = malloc(strlen(root)+1+UTFmax*npath+1);
sprint(dir, "%s/%.*S", root, npath, path);
}
dir = cleanname(dir);
s = smprint("%.*S", nstr, str);
c = complete(dir, s);
free(s);
if(c == nil)
goto Return;
if(!c->advance)
showcandidates(c);
if(c->advance)
rp = runesmprint("%s", c->string);
Return:
freecompletion(c);
free(dir);
free(path);
free(str);
return rp;
}
void
key(Rune r)
{
uint sig;
Rune *rp;
int nr;
if(r == 0)
return;
if(r==SCROLLKEY){ /* scroll key */
switch(r){
case Kpgup:
setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
return;
case Kpgdown:
setorigin(line2q(t.f->maxlines*2/3), 1);
if(t.qh<=t.org+t.f->nchars)
consread();
return;
}else if(r == BACKSCROLLKEY){
setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
case Kup:
setorigin(backnl(t.org, t.f->maxlines/3), 1);
return;
}else if(r == CUT){
case Kdown:
setorigin(line2q(t.f->maxlines/3), 1);
if(t.qh<=t.org+t.f->nchars)
consread();
return;
case Kleft:
if(t.q0 > 0){
t.q0--;
t.q1 = t.q0;
updatesel();
show(t.q0);
}
return;
case Kright:
if(t.q1 < t.nr){
t.q1++;
t.q0 = t.q1;
updatesel();
show(t.q1);
}
return;
case Khome:
show(0);
return;
case Kend:
case 0x05:
show(t.nr);
return;
case CUT:
snarf();
cut();
if(scrolling)
show(t.q0);
return;
}else if(r == COPY){
case COPY:
snarf();
if(scrolling)
show(t.q0);
return;
}else if(r == PASTE){
case PASTE:
snarfupdate();
paste(t.snarf, t.nsnarf, 0);
if(scrolling)
@ -661,19 +812,21 @@ key(Rune r)
snarf();
switch(r) {
case 0x03: /* ^C: send interrupt */
case 0x7F: /* DEL: send interrupt */
t.qh = t.q0 = t.q1 = t.nr;
show(t.q0);
goto Default;
fprint(2, "send interrupt to %d group\n", rcpid);
#ifdef TIOCSIG
sig = 2; /* SIGINT */
if(ioctl(rcfd[0], TIOCSIG, &sig) < 0)
fprint(2, "sending interrupt: %r\n");
#else
postnote(PNGROUP, rcpid, "interrupt");
#endif
write(rcfd, "\x7F", 1);
break;
case 0x06: /* ^F: file name completion */
case Kins: /* Insert: file name completion */
rp = namecomplete();
if(rp == nil)
return;
nr = runestrlen(rp);
paste(rp, nr, 1);
free(rp);
return;
case 0x08: /* ^H: erase character */
case 0x15: /* ^U: erase line */
case 0x17: /* ^W: erase word */
@ -682,7 +835,6 @@ fprint(2, "send interrupt to %d group\n", rcpid);
cut();
break;
default:
Default:
paste(&r, 1, 1);
break;
}
@ -773,7 +925,7 @@ consread(void)
}
/* take out control-d when not doing a zero length write */
n = p-buf;
if(write(rcfd[1], buf, n) < 0)
if(write(rcfd, buf, n) < 0)
exits(0);
/* mallocstats(); */
}
@ -833,7 +985,6 @@ conswrite(char *p, int n)
void
runewrite(Rune *r, int n)
{
uint m;
int i;
uint initial;
uint q0, q1;
@ -896,37 +1047,7 @@ runewrite(Rune *r, int n)
updatesel();
}
if(t.nr>HiWater && t.qh>=t.org){
m = HiWater-LoWater;
if(m > t.org);
m = t.org;
t.org -= m;
t.qh -= m;
if(t.q0 > m)
t.q0 -= m;
else
t.q0 = 0;
if(t.q1 > m)
t.q1 -= m;
else
t.q1 = 0;
t.nr -= m;
runemove(t.r, t.r+m, t.nr);
}
t.r = runerealloc(t.r, t.nr+n);
runemove(t.r+t.qh+n, t.r+t.qh, t.nr-t.qh);
runemove(t.r+t.qh, r, n);
t.nr += n;
if(t.qh < t.org)
t.org += n;
else if(t.qh <= t.f->nchars+t.org)
frinsert(t.f, r, r+n, t.qh-t.org);
if (t.qh <= t.q0)
t.q0 += n;
if (t.qh <= t.q1)
t.q1 += n;
t.qh += n;
updatesel();
insert(r, n, t.qh, 1);
}
@ -1009,12 +1130,83 @@ snarf(void)
putsnarf(sbuf);
}
uint
min(uint x, uint y)
{
if(x < y)
return x;
return y;
}
uint
max(uint x, uint y)
{
if(x > y)
return x;
return y;
}
uint
insert(Rune *r, int n, uint q0, int hostwrite)
{
uint m;
if(n == 0)
return q0;
if(t.nr+n>HiWater && q0>=t.org && q0>=t.qh){
m = min(HiWater-LoWater, min(t.org, t.qh));
t.org -= m;
t.qh -= m;
if(t.q0 > m)
t.q0 -= m;
else
t.q0 = 0;
if(t.q1 > m)
t.q1 -= m;
else
t.q1 = 0;
t.nr -= m;
runemove(t.r, t.r+m, t.nr);
q0 -= m;
}
if(t.nr+n > t.maxr){
/*
* Minimize realloc breakage:
* Allocate at least MinWater
* Double allocation size each time
* But don't go much above HiWater
*/
m = max(min(2*(t.nr+n), HiWater), t.nr+n)+MinWater;
if(m > HiWater)
m = max(HiWater+MinWater, t.nr+n);
if(m > t.maxr){
t.r = runerealloc(t.r, m);
t.maxr = m;
}
}
runemove(t.r+q0+n, t.r+q0, t.nr-q0);
runemove(t.r+q0, r, n);
t.nr += n;
/* if output touches, advance selection, not qh; works best for keyboard and output */
if(q0 <= t.q1)
t.q1 += n;
if(q0 <= t.q0)
t.q0 += n;
if(q0 < t.qh || (q0==t.qh && hostwrite))
t.qh += n;
else
consread();
if(q0 < t.org)
t.org += n;
else if(q0 <= t.org+t.f->nchars)
frinsert(t.f, r, r+n, q0-t.org);
return q0;
}
void
paste(Rune *r, int n, int advance)
{
Rune *rbuf;
uint m;
uint q0;
if(rawon && t.q0==t.nr){
addraw(r, n);
@ -1024,6 +1216,7 @@ paste(Rune *r, int n, int advance)
cut();
if(n == 0)
return;
/*
* if this is a button2 execute then we might have been passed
* runes inside the buffer. must save them before realloc.
@ -1035,36 +1228,7 @@ paste(Rune *r, int n, int advance)
r = rbuf;
}
if(t.nr>HiWater && t.q0>=t.org && t.q0>=t.qh){
m = HiWater-LoWater;
if(m > t.org)
m = t.org;
if(m > t.qh);
m = t.qh;
t.org -= m;
t.qh -= m;
t.q0 -= m;
t.q1 -= m;
t.nr -= m;
runemove(t.r, t.r+m, t.nr);
}
t.r = runerealloc(t.r, t.nr+n);
q0 = t.q0;
runemove(t.r+q0+n, t.r+q0, t.nr-q0);
runemove(t.r+q0, r, n);
t.nr += n;
if(q0 < t.qh)
t.qh += n;
else
consread();
if(q0 < t.org)
t.org += n;
else if(q0 <= t.f->nchars+t.org)
frinsert(t.f, r, r+n, q0-t.org);
if(advance)
t.q0 += n;
t.q1 += n;
insert(r, n, t.q0, 0);
updatesel();
free(rbuf);
}
@ -1321,61 +1485,6 @@ clickmatch(int cl, int cr, int dir, uint *q)
return cl=='\n' && nest==1;
}
void
rcstart(int fd[2], int argc, char **argv)
{
int pid;
char *xargv[3];
char slave[256];
int sfd;
if(argc == 0){
argc = 2;
argv = xargv;
argv[0] = getenv("SHELL");
if(argv[0] == 0)
argv[0] = "rc";
argv[1] = "-i";
argv[2] = 0;
}
/*
* fd0 is slave (tty), fd1 is master (pty)
*/
fd[0] = fd[1] = -1;
if(getpts(fd, slave) < 0)
fprint(2, "getpts: %r\n");
switch(pid = fork()) {
case 0:
putenv("TERM", "9term");
close(fd[1]);
setsid();
// tcsetpgrp(0, pid);
sfd = open(slave, ORDWR);
if(sfd < 0)
fprint(2, "open %s: %r\n", slave);
if(ioctl(sfd, TIOCSCTTY, 0) < 0)
fprint(2, "ioctl TIOCSCTTY: %r\n");
// ioctl(sfd, I_PUSH, "ptem");
// ioctl(sfd, I_PUSH, "ldterm");
dup(sfd, 0);
dup(sfd, 1);
dup(sfd, 2);
system("stty tabs -onlcr -echo erase ^h intr ^?");
execvp(argv[0], argv);
fprint(2, "exec %s failed: %r\n", argv[0]);
_exits("oops");
break;
case -1:
fatal("proc failed: %r");
break;
}
close(fd[0]);
fd[0] = fd[1];
rcpid = pid;
}
void
tcheck(void)
{
@ -1421,7 +1530,7 @@ scrdraw(void)
freeimage(scrx);
scrx = allocimage(display, Rect(0, 0, 32, r.max.y), screen->chan, 1, DPaleyellow);
if(scrx == 0)
fatal("scroll balloc");
sysfatal("scroll balloc");
}
r1.min.x = 0;
r1.max.x = Dx(r);
@ -1525,16 +1634,11 @@ plumb(uint q0, uint q1)
char *p;
int i, p0, n;
char cbuf[100];
char *w;
if(getchildwd(rcpid, childwdir, sizeof childwdir) == 0)
w = childwdir;
else
w = wdir;
pm = malloc(sizeof(Plumbmsg));
pm->src = strdup("9term");
pm->dst = 0;
pm->wdir = strdup(w);
pm->wdir = strdup(wdir);
pm->type = strdup("text");
pm->data = nil;
if(q1 > q0)

View file

@ -1,19 +1,4 @@
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <cursor.h>
#include <keyboard.h>
#include <frame.h>
#include <plumb.h>
#include <termios.h>
#include <sys/termios.h>
#ifdef __linux__
#include <pty.h>
#endif
extern int getchildwd(int, char*, int);
extern int getpts(int[], char*);
extern int childpty(int[], char*);
extern void updatewinsize(int, int, int, int);
extern int rcfd[];

View file

@ -1,17 +1,43 @@
#include "9term.h"
#include <termios.h>
#include <sys/termios.h>
#include <libutil.h>
int
getchildwd(int pid, char *wdir, int bufn)
{
USED(pid);
USED(wdir);
USED(bufn);
return -1;
}
int
getpts(int fd[], char *slave)
{
return openpty(&fd[1], &fd[0], slave, 0, 0);
}
int
childpty(int fd[], char *slave)
{
int sfd;
close(fd[1]);
setsid();
sfd = open(slave, ORDWR);
if(sfd < 0)
sysfatal("open %s: %r\n", slave);
if(ioctl(sfd, TIOCSCTTY, 0) < 0)
fprint(2, "ioctl TIOCSCTTY: %r\n");
return sfd;
}
struct winsize ows;
void
updatewinsize(int row, int col, int dx, int dy)
{
struct winsize ws;
ws.ws_row = row;
ws.ws_col = col;
ws.ws_xpixel = dx;
ws.ws_ypixel = dy;
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
fprint(2, "ioctl: %r\n");
ows = ws;
}

View file

@ -1,22 +1,46 @@
#include <u.h>
#include <termios.h>
#include <sys/termios.h>
#include <pty.h>
#include <libc.h>
#include "9term.h"
int
getchildwd(int pid, char *wdir, int bufn)
{
char path[256];
int n;
snprint(path, sizeof path, "/proc/%d/cwd", pid);
n = readlink(path, wdir, bufn);
if(n < 0)
return -1;
wdir[n] = '\0';
return 0;
}
int
getpts(int fd[], char *slave)
{
openpty(&fd[1], &fd[0], slave, 0, 0);
return 0;
}
int
childpty(int fd[], char *slave)
{
int sfd;
close(fd[1]);
setsid();
sfd = open(slave, ORDWR);
if(sfd < 0)
sysfatal("open %s: %r\n", slave);
if(ioctl(sfd, TIOCSCTTY, 0) < 0)
fprint(2, "ioctl TIOCSCTTY: %r\n");
return sfd;
}
struct winsize ows;
void
updatewinsize(int row, int col, int dx, int dy)
{
struct winsize ws;
ws.ws_row = row;
ws.ws_col = col;
ws.ws_xpixel = dx;
ws.ws_ypixel = dy;
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
fprint(2, "ioctl: %r\n");
ows = ws;
}

View file

@ -1,21 +1,6 @@
#include "9term.h"
int
getchildwd(int pid, char *wdir, int bufn)
{
char path[256];
char cwd[256];
if(getcwd(cwd, sizeof cwd) < 0)
return -1;
snprint(path, sizeof path, "/proc/%d/cwd", pid);
if(chdir(path) < 0)
return -1;
if(getcwd(wdir, bufn) < 0)
return -1;
chdir(cwd);
return 0;
}
#include <termios.h>
#include <sys/termios.h>
int
getpts(int fd[], char *slave)
@ -28,3 +13,21 @@ getpts(int fd[], char *slave)
fd[0] = open(slave, OREAD);
return 0;
}
struct winsize ows;
void
updatewinsize(int row, int col, int dx, int dy)
{
struct winsize ws;
ws.ws_row = row;
ws.ws_col = col;
ws.ws_xpixel = dx;
ws.ws_ypixel = dy;
if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
fprint(2, "ioctl: %r\n");
ows = ws;
}

View file

@ -1,15 +1,15 @@
PLAN9=../../..
<$PLAN9/src/mkhdr
TARG=9term
TARG=9term win
OFILES=\
9term.$O\
rcstart.$O\
$SYSNAME.$O\
SHORTLIB=frame draw plumb fs mux thread 9
SHORTLIB=complete frame draw plumb fs mux thread 9
<$PLAN9/src/mkone
<$PLAN9/src/mkmany
LDFLAGS=-L$X11/lib -lX11 -lutil

51
src/cmd/9term/rcstart.c Normal file
View file

@ -0,0 +1,51 @@
#include <u.h>
#include <libc.h>
#include "term.h"
int
rcstart(int argc, char **argv, int *pfd)
{
int pid;
int fd[2];
char *xargv[3];
char slave[256];
int sfd;
if(argc == 0){
argc = 2;
argv = xargv;
argv[0] = getenv("SHELL");
if(argv[0] == 0)
argv[0] = "rc";
argv[1] = "-i";
argv[2] = 0;
}
/*
* fd0 is slave (tty), fd1 is master (pty)
*/
fd[0] = fd[1] = -1;
if(getpts(fd, slave) < 0)
fprint(2, "getpts: %r\n");
switch(pid = fork()) {
case 0:
putenv("TERM", "9term");
sfd = childpty(fd, slave);
dup(sfd, 0);
dup(sfd, 1);
dup(sfd, 2);
system("stty tabs -onlcr -echo erase ^h intr ^?");
execvp(argv[0], argv);
fprint(2, "exec %s failed: %r\n", argv[0]);
_exits("oops");
break;
case -1:
sysfatal("proc failed: %r");
break;
}
close(fd[0]);
*pfd = fd[1];
return pid;
}

5
src/cmd/9term/term.h Normal file
View file

@ -0,0 +1,5 @@
extern int getpts(int[], char*);
extern int childpty(int[], char*);
extern void updatewinsize(int, int, int, int);
extern int rcfd;
extern int rcstart(int, char*[], int*);

View file

@ -3,6 +3,7 @@
#include <thread.h>
#include <fcall.h>
#include <fs.h>
#include "term.h"
#define EVENTSIZE 256
#define STACK 32768
@ -51,11 +52,11 @@ int ntypeb;
int ntyper;
int ntypebreak;
int debug;
int rcfd;
char *name;
char **prog;
int p[2];
Channel *cpid;
Channel *cwait;
int pid = -1;
@ -124,9 +125,11 @@ threadmain(int argc, char **argv)
prog = argv;
if(argc > 0)
if(argc > 0){
name = argv[0];
else
argc--;
argv++;
}else
name = "gnot";
threadnotify(nopipes, 1);
@ -156,14 +159,9 @@ threadmain(int argc, char **argv)
*/
fsunmount(fs);
if(pipe(p) < 0)
sysfatal("pipe: %r");
cpid = chancreate(sizeof(ulong), 1);
cwait = threadwaitchan();
threadcreate(waitthread, nil, STACK);
threadcreate(runproc, nil, STACK);
pid = recvul(cpid);
pid = rcstart(argc, argv, &rcfd);
if(pid == -1)
sysfatal("exec failed");
@ -179,30 +177,6 @@ threadmain(int argc, char **argv)
stdinproc(nil);
}
char *shell[] = { "rc", "-i", 0 };
void
runproc(void *v)
{
int fd[3];
char *sh;
USED(v);
fd[0] = p[1];
// fd[1] = bodyfd;
// fd[2] = bodyfd;
fd[1] = p[1];
fd[2] = p[1];
if(prog[0] == nil){
prog = shell;
if((sh = getenv("SHELL")) != nil)
shell[0] = sh;
}
threadexec(cpid, fd, prog[0], prog);
threadexits(nil);
}
void
error(char *s)
{
@ -329,7 +303,7 @@ stdinproc(void *v)
Fid *efd = eventfd;
Fid *dfd = datafd;
Fid *afd = addrfd;
int fd0 = p[0];
int fd0 = rcfd;
Event e, e2, e3, e4;
USED(v);
@ -426,7 +400,7 @@ stdinproc(void *v)
void
stdoutproc(void *v)
{
int fd1 = p[0];
int fd1 = rcfd;
Fid *afd = addrfd;
Fid *dfd = datafd;
int n, m, w, npart;
@ -439,6 +413,8 @@ stdoutproc(void *v)
buf = malloc(8192+UTFmax+1);
npart = 0;
for(;;){
/* Let typing have a go -- maybe there's a rubout waiting. */
yield();
n = threadread(fd1, buf+npart, 8192);
if(n < 0)
error(nil);
@ -556,7 +532,7 @@ addtype(int c, uint p0, char *b, int nb, int nr)
for(i=0; i<nb; i+=w){
w = chartorune(&r, b+i);
if((r==0x7F||r==3) && c=='K'){
postnote(PNGROUP, pid, "interrupt");
write(rcfd, "\x7F", 1);
/* toss all typing */
q.p += ntyper+nr;
ntypebreak = 0;

View file

@ -161,7 +161,8 @@ threadmain(int argc, char *argv[])
cerr = chancreate(sizeof(char*), 0);
cedit = chancreate(sizeof(int), 0);
cexit = chancreate(sizeof(int), 0);
if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil){
cwarn = chancreate(sizeof(void*), 1);
if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil || cwarn==nil){
fprint(2, "acme: can't create initial channels: %r\n");
exits("channels");
}
@ -251,7 +252,7 @@ readfile(Column *c, char *s)
w = coladd(c, nil, nil, -1);
cvttorunes(s, strlen(s), rb, &nb, &nr, nil);
rs = cleanrname((Runestr){rb, nr});
rs = cleanrname(runestr(rb, nr));
winsetname(w, rs.r, rs.nr);
textload(&w->body, 0, s, 1);
w->body.file->mod = FALSE;
@ -403,7 +404,6 @@ keyboardthread(void *v)
winlock(t->w, 'K');
wincommit(t->w, t);
winunlock(t->w);
flushwarnings(1);
flushimage(display, 1);
}
alts[KTimer].c = nil;
@ -430,7 +430,6 @@ keyboardthread(void *v)
}
if(nbrecv(keyboardctl->c, &r) > 0)
goto casekeyboard;
flushwarnings(1);
flushimage(display, 1);
break;
}
@ -447,7 +446,7 @@ mousethread(void *v)
Plumbmsg *pm;
Mouse m;
char *act;
enum { MResize, MMouse, MPlumb, NMALT };
enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
static Alt alts[NMALT+1];
USED(v);
@ -461,11 +460,18 @@ mousethread(void *v)
alts[MPlumb].c = cplumb;
alts[MPlumb].v = &pm;
alts[MPlumb].op = CHANRCV;
alts[MWarnings].c = cwarn;
alts[MWarnings].v = nil;
alts[MWarnings].op = CHANRCV;
if(cplumb == nil)
alts[MPlumb].op = CHANNOP;
alts[NMALT].op = CHANEND;
for(;;){
qlock(&row.lk);
flushwarnings();
qunlock(&row.lk);
flushimage(display, 1);
switch(alt(alts)){
case MResize:
if(getwindow(display, Refnone) < 0)
@ -473,8 +479,6 @@ mousethread(void *v)
draw(screen, screen->r, display->white, nil, ZP);
scrlresize();
rowresize(&row, screen->clipr);
flushwarnings(1);
flushimage(display, 1);
break;
case MPlumb:
if(strcmp(pm->type, "text") == 0){
@ -484,10 +488,10 @@ mousethread(void *v)
else if(strcmp(act, "showdata")==0)
plumbshow(pm);
}
flushwarnings(1);
flushimage(display, 1);
plumbfree(pm);
break;
case MWarnings:
break;
case MMouse:
/*
* Make a copy so decisions are consistent; mousectl changes
@ -570,8 +574,6 @@ mousethread(void *v)
goto Continue;
}
Continue:
flushwarnings(0);
flushimage(display, 1);
qunlock(&row.lk);
break;
}

View file

@ -543,5 +543,6 @@ Channel *mouseexit1; /* chan(int) */
Channel *cexit; /* chan(int) */
Channel *cerr; /* chan(char*) */
Channel *cedit; /* chan(int) */
Channel *cwarn; /* chan(void*)[1] (really chan(unit)[1]) */
#define STACK 32768

View file

@ -268,7 +268,7 @@ D_cmd(Text *t, Cmd *cp)
runemove(n, dir.r, dir.nr);
n[dir.nr] = '/';
runemove(n+dir.nr+1, r, nn);
rs = cleanrname((Runestr){n, dir.nr+1+nn});
rs = cleanrname(runestr(n, dir.nr+1+nn));
}
w = lookfile(rs.r, rs.nr);
if(w == nil){

View file

@ -25,6 +25,7 @@ void fontx(Text*, Text*, Text*, int, int, Rune*, int);
void get(Text*, Text*, Text*, int, int, Rune*, int);
void id(Text*, Text*, Text*, int, int, Rune*, int);
void incl(Text*, Text*, Text*, int, int, Rune*, int);
void indent(Text*, Text*, Text*, int, int, Rune*, int);
void xkill(Text*, Text*, Text*, int, int, Rune*, int);
void local(Text*, Text*, Text*, int, int, Rune*, int);
void look(Text*, Text*, Text*, int, int, Rune*, int);
@ -58,6 +59,7 @@ static Rune LFont[] = { 'F', 'o', 'n', 't', 0 };
static Rune LGet[] = { 'G', 'e', 't', 0 };
static Rune LID[] = { 'I', 'D', 0 };
static Rune LIncl[] = { 'I', 'n', 'c', 'l', 0 };
static Rune LIndent[] = { 'I', 'n', 'd', 'e', 'n', 't', 0 };
static Rune LKill[] = { 'K', 'i', 'l', 'l', 0 };
static Rune LLoad[] = { 'L', 'o', 'a', 'd', 0 };
static Rune LLocal[] = { 'L', 'o', 'c', 'a', 'l', 0 };
@ -87,6 +89,7 @@ Exectab exectab[] = {
{ LGet, get, FALSE, TRUE, XXX },
{ LID, id, FALSE, XXX, XXX },
{ LIncl, incl, FALSE, XXX, XXX },
{ LIndent, indent, FALSE, XXX, XXX },
{ LKill, xkill, FALSE, XXX, XXX },
{ LLoad, dump, FALSE, FALSE, XXX },
{ LLocal, local, FALSE, XXX, XXX },
@ -1443,7 +1446,6 @@ runproc(void *argvp)
goto Fail;
Hard:
/*
* ugly: set path = (. $cputype /bin)
* should honor $path if unusual.

View file

@ -69,6 +69,7 @@ Rune* bytetorune(char*, int*);
void fsysinit(void);
Mntdir* fsysmount(Rune*, int, Rune**, int);
void fsysdelid(Mntdir*);
void fsysincid(Mntdir*);
Xfid* respond(Xfid*, Fcall*, char*);
int rxcompile(Rune*);
int rgetc(void*, uint);
@ -86,9 +87,11 @@ int expand(Text*, uint, uint, Expand*);
Rune* skipbl(Rune*, int, int*);
Rune* findbl(Rune*, int, int*);
char* edittext(Window*, int, Rune*, int);
void flushwarnings(int);
void flushwarnings(void);
void startplumbing(void);
Runestr runestr(Rune*, uint);
#define runemalloc(a) (Rune*)emalloc((a)*sizeof(Rune))
#define runerealloc(a, b) (Rune*)erealloc((a), (b)*sizeof(Rune))
#define runemove(a, b, c) memmove((a), (b), (c)*sizeof(Rune))

View file

@ -37,22 +37,25 @@ static Xfid* fsysremove(Xfid*, Fid*);
static Xfid* fsysstat(Xfid*, Fid*);
static Xfid* fsyswstat(Xfid*, Fid*);
Xfid* (*fcall[Tmax])(Xfid*, Fid*) =
Xfid* (*fcall[Tmax])(Xfid*, Fid*);
static void
initfcall(void)
{
[Tflush] = fsysflush,
[Tversion] = fsysversion,
[Tauth] = fsysauth,
[Tattach] = fsysattach,
[Twalk] = fsyswalk,
[Topen] = fsysopen,
[Tcreate] = fsyscreate,
[Tread] = fsysread,
[Twrite] = fsyswrite,
[Tclunk] = fsysclunk,
[Tremove]= fsysremove,
[Tstat] = fsysstat,
[Twstat] = fsyswstat,
};
fcall[Tflush] = fsysflush;
fcall[Tversion] = fsysversion;
fcall[Tauth] = fsysauth;
fcall[Tattach] = fsysattach;
fcall[Twalk] = fsyswalk;
fcall[Topen] = fsysopen;
fcall[Tcreate] = fsyscreate;
fcall[Tread] = fsysread;
fcall[Twrite] = fsyswrite;
fcall[Tclunk] = fsysclunk;
fcall[Tremove]= fsysremove;
fcall[Tstat] = fsysstat;
fcall[Twstat] = fsyswstat;
}
char Eperm[] = "permission denied";
char Eexist[] = "file does not exist";
@ -113,6 +116,7 @@ fsysinit(void)
int p[2];
char *u;
initfcall();
if(pipe(p) < 0)
error("can't create pipe");
if(post9pservice(p[0], "acme") < 0)
@ -186,6 +190,14 @@ fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
return m;
}
void
fsysincid(Mntdir *m)
{
qlock(&mnt.lk);
m->ref++;
qunlock(&mnt.lk);
}
void
fsysdelid(Mntdir *idm)
{
@ -331,7 +343,7 @@ fsysattach(Xfid *x, Fid *f)
m->ref++;
break;
}
if(m == nil){
if(m == nil && x->fcall.aname[0]){
snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
sendp(cerr, estrdup(buf));
}

View file

@ -259,7 +259,7 @@ plumbshow(Plumbmsg *m)
}
cvttorunes(name, strlen(name), rb, &nb, &nr, nil);
free(p);
rs = cleanrname((Runestr){rb, nr});
rs = cleanrname(runestr(rb, nr));
winsetname(w, rs.r, rs.nr);
r = runemalloc(m->ndata);
cvttorunes(m->data, m->ndata, r, &nb, &nr, nil);
@ -385,13 +385,13 @@ includefile(Rune *dir, Rune *file, int nfile)
n = access(a, 0);
free(a);
if(n < 0)
return (Runestr){nil, 0};
return runestr(nil, 0);
r = runemalloc(m+1+nfile);
runemove(r, dir, m);
runemove(r+m, Lslash, 1);
runemove(r+m+1, file, nfile);
free(file);
return cleanrname((Runestr){r, m+1+nfile});
return cleanrname(runestr(r, m+1+nfile));
}
static Rune *objdir;
@ -442,7 +442,7 @@ includename(Text *t, Rune *r, int n)
return file;
Rescue:
return (Runestr){r, n};
return runestr(r, n);
}
Runestr
@ -475,11 +475,11 @@ dirname(Text *t, Rune *r, int n)
goto Rescue;
runemove(b+slash+1, r, n);
free(r);
return cleanrname((Runestr){b, slash+1+n});
return cleanrname(runestr(b, slash+1+n));
Rescue:
free(b);
tmp = (Runestr){r, n};
tmp = runestr(r, n);
if(r)
return cleanrname(tmp);
return tmp;

View file

@ -578,7 +578,7 @@ textcomplete(Text *t)
path[i] = textreadc(t, q++);
/* is path rooted? if not, we need to make it relative to window path */
if(npath>0 && path[0]=='/')
dir = (Runestr){path, npath};
dir = runestr(path, npath);
else{
dir = dirname(t, nil, 0);
if(dir.nr + 1 + npath > nelem(tmp)){

View file

@ -14,6 +14,16 @@
static Point prevmouse;
static Window *mousew;
Runestr
runestr(Rune *r, uint n)
{
Runestr rs;
rs.r = r;
rs.nr = n;
return rs;
}
void
cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
{
@ -133,12 +143,17 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
}
warn = emalloc(sizeof(Warning));
warn->next = warnings;
warn->md = md;
if(md)
fsysincid(md);
warnings = warn;
bufinsert(&warn->buf, 0, r, nr);
nbsendp(cwarn, 0);
}
/* called while row is locked */
void
flushwarnings(int dolock)
flushwarnings(void)
{
Warning *warn, *next;
Window *w;
@ -146,8 +161,6 @@ flushwarnings(int dolock)
int owner, nr, q0, n;
Rune *r;
if(dolock)
qlock(&row.lk);
if(row.ncol == 0){ /* really early error */
rowinit(&row, screen->clipr);
rowadd(&row, nil, -1);
@ -189,11 +202,11 @@ flushwarnings(int dolock)
winunlock(w);
bufclose(&warn->buf);
next = warn->next;
if(warn->md)
fsysdelid(warn->md);
free(warn);
}
warnings = nil;
if(dolock)
qunlock(&row.lk);
}
void

View file

@ -543,7 +543,6 @@ xfidwrite(Xfid *x)
}
if(w)
winunlock(w);
flushwarnings(1);
}
void
@ -814,7 +813,6 @@ xfideventwrite(Xfid *x, Window *w)
qunlock(&row.lk);
goto Rescue;
}
flushwarnings(0);
qunlock(&row.lk);
}
@ -1032,7 +1030,6 @@ xfidindexread(Xfid *x)
b[n++] = '\n';
}
}
flushwarnings(0);
qunlock(&row.lk);
off = x->fcall.offset;
cnt = x->fcall.count;

View file

@ -119,6 +119,8 @@ main(int argc, char **argv)
line = malloc(strlen(p)+5);
sprint(line, "/%s/P\n", p);
}
dict->path = unsharp(dict->path);
dict->indexpath = unsharp(dict->indexpath);
bdict = Bopen(dict->path, OREAD);
if(!bdict) {
err("can't open dictionary %s", dict->path);

View file

@ -1,3 +1,5 @@
#define stdout bstdout
char mode; /* '\0', 'e', 'f', 'h' */
char bflag; /* ignore multiple and trailing blanks */
char rflag; /* recurse down directory trees */

View file

@ -26,6 +26,8 @@ void
done(int status)
{
rmtmpfiles();
Bflush(&stdout);
Bterm(&stdout);
switch(status)
{
case 0:

View file

@ -4,8 +4,8 @@
#define index findex
char choice[2048];
char index[] = "/sys/games/lib/fortunes.index";
char fortunes[] = "/sys/games/lib/fortunes";
char *index = "#9/lib/fortunes.index";
char *fortunes = "#9/lib/fortunes";
#define lrand rand
@ -21,6 +21,9 @@ main(int argc, char *argv[])
Dir *fbuf, *ixbuf;
Biobuf *f, g;
index = unsharp(index);
fortunes = unsharp(index);
newindex = 0;
oldindex = 0;
ix = offs = 0;
@ -55,6 +58,7 @@ main(int argc, char *argv[])
}
}
if(oldindex){
srand(getpid());
seek(ix, lrand()%(ixbuf->length/sizeof(offs))*sizeof(offs), 0);
read(ix, off, sizeof(off));
Bseek(f, off[0]|(off[1]<<8)|(off[2]<<16)|(off[3]<<24), 0);

277
src/cmd/grep/comp.c Normal file
View file

@ -0,0 +1,277 @@
#include "grep.h"
/*
* incremental compiler.
* add the branch c to the
* state s.
*/
void
increment(State *s, int c)
{
int i;
State *t, **tt;
Re *re1, *re2;
nfollow = 0;
gen++;
matched = 0;
for(i=0; i<s->count; i++)
fol1(s->re[i], c);
qsort(follow, nfollow, sizeof(*follow), fcmp);
for(tt=&state0; t = *tt;) {
if(t->count > nfollow) {
tt = &t->linkleft;
goto cont;
}
if(t->count < nfollow) {
tt = &t->linkright;
goto cont;
}
for(i=0; i<nfollow; i++) {
re1 = t->re[i];
re2 = follow[i];
if(re1 > re2) {
tt = &t->linkleft;
goto cont;
}
if(re1 < re2) {
tt = &t->linkright;
goto cont;
}
}
if(!!matched && !t->match) {
tt = &t->linkleft;
goto cont;
}
if(!matched && !!t->match) {
tt = &t->linkright;
goto cont;
}
s->next[c] = t;
return;
cont:;
}
t = sal(nfollow);
*tt = t;
for(i=0; i<nfollow; i++) {
re1 = follow[i];
t->re[i] = re1;
}
s->next[c] = t;
t->match = matched;
}
int
fcmp(const void *va, const void *vb)
{
Re **aa, **bb;
Re *a, *b;
aa = (Re**)va;
bb = (Re**)vb;
a = *aa;
b = *bb;
if(a > b)
return 1;
if(a < b)
return -1;
return 0;
}
void
fol1(Re *r, int c)
{
Re *r1;
loop:
if(r->gen == gen)
return;
if(nfollow >= maxfollow)
error("nfollow");
r->gen = gen;
switch(r->type) {
default:
error("fol1");
case Tcase:
if(c >= 0 && c < 256)
if(r1 = r->cases[c])
follow[nfollow++] = r1;
if(r = r->next)
goto loop;
break;
case Talt:
case Tor:
fol1(r->alt, c);
r = r->next;
goto loop;
case Tbegin:
if(c == '\n' || c == Cbegin)
follow[nfollow++] = r->next;
break;
case Tend:
if(c == '\n')
matched = 1;
break;
case Tclass:
if(c >= r->lo && c <= r->hi)
follow[nfollow++] = r->next;
break;
}
}
Rune tab1[] =
{
0x007f,
0x07ff,
};
Rune tab2[] =
{
0x003f,
0x0fff,
};
Re2
rclass(Rune p0, Rune p1)
{
char xc0[6], xc1[6];
int i, n, m;
Re2 x;
if(p0 > p1)
return re2char(0xff, 0xff); // no match
/*
* bust range into same length
* character sequences
*/
for(i=0; i<nelem(tab1); i++) {
m = tab1[i];
if(p0 <= m && p1 > m)
return re2or(rclass(p0, m), rclass(m+1, p1));
}
/*
* bust range into part of a single page
* or into full pages
*/
for(i=0; i<nelem(tab2); i++) {
m = tab2[i];
if((p0 & ~m) != (p1 & ~m)) {
if((p0 & m) != 0)
return re2or(rclass(p0, p0|m), rclass((p0|m)+1, p1));
if((p1 & m) != m)
return re2or(rclass(p0, (p1&~m)-1), rclass(p1&~m, p1));
}
}
n = runetochar(xc0, &p0);
i = runetochar(xc1, &p1);
if(i != n)
error("length");
x = re2char(xc0[0], xc1[0]);
for(i=1; i<n; i++)
x = re2cat(x, re2char(xc0[i], xc1[i]));
return x;
}
int
pcmp(const void *va, const void *vb)
{
int n;
Rune *a, *b;
a = (Rune*)va;
b = (Rune*)vb;
n = a[0] - b[0];
if(n)
return n;
return a[1] - b[1];
}
/*
* convert character chass into
* run-pair ranges of matches.
* this is 10646/utf specific and
* needs to be changed for some
* other input character set.
* this is the key to a fast
* regular search of characters
* by looking at sequential bytes.
*/
Re2
re2class(char *s)
{
Rune pairs[200], *p, *q, ov;
int nc;
Re2 x;
nc = 0;
if(*s == '^') {
nc = 1;
s++;
}
p = pairs;
s += chartorune(p, s);
for(;;) {
if(*p == '\\')
s += chartorune(p, s);
if(*p == 0)
break;
p[1] = *p;
p += 2;
s += chartorune(p, s);
if(*p != '-')
continue;
s += chartorune(p, s);
if(*p == '\\')
s += chartorune(p, s);
if(*p == 0)
break;
p[-1] = *p;
s += chartorune(p, s);
}
*p = 0;
qsort(pairs, (p-pairs)/2, 2*sizeof(*pairs), pcmp);
q = pairs;
for(p=pairs+2; *p; p+=2) {
if(p[0] > p[1])
continue;
if(p[0] > q[1] || p[1] < q[0]) {
q[2] = p[0];
q[3] = p[1];
q += 2;
continue;
}
if(p[0] < q[0])
q[0] = p[0];
if(p[1] > q[1])
q[1] = p[1];
}
q[2] = 0;
p = pairs;
if(nc) {
x = rclass(0, p[0]-1);
ov = p[1]+1;
for(p+=2; *p; p+=2) {
x = re2or(x, rclass(ov, p[0]-1));
ov = p[1]+1;
}
x = re2or(x, rclass(ov, 0xffff));
} else {
x = rclass(p[0], p[1]);
for(p+=2; *p; p+=2)
x = re2or(x, rclass(p[0], p[1]));
}
return x;
}

125
src/cmd/grep/grep.h Normal file
View file

@ -0,0 +1,125 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#ifndef EXTERN
#define EXTERN extern
#endif
typedef struct Re Re;
typedef struct Re2 Re2;
typedef struct State State;
struct State
{
int count;
int match;
Re** re;
State* linkleft;
State* linkright;
State* next[256];
};
struct Re2
{
Re* beg;
Re* end;
};
struct Re
{
uchar type;
ushort gen;
union
{
Re* alt; /* Talt */
Re** cases; /* case */
struct /* class */
{
Rune lo;
Rune hi;
};
Rune val; /* char */
};
Re* next;
};
enum
{
Talt = 1,
Tbegin,
Tcase,
Tclass,
Tend,
Tor,
Caselim = 7,
Nhunk = 1<<16,
Cbegin = 0x10000,
Flshcnt = (1<<9)-1,
Cflag = 1<<0,
Hflag = 1<<1,
Iflag = 1<<2,
Llflag = 1<<3,
LLflag = 1<<4,
Nflag = 1<<5,
Sflag = 1<<6,
Vflag = 1<<7,
Bflag = 1<<8
};
EXTERN union
{
char string[16*1024];
struct
{
/*
* if a line requires multiple reads, we keep shifting
* buf down into pre and then do another read into
* buf. so you'll get the last 16-32k of the matching line.
* if pre were smaller than buf you'd get a suffix of the
* line with a hole cut out.
*/
uchar pre[16*1024]; /* to save to previous '\n' */
uchar buf[16*1024]; /* input buffer */
};
} u;
EXTERN char *filename;
EXTERN Biobuf bout;
EXTERN char flags[256];
EXTERN Re** follow;
EXTERN ushort gen;
EXTERN char* input;
EXTERN long lineno;
EXTERN int literal;
EXTERN int matched;
EXTERN long maxfollow;
EXTERN long nfollow;
EXTERN int peekc;
EXTERN Biobuf* rein;
EXTERN State* state0;
EXTERN Re2 topre;
extern Re* addcase(Re*);
extern void appendnext(Re*, Re*);
extern void error(char*);
extern int fcmp(const void*, const void*); /* (Re**, Re**) */
extern void fol1(Re*, int);
extern int getrec(void);
extern void increment(State*, int);
#define initstate grepinitstate
extern State* initstate(Re*);
extern void* mal(int);
extern void patchnext(Re*, Re*);
extern Re* ral(int);
extern Re2 re2cat(Re2, Re2);
extern Re2 re2class(char*);
extern Re2 re2or(Re2, Re2);
extern Re2 re2char(int, int);
extern Re2 re2star(Re2);
extern State* sal(int);
extern int search(char*, int);
extern void str2top(char*);
extern int yyparse(void);
extern void reprint(char*, Re*);
extern void yyerror(char*, ...);

226
src/cmd/grep/grep.y Normal file
View file

@ -0,0 +1,226 @@
%{
#include "grep.h"
%}
%union
{
int val;
char* str;
Re2 re;
}
%type <re> expr prog
%type <re> expr0 expr1 expr2 expr3 expr4
%token <str> LCLASS
%token <val> LCHAR
%token LLPAREN LRPAREN LALT LSTAR LPLUS LQUES
%token LBEGIN LEND LDOT LBAD LNEWLINE
%%
prog:
expr newlines
{
$$.beg = ral(Tend);
$$.end = $$.beg;
$$ = re2cat(re2star(re2or(re2char(0x00, '\n'-1), re2char('\n'+1, 0xff))), $$);
$$ = re2cat($1, $$);
$$ = re2cat(re2star(re2char(0x00, 0xff)), $$);
topre = $$;
}
expr:
expr0
| expr newlines expr0
{
$$ = re2or($1, $3);
}
expr0:
expr1
| LSTAR { literal = 1; } expr1
{
$$ = $3;
}
expr1:
expr2
| expr1 LALT expr2
{
$$ = re2or($1, $3);
}
expr2:
expr3
| expr2 expr3
{
$$ = re2cat($1, $2);
}
expr3:
expr4
| expr3 LSTAR
{
$$ = re2star($1);
}
| expr3 LPLUS
{
$$.beg = ral(Talt);
patchnext($1.end, $$.beg);
$$.beg->alt = $1.beg;
$$.end = $$.beg;
$$.beg = $1.beg;
}
| expr3 LQUES
{
$$.beg = ral(Talt);
$$.beg->alt = $1.beg;
$$.end = $1.end;
appendnext($$.end, $$.beg);
}
expr4:
LCHAR
{
$$.beg = ral(Tclass);
$$.beg->lo = $1;
$$.beg->hi = $1;
$$.end = $$.beg;
}
| LBEGIN
{
$$.beg = ral(Tbegin);
$$.end = $$.beg;
}
| LEND
{
$$.beg = ral(Tend);
$$.end = $$.beg;
}
| LDOT
{
$$ = re2class("^\n");
}
| LCLASS
{
$$ = re2class($1);
}
| LLPAREN expr1 LRPAREN
{
$$ = $2;
}
newlines:
LNEWLINE
| newlines LNEWLINE
%%
void
yyerror(char *e, ...)
{
if(filename)
fprint(2, "grep: %s:%ld: %s\n", filename, lineno, e);
else
fprint(2, "grep: %s\n", e);
exits("syntax");
}
long
yylex(void)
{
char *q, *eq;
int c, s;
if(peekc) {
s = peekc;
peekc = 0;
return s;
}
c = getrec();
if(literal) {
if(c != 0 && c != '\n') {
yylval.val = c;
return LCHAR;
}
literal = 0;
}
switch(c) {
default:
yylval.val = c;
s = LCHAR;
break;
case '\\':
c = getrec();
yylval.val = c;
s = LCHAR;
if(c == '\n')
s = LNEWLINE;
break;
case '[':
goto getclass;
case '(':
s = LLPAREN;
break;
case ')':
s = LRPAREN;
break;
case '|':
s = LALT;
break;
case '*':
s = LSTAR;
break;
case '+':
s = LPLUS;
break;
case '?':
s = LQUES;
break;
case '^':
s = LBEGIN;
break;
case '$':
s = LEND;
break;
case '.':
s = LDOT;
break;
case 0:
peekc = -1;
case '\n':
s = LNEWLINE;
break;
}
return s;
getclass:
q = u.string;
eq = q + nelem(u.string) - 5;
c = getrec();
if(c == '^') {
q[0] = '^';
q[1] = '\n';
q[2] = '-';
q[3] = '\n';
q += 4;
c = getrec();
}
for(;;) {
if(q >= eq)
error("class too long");
if(c == ']' || c == 0)
break;
if(c == '\\') {
*q++ = c;
c = getrec();
if(c == 0)
break;
}
*q++ = c;
c = getrec();
}
*q = 0;
if(c == 0)
return LBAD;
yylval.str = u.string;
return LCLASS;
}

260
src/cmd/grep/main.c Normal file
View file

@ -0,0 +1,260 @@
#define EXTERN
#include "grep.h"
char *validflags = "bchiLlnsv";
void
usage(void)
{
fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
exits("usage");
}
void
main(int argc, char *argv[])
{
int i, status;
ARGBEGIN {
default:
if(utfrune(validflags, ARGC()) == nil)
usage();
flags[ARGC()]++;
break;
case 'e':
flags['e']++;
lineno = 0;
str2top(ARGF());
break;
case 'f':
flags['f']++;
filename = ARGF();
rein = Bopen(filename, OREAD);
if(rein == 0) {
fprint(2, "grep: can't open %s: %r\n", filename);
exits("open");
}
lineno = 1;
str2top(filename);
break;
} ARGEND
if(flags['f'] == 0 && flags['e'] == 0) {
if(argc <= 0)
usage();
str2top(argv[0]);
argc--;
argv++;
}
follow = mal(maxfollow*sizeof(*follow));
state0 = initstate(topre.beg);
Binit(&bout, 1, OWRITE);
switch(argc) {
case 0:
status = search(0, 0);
break;
case 1:
status = search(argv[0], 0);
break;
default:
status = 0;
for(i=0; i<argc; i++)
status |= search(argv[i], Hflag);
break;
}
if(status)
exits(0);
exits("no matches");
}
int
search(char *file, int flag)
{
State *s, *ns;
int c, fid, eof, nl, empty;
long count, lineno, n;
uchar *elp, *lp, *bol;
if(file == 0) {
file = "stdin";
fid = 0;
flag |= Bflag;
} else
fid = open(file, OREAD);
if(fid < 0) {
fprint(2, "grep: can't open %s: %r\n", file);
return 0;
}
if(flags['b'])
flag ^= Bflag; /* dont buffer output */
if(flags['c'])
flag |= Cflag; /* count */
if(flags['h'])
flag &= ~Hflag; /* do not print file name in output */
if(flags['i'])
flag |= Iflag; /* fold upper-lower */
if(flags['l'])
flag |= Llflag; /* print only name of file if any match */
if(flags['L'])
flag |= LLflag; /* print only name of file if any non match */
if(flags['n'])
flag |= Nflag; /* count only */
if(flags['s'])
flag |= Sflag; /* status only */
if(flags['v'])
flag |= Vflag; /* inverse match */
s = state0;
lineno = 0;
count = 0;
eof = 0;
empty = 1;
nl = 0;
lp = u.buf;
bol = lp;
loop0:
n = lp-bol;
if(n > sizeof(u.pre))
n = sizeof(u.pre);
memmove(u.buf-n, bol, n);
bol = u.buf-n;
n = read(fid, u.buf, sizeof(u.buf));
/* if file has no final newline, simulate one to emit matches to last line */
if(n > 0) {
empty = 0;
nl = u.buf[n-1]=='\n';
} else {
if(n < 0){
fprint(2, "grep: read error on %s: %r\n", file);
return count != 0;
}
if(!eof && !nl && !empty) {
u.buf[0] = '\n';
n = 1;
eof = 1;
}
}
if(n <= 0) {
close(fid);
if(flag & Cflag) {
if(flag & Hflag)
Bprint(&bout, "%s:", file);
Bprint(&bout, "%ld\n", count);
}
if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
Bprint(&bout, "%s\n", file);
Bflush(&bout);
return count != 0;
}
lp = u.buf;
elp = lp+n;
if(flag & Iflag)
goto loopi;
/*
* normal character loop
*/
loop:
c = *lp;
ns = s->next[c];
if(ns == 0) {
increment(s, c);
goto loop;
}
// if(flags['2'])
// if(s->match)
// print("%d: %.2x**\n", s, c);
// else
// print("%d: %.2x\n", s, c);
lp++;
s = ns;
if(c == '\n') {
lineno++;
if(!!s->match == !(flag&Vflag)) {
count++;
if(flag & (Cflag|Sflag|Llflag|LLflag))
goto cont;
if(flag & Hflag)
Bprint(&bout, "%s:", file);
if(flag & Nflag)
Bprint(&bout, "%ld: ", lineno);
/* suppress extra newline at EOF unless we are labeling matches with file name */
Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
if(flag & Bflag)
Bflush(&bout);
}
if((lineno & Flshcnt) == 0)
Bflush(&bout);
cont:
bol = lp;
}
if(lp != elp)
goto loop;
goto loop0;
/*
* character loop for -i flag
* for speed
*/
loopi:
c = *lp;
if(c >= 'A' && c <= 'Z')
c += 'a'-'A';
ns = s->next[c];
if(ns == 0) {
increment(s, c);
goto loopi;
}
lp++;
s = ns;
if(c == '\n') {
lineno++;
if(!!s->match == !(flag&Vflag)) {
count++;
if(flag & (Cflag|Sflag|Llflag|LLflag))
goto conti;
if(flag & Hflag)
Bprint(&bout, "%s:", file);
if(flag & Nflag)
Bprint(&bout, "%ld: ", lineno);
/* suppress extra newline at EOF unless we are labeling matches with file name */
Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
if(flag & Bflag)
Bflush(&bout);
}
if((lineno & Flshcnt) == 0)
Bflush(&bout);
conti:
bol = lp;
}
if(lp != elp)
goto loopi;
goto loop0;
}
State*
initstate(Re *r)
{
State *s;
int i;
addcase(r);
if(flags['1'])
reprint("r", r);
nfollow = 0;
gen++;
fol1(r, Cbegin);
follow[nfollow++] = r;
qsort(follow, nfollow, sizeof(*follow), fcmp);
s = sal(nfollow);
for(i=0; i<nfollow; i++)
s->re[i] = follow[i];
return s;
}

20
src/cmd/grep/mkfile Normal file
View file

@ -0,0 +1,20 @@
PLAN9=../../..
<$PLAN9/src/mkhdr
# Calling this grep breaks a LOT. Like egrep on Linux.
# And probably configure.
TARG=9grep
HFILES=\
grep.h\
OFILES=\
y.tab.$O\
main.$O\
comp.$O\
sub.$O\
YFILES=grep.y\
SHORTLIB=bio 9
<$PLAN9/src/mkone

317
src/cmd/grep/sub.c Normal file
View file

@ -0,0 +1,317 @@
#include "grep.h"
void*
mal(int n)
{
static char *s;
static int m = 0;
void *v;
n = (n+3) & ~3;
if(m < n) {
if(n > Nhunk) {
v = sbrk(n);
memset(v, 0, n);
return v;
}
s = sbrk(Nhunk);
m = Nhunk;
}
v = s;
s += n;
m -= n;
memset(v, 0, n);
return v;
}
State*
sal(int n)
{
State *s;
s = mal(sizeof(*s));
// s->next = mal(256*sizeof(*s->next));
s->count = n;
s->re = mal(n*sizeof(*state0->re));
return s;
}
Re*
ral(int type)
{
Re *r;
r = mal(sizeof(*r));
r->type = type;
maxfollow++;
return r;
}
void
error(char *s)
{
fprint(2, "grep: internal error: %s\n", s);
exits(s);
}
int
countor(Re *r)
{
int n;
n = 0;
loop:
switch(r->type) {
case Tor:
n += countor(r->alt);
r = r->next;
goto loop;
case Tclass:
return n + r->hi - r->lo + 1;
}
return n;
}
Re*
oralloc(int t, Re *r, Re *b)
{
Re *a;
if(b == 0)
return r;
a = ral(t);
a->alt = r;
a->next = b;
return a;
}
void
case1(Re *c, Re *r)
{
int n;
loop:
switch(r->type) {
case Tor:
case1(c, r->alt);
r = r->next;
goto loop;
case Tclass: /* add to character */
for(n=r->lo; n<=r->hi; n++)
c->cases[n] = oralloc(Tor, r->next, c->cases[n]);
break;
default: /* add everything unknown to next */
c->next = oralloc(Talt, r, c->next);
break;
}
}
Re*
addcase(Re *r)
{
int i, n;
Re *a;
if(r->gen == gen)
return r;
r->gen = gen;
switch(r->type) {
default:
error("addcase");
case Tor:
n = countor(r);
if(n >= Caselim) {
a = ral(Tcase);
a->cases = mal(256*sizeof(*a->cases));
case1(a, r);
for(i=0; i<256; i++)
if(a->cases[i]) {
r = a->cases[i];
if(countor(r) < n)
a->cases[i] = addcase(r);
}
return a;
}
return r;
case Talt:
r->next = addcase(r->next);
r->alt = addcase(r->alt);
return r;
case Tbegin:
case Tend:
case Tclass:
return r;
}
}
void
str2top(char *p)
{
Re2 oldtop;
oldtop = topre;
input = p;
topre.beg = 0;
topre.end = 0;
yyparse();
gen++;
if(topre.beg == 0)
yyerror("syntax");
if(oldtop.beg)
topre = re2or(oldtop, topre);
}
void
appendnext(Re *a, Re *b)
{
Re *n;
while(n = a->next)
a = n;
a->next = b;
}
void
patchnext(Re *a, Re *b)
{
Re *n;
while(a) {
n = a->next;
a->next = b;
a = n;
}
}
int
getrec(void)
{
int c;
if(flags['f']) {
c = Bgetc(rein);
if(c <= 0)
return 0;
} else
c = *input++ & 0xff;
if(flags['i'] && c >= 'A' && c <= 'Z')
c += 'a'-'A';
if(c == '\n')
lineno++;
return c;
}
Re2
re2cat(Re2 a, Re2 b)
{
Re2 c;
c.beg = a.beg;
c.end = b.end;
patchnext(a.end, b.beg);
return c;
}
Re2
re2star(Re2 a)
{
Re2 c;
c.beg = ral(Talt);
c.beg->alt = a.beg;
patchnext(a.end, c.beg);
c.end = c.beg;
return c;
}
Re2
re2or(Re2 a, Re2 b)
{
Re2 c;
c.beg = ral(Tor);
c.beg->alt = b.beg;
c.beg->next = a.beg;
c.end = b.end;
appendnext(c.end, a.end);
return c;
}
Re2
re2char(int c0, int c1)
{
Re2 c;
c.beg = ral(Tclass);
c.beg->lo = c0 & 0xff;
c.beg->hi = c1 & 0xff;
c.end = c.beg;
return c;
}
void
reprint1(Re *a)
{
int i, j;
loop:
if(a == 0)
return;
if(a->gen == gen)
return;
a->gen = gen;
print("%p: ", a);
switch(a->type) {
default:
print("type %d\n", a->type);
error("print1 type");
case Tcase:
print("case ->%p\n", a->next);
for(i=0; i<256; i++)
if(a->cases[i]) {
for(j=i+1; j<256; j++)
if(a->cases[i] != a->cases[j])
break;
print(" [%.2x-%.2x] ->%p\n", i, j-1, a->cases[i]);
i = j-1;
}
for(i=0; i<256; i++)
reprint1(a->cases[i]);
break;
case Tbegin:
print("^ ->%p\n", a->next);
break;
case Tend:
print("$ ->%p\n", a->next);
break;
case Tclass:
print("[%.2x-%.2x] ->%p\n", a->lo, a->hi, a->next);
break;
case Tor:
case Talt:
print("| %p ->%p\n", a->alt, a->next);
reprint1(a->alt);
break;
}
a = a->next;
goto loop;
}
void
reprint(char *s, Re *r)
{
print("%s:\n", s);
gen++;
reprint1(r);
print("\n\n");
}

View file

@ -3,11 +3,11 @@ PLAN9=../..
TARG=`ls *.c | sed 's/\.c//'`
LDFLAGS=$LDFLAGS
SHORTLIB=sec fs mux regexp9 thread bio 9
SHORTLIB=mach sec fs mux regexp9 thread bio 9
<$PLAN9/src/mkmany
BUGGERED='CVS|9term|faces|factotum|htmlfmt|mk|rio|upas|vac|venti'
BUGGERED='CVS|faces|factotum|htmlfmt|mk|upas|vac|venti'
DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
<$PLAN9/src/mkdirs

View file

@ -97,6 +97,7 @@ static Dirtab dir[NDIR] =
static int ndir = NQID;
static int srvfd;
#define clock plumbclock /* SunOS name clash */
static int clock;
static Fid *fids[Nhash];
static QLock readlock;

View file

@ -54,9 +54,10 @@ threadmain(int argc, char *argv[])
error("can't initialize $user or $home: %r");
if(plumbfile == nil){
sprint(buf, "%s/lib/plumbing", home);
if(access(buf, 0) < 0)
sprint(buf, "#9/plumb/initial.plumbing");
plumbfile = estrdup(buf);
if(access(buf, 0) >= 0)
plumbfile = estrdup(buf);
else
plumbfile = unsharp("#9/plumb/initial.plumbing");
}
fd = open(plumbfile, OREAD);

View file

@ -415,7 +415,7 @@ include(char *s)
fd = open(t, OREAD);
if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
snprint(buf, sizeof buf, "#9/plumb/%s", t);
t = buf;
t = unsharp(buf);
fd = open(t, OREAD);
}
if(fd < 0)

View file

@ -27,20 +27,10 @@ char *syssigname[]={
char*
Rcmain(void)
{
return "#9/rcmain";
/*
static char buf[256];
char *root;
root = getenv("PLAN9");
if(root == nil)
root = "/usr/local/plan9";
snprint(buf, sizeof buf, "%s/rcmain", root);
return buf;
*/
return unsharp("#9/rcmain");
}
char Fdprefix[]="#d/";
char Fdprefix[]="/dev/fd/";
void execfinit(void);
void execbind(void);
void execmount(void);

27
src/cmd/rio/Imakefile Normal file
View file

@ -0,0 +1,27 @@
INCLUDES = -I$(TOP)
DEPLIBS = $(DEPXLIB)
LOCAL_LIBRARIES = $(XLIB)
DEFINES = -DSHAPE # -g3 -DDEBUG -DDEBUG_EV
SRCS = main.c event.c manage.c menu.c client.c grab.c cursor.c error.c color.c
OBJS = main.o event.o manage.o menu.o client.o grab.o cursor.o error.o color.o
HFILES = dat.h fns.h patchlevel.h
MFILES = README 9wm.man Imakefile Makefile.no-imake
ComplexProgramTarget(rio)
bun:
bundle $(MFILES) $(SRCS) $(HFILES) >bun
dist:
bundle $(MFILES) main.c event.c manage.c >bun1
bundle menu.c client.c grab.c cursor.c error.c $(HFILES) >bun2
trout: 9wm.man
troff -man 9wm.man >trout
vu: trout
xditview trout
clean::
$(RM) bun bun[12] trout core

View file

@ -8,7 +8,7 @@
#include "fns.h"
unsigned long
colorpixel(Display *dpy, int depth, ulong rgb)
colorpixel(Display *dpy, int depth, unsigned long rgb)
{
int r, g, b;

View file

@ -9,6 +9,9 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
#include "dat.h"
#include "fns.h"
#include "patchlevel.h"
@ -70,12 +73,15 @@ main(int argc, char *argv[])
int i, background, do_exit, do_restart;
char *fname;
int shape_event;
#ifdef SHAPE
int dummy;
#endif
shape_event = 0;
myargv = argv; /* for restart */
do_exit = do_restart = 0;
background = 1;
background = 0;
font = 0;
fname = 0;
for (i = 1; i < argc; i++)
@ -289,12 +295,11 @@ initscreen(ScreenInfo *s, int i, int background)
XSync(dpy, False);
if (background) {
/*
XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
XClearWindow(dpy, s->root);
*/
} else
system("xsetroot -solid grey30");
}
s->menuwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 2, colorpixel(dpy, s->depth, 0x88CC88), colorpixel(dpy, s->depth, 0xE9FFE9));
s->sweepwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 4, s->red, colorpixel(dpy, s->depth, 0xEEEEEE));
}

View file

@ -1,3 +1,4 @@
PLAN9=../../..
<$PLAN9/src/mkhdr
OFILES=\
@ -18,3 +19,7 @@ TARG=rio
LDFLAGS=-L$X11/lib -lXext -lX11
<$PLAN9/src/mkone
CFLAGS=$CFLAGS -DSHAPE -I$X11/include

View file

@ -460,6 +460,9 @@ main(int argc, char *argv[])
int low;
Bits h;
codefile = unsharp(codefile);
brfile = unsharp(brfile);
Binit(&bin, 0, OREAD);
Binit(&bout, 1, OWRITE);
for(i=0; c = "aeiouyAEIOUY"[i]; i++)

View file

@ -399,7 +399,7 @@ others(void)
{
int c, i, j;
finput = Bopen(parser, OREAD);
finput = Bopen(unsharp(parser), OREAD);
if(finput == 0)
error("cannot open parser %s: %r", parser);
warray("yyr1", levprd, nprod);