plan9fox/acme/bin/source/adict/adict.c
2011-04-14 17:27:24 +00:00

592 lines
11 KiB
C

#include <u.h>
#include <libc.h>
#include <bio.h>
#include <thread.h>
#include "win.h"
#include "adict.h"
enum
{
STACK = 8192,
};
char *prog = "adict";
char *lprog = "/bin/adict";
char *xprog = "/bin/dict";
char *dict, *pattern, *curaddr[MAXMATCH], *curone, *args[6], buffer[80];
char abuffer[80], fbuffer[80], pbuffer[80];
int curindex, count, Eopen, Mopen;
Win Mwin, Ewin, Dwin;
void openwin(char*, char*, Win*, int);
void handle(Win*, int);
void rexec(void*);
void pexec(void*);
int getaddr(char*);
void
usage(void)
{
fprint(2, "usage: %s [-d dictname] [pattern]\n", argv0);
threadexitsall(nil);
}
int mainstacksize = STACK;
void
threadmain(int argc, char** argv)
{
ARGBEGIN{
case 'd':
dict = strdup(ARGF());
break;
default:
usage();
}ARGEND
/* if running as other name, note that fact */
if(access(argv0, AEXIST) == 0)
lprog = argv0;
switch(argc){
case 1:
pattern = pbuffer;
strcpy(pattern,argv[0]);
if(dict == nil)
dict = "pgw";
break;
case 0:
break;
default:
usage();
}
if ((dict == nil) && (pattern == nil))
openwin(prog,"", &Dwin, Dictwin);
if (pattern == nil)
openwin(prog,"",&Ewin, Entrywin);
if ((count = getaddr(pattern)) <= 1)
openwin(prog,"Prev Next", &Ewin, Entrywin);
else
openwin(prog, "", &Mwin, Matchwin);
}
static int
procrexec(char *xprog, ...)
{
int fpipe[2];
void *rexarg[4];
Channel *c;
va_list va;
int i;
char *p;
pipe(fpipe);
va_start(va, xprog);
p = xprog;
for(i=0; p && i+1<nelem(args); i++){
args[i] = p;
p = va_arg(va, char*);
}
args[i] = nil;
c = chancreate(sizeof(ulong), 0);
rexarg[0] = xprog;
rexarg[1] = args;
rexarg[2] = fpipe;
rexarg[3] = c;
proccreate(rexec, rexarg, STACK);
recvul(c);
chanfree(c);
close(fpipe[1]);
return fpipe[0];
}
int
getaddr(char *pattern)
{
/* Get char offset into dictionary of matches. */
int fd, i;
Biobuf inbuf;
char *bufptr;
char *obuf;
if (pattern == nil) {
curone = nil;
curindex = 0;
curaddr[curindex] = nil;
return 0;
}
sprint(buffer,"/%s/A", pattern);
fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
Binit(&inbuf, fd, OREAD);
i = 0;
curindex = 0;
while ((bufptr = Brdline(&inbuf, '\n')) != nil && (i < (MAXMATCH-1))) {
bufptr[Blinelen(&inbuf)-1] = 0;
obuf=bufptr;
while (bufptr[0] != '#' && bufptr[0] != 0) bufptr++;
if(bufptr[0] == 0)
print("whoops buf «%s»\n", obuf);
curaddr[i] = malloc(strlen(bufptr));
strcpy(curaddr[i], bufptr);
i++;
}
curaddr[i] = nil;
if (i == MAXMATCH)
fprint(2, "Too many matches!\n");
Bterm(&inbuf);
close(fd);
curone = curaddr[curindex];
return(i);
}
char*
getpattern(char *addr)
{
/* Get the pattern corresponding to an absolute address.*/
int fd;
char *res, *t;
res = nil;
sprint(buffer,"%sh", addr);
fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
if (read(fd, pbuffer, 80) > 80)
fprint(2, "Error in getting addres from dict.\n");
else {
t = pbuffer;
/* remove trailing whitespace, newline */
if (t != nil){
while(*t != 0 && *t != '\n')
t++;
if(t == 0 && t > pbuffer)
t--;
while(t >= pbuffer && (*t==' ' || *t=='\n' || *t=='\t' || *t=='\r'))
*t-- = 0;
}
res = pbuffer;
}
close(fd);
return(res);
}
char*
chgaddr(int dir)
{
/* Increment or decrement the current address (curone). */
int fd;
char *res, *t;
res = nil;
if (dir < 0)
sprint(buffer,"%s-a", curone);
else
sprint(buffer,"%s+a", curone);
fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
if (read(fd, abuffer, 80) > 80)
fprint(2, "Error in getting addres from dict.\n");
else {
res = abuffer;
while (*res != '#') res++;
t = res;
while ((*t != '\n') && (t != nil)) t++;
if (t != nil) *t = 0;
}
close(fd);
return(res);
}
void
dispdicts(Win *cwin)
{
/* Display available dictionaries in window. */
int fd, nb, i;
char buf[1024], *t;
fd = procrexec(xprog, "-d", "?", nil);
wreplace(cwin, "0,$","",0); /* Clear window */
while ((nb = read(fd, buf, 1024)) > 0) {
t = buf;
i = 0;
if (strncmp("Usage", buf, 5) == 0) { /* Remove first line. */
while (t[0] != '\n') {
t++;
i++;
}
t++;
i++;
}
wwritebody(cwin, t, nb-i);
}
close(fd);
wclean(cwin);
}
void
dispentry(Win *cwin)
{
/* Display the current selection in window. */
int fd, nb;
char buf[BUFSIZE];
if (curone == nil) {
if (pattern != nil) {
sprint(buf,"Pattern not found.\n");
wwritebody(cwin, buf, 19);
wclean(cwin);
}
return;
}
sprint(buffer,"%sp", curone);
fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
wreplace(cwin, "0,$","",0); /* Clear window */
while ((nb = read(fd, buf, BUFSIZE)) > 0) {
wwritebody(cwin, buf, nb);
}
close(fd);
wclean(cwin);
}
void
dispmatches(Win *cwin)
{
/* Display the current matches. */
int fd, nb;
char buf[BUFSIZE];
sprint(buffer,"/%s/H", pattern);
fd = procrexec(xprog, "-d", dict, "-c", buffer, nil);
while ((nb = read(fd, buf, BUFSIZE)) > 0)
wwritebody(cwin, buf, nb);
close(fd);
wclean(cwin);
}
char*
format(char *s)
{
/* Format a string to be written in window tag. Acme doesn't like */
/* non alpha-num's in the tag line. */
char *t, *h;
t = fbuffer;
if (s == nil) {
*t = 0;
return t;
}
strcpy(t, s);
h = t;
while (*t != 0) {
if (!(((*t >= 'a') && (*t <= 'z')) ||
((*t >= 'A') && (*t <= 'Z')) ||
((*t >= '0') && (*t <= '9'))))
*t = '_';
t++;
}
if (strlen(h) > MAXTAG)
h[MAXTAG] = 0;
if (strcmp(s,h) == 0) return s;
return h;
}
void
openwin(char *name, char *buttons, Win *twin, int wintype)
{
char buf[80];
wnew(twin);
if (wintype == Dictwin)
sprint(buf,"%s",name);
else
if ((wintype == Entrywin) && (count > 1))
sprint(buf,"%s/%s/%s/%d",name, dict, format(pattern), curindex+1);
else
sprint(buf,"%s/%s/%s",name, dict, format(pattern));
wname(twin, buf);
wtagwrite(twin, buttons, strlen(buttons));
wclean(twin);
wdormant(twin);
if (wintype == Dictwin)
dispdicts(twin);
if (wintype == Matchwin) {
Mopen = True;
dispmatches(twin);
}
if (wintype == Entrywin) {
Eopen = True;
dispentry(twin);
}
handle(twin, wintype);
}
void
vopenwin(void *v)
{
void **arg;
char *name, *buttons;
Win *twin;
int wintype;
arg = v;
name = arg[0];
buttons = arg[1];
twin = arg[2];
wintype = (int)arg[3];
sendul(arg[4], 0);
openwin(name, buttons, twin, wintype);
threadexits(nil);
}
void
procopenwin(char *name, char *buttons, Win *twin, int wintype)
{
void *arg[5];
Channel *c;
c = chancreate(sizeof(ulong), 0);
arg[0] = name;
arg[1] = buttons;
arg[2] = twin;
arg[3] = (void*)wintype;
arg[4] = c;
proccreate(vopenwin, arg, STACK);
recvul(c);
chanfree(c);
}
void
rexec(void *v)
{
void **arg;
char *prog;
char **args;
int *fd;
Channel *c;
arg = v;
prog = arg[0];
args = arg[1];
fd = arg[2];
c = arg[3];
rfork(RFENVG|RFFDG);
dup(fd[1], 1);
close(fd[1]);
close(fd[0]);
procexec(c, prog, args);
fprint(2, "Remote pipe execution failed: %s %r\n", prog);
abort();
threadexits(nil);
}
void
pexec(void *v)
{
void **arg;
char *prog;
char **args;
Channel *c;
arg = v;
prog = arg[0];
args = arg[1];
c = arg[2];
procexec(c, prog, args);
fprint(2, "Remote execution failed: %s %r\n", prog);
abort();
threadexits(nil);
}
void
procpexec(char *prog, char **args)
{
void *rexarg[4];
Channel *c;
c = chancreate(sizeof(ulong), 0);
rexarg[0] = prog;
rexarg[1] = args;
rexarg[2] = c;
proccreate(pexec, rexarg, STACK);
recvul(c);
chanfree(c);
}
void
kill(void)
{
/* Kill all processes related to this one. */
int fd;
sprint(buffer, "/proc/%d/notepg", getpid());
fd = open(buffer, OWRITE);
rfork(RFNOTEG);
write(fd, "kill", 4);
}
int
command(char *com, Win *w, int wintype)
{
char *buf;
if (strncmp(com, "Del", 3) == 0) {
switch(wintype){
case Entrywin:
if (wdel(w)) {
Eopen = False;
threadexits(nil);
}
break;
case Dictwin:
if (wdel(w))
threadexits(nil);
break;
case Matchwin:
kill();
if (Eopen)
if (~wdel(&Ewin)) /* Remove the entry window */
wdel(&Ewin);
if (!wdel(w))
wdel(w);
threadexits(nil);
break;
}
return True;
}
if (strncmp(com, "Next", 4) == 0){
if (curone != nil) {
curone = chgaddr(1);
buf = getpattern(curone);
sprint(buffer,"%s/%s/%s", prog, dict, format(buf));
wname(w, buffer);
dispentry(w);
}
return True;
}
if (strncmp(com, "Prev",4) == 0){
if (curone != nil) {
curone = chgaddr(-1);
buf = getpattern(curone);
sprint(buffer,"%s/%s/%s", prog, dict, format(buf));
wname(w, buffer);
dispentry(w);
}
return True;
}
if (strncmp(com, "Nmatch",6) == 0){
if (curaddr[++curindex] == nil)
curindex = 0;
curone = curaddr[curindex];
if (curone != nil) {
sprint(buffer,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1);
wname(w, buffer);
dispentry(w);
}
return True;
}
return False;
}
void
handle(Win *w, int wintype)
{
Event e, e2, ea, etoss;
char *s, *t, buf[80];
int tmp, na;
while (True) {
wevent(w, &e);
switch(e.c2){
default:
/* fprint(2,"unknown message %c%c\n", e.c1, e.c2); */
break;
case 'i':
/* fprint(2,"'%s' inserted in tag at %d\n", e.b, e.q0);*/
break;
case 'I':
/* fprint(2,"'%s' inserted in body at %d\n", e.b, e.q0);*/
break;
case 'd':
/* fprint(2, "'%s' deleted in tag at %d\n", e.b, e.q0);*/
break;
case 'D':
/* fprint(2, "'%s' deleted in body at %d\n", e.b, e.q0);*/
break;
case 'x':
case 'X': /* Execute command. */
if (e.flag & 2)
wevent(w, &e2);
if(e.flag & 8){
wevent(w, &ea);
wevent(w, &etoss);
na = ea.nb;
} else
na = 0;
s = e.b;
if ((e.flag & 2) && e.nb == 0)
s = e2.b;
if(na){
t = malloc(strlen(s)+1+na+1);
snprint(t, strlen(s)+1+na+1, "%s %s", s, ea.b);
s = t;
}
/* if it's a long message, it can't be for us anyway */
if(!command(s, w, wintype)) /* send it back */
wwriteevent(w, &e);
if(na)
free(s);
break;
case 'l':
case 'L': /* Look for something. */
if (e.flag & 2)
wevent(w, &e);
wclean(w); /* Set clean bit. */
if (wintype == Dictwin) {
strcpy(buf, e.b);
args[0] = lprog;
args[1] = "-d";
args[2] = buf;
args[3] = nil;
procpexec(lprog, args); /* New adict with chosen dict. */
}
if (wintype == Entrywin) {
strcpy(buf, e.b);
args[0] = lprog;
args[1] = "-d";
args[2] = dict;
args[3] = buf;
args[4] = nil;
procpexec(lprog, args); /* New adict with chosen pattern. */
}
if (wintype == Matchwin) {
tmp = atoi(e.b) - 1;
if ((tmp >= 0) && (tmp < MAXMATCH) && (curaddr[tmp] != nil)) {
curindex = tmp;
curone = curaddr[curindex];
/* Display selected match. */
if (Eopen) {
sprint(buf,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1);
wname(&Ewin, buf);
dispentry(&Ewin);
}
else
procopenwin(prog,"Nmatch Prev Next", &Ewin, Entrywin);
}
}
break;
}
}
}