123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- #include "awiki.h"
- Wiki *wlist;
- void
- link(Wiki *w)
- {
- if(w->linked)
- return;
- w->linked = 1;
- w->prev = nil;
- w->next = wlist;
- if(wlist)
- wlist->prev = w;
- wlist = w;
- }
- void
- unlink(Wiki *w)
- {
- if(!w->linked)
- return;
- w->linked = 0;
- if(w->next)
- w->next->prev = w->prev;
- if(w->prev)
- w->prev->next = w->next;
- else
- wlist = w->next;
- w->next = nil;
- w->prev = nil;
- }
- void
- wikiname(Window *w, char *name)
- {
- char *p, *q;
- p = emalloc(strlen(dir)+1+strlen(name)+1+1);
- strcpy(p, dir);
- strcat(p, "/");
- strcat(p, name);
- for(q=p; *q; q++)
- if(*q==' ')
- *q = '_';
- winname(w, p);
- free(p);
- }
- int
- wikiput(Wiki *w)
- {
- int fd, n;
- char buf[1024], *p;
- Biobuf *b;
- if((fd = open("new", ORDWR)) < 0){
- fprint(2, "Wiki: cannot open raw: %r\n");
- return -1;
- }
- winopenbody(w->win, OREAD);
- b = w->win->body;
- if((p = Brdline(b, '\n'))==nil){
- Short:
- winclosebody(w->win);
- fprint(2, "Wiki: no data\n");
- close(fd);
- return -1;
- }
- write(fd, p, Blinelen(b));
- snprint(buf, sizeof buf, "D%lud\n", w->time);
- if(email)
- snprint(buf+strlen(buf), sizeof(buf)-strlen(buf), "A%s\n", email);
- if(Bgetc(b) == '#'){
- p = Brdline(b, '\n');
- if(p == nil)
- goto Short;
- snprint(buf+strlen(buf), sizeof(buf)-strlen(buf), "C%s\n", p);
- }
- write(fd, buf, strlen(buf));
- write(fd, "\n\n", 2);
- while((n = Bread(b, buf, sizeof buf)) > 0)
- write(fd, buf, n);
- winclosebody(w->win);
- werrstr("");
- if((n=write(fd, "", 0)) != 0){
- fprint(2, "Wiki commit %lud %d %d: %r\n", w->time, fd, n);
- close(fd);
- return -1;
- }
- seek(fd, 0, 0);
- if((n = read(fd, buf, 300)) < 0){
- fprint(2, "Wiki readback: %r\n");
- close(fd);
- return -1;
- }
- close(fd);
- buf[n] = '\0';
- sprint(buf, "%s/", buf);
- free(w->arg);
- w->arg = estrdup(buf);
- w->isnew = 0;
- wikiget(w);
- wikiname(w->win, w->arg);
- return n;
- }
- void
- wikiget(Wiki *w)
- {
- char *p;
- int fd, normal;
- Biobuf *bin;
- fprint(w->win->ctl, "dirty\n");
- p = emalloc(strlen(w->arg)+8+1);
- strcpy(p, w->arg);
- normal = 1;
- if(p[strlen(p)-1] == '/'){
- normal = 0;
- strcat(p, "current");
- }else if(strlen(p)>8 && strcmp(p+strlen(p)-8, "/current")==0){
- normal = 0;
- w->arg[strlen(w->arg)-7] = '\0';
- }
- if((fd = open(p, OREAD)) < 0){
- fprint(2, "Wiki: cannot read %s: %r\n", p);
- winclean(w->win);
- return;
- }
- free(p);
- winopenbody(w->win, OWRITE);
- bin = emalloc(sizeof(*bin));
- Binit(bin, fd, OREAD);
- p = nil;
- if(!normal){
- if((p = Brdline(bin, '\n')) == nil){
- fprint(2, "Wiki: cannot read title: %r\n");
- winclean(w->win);
- close(fd);
- free(bin);
- return;
- }
- p[Blinelen(bin)-1] = '\0';
- }
- /* clear window */
- if(w->win->data < 0)
- w->win->data = winopenfile(w->win, "data");
- if(winsetaddr(w->win, ",", 0))
- write(w->win->data, "", 0);
- if(!normal)
- Bprint(w->win->body, "%s\n\n", p);
- while(p = Brdline(bin, '\n')){
- p[Blinelen(bin)-1] = '\0';
- if(normal)
- Bprint(w->win->body, "%s\n", p);
- else{
- if(p[0]=='D')
- w->time = strtoul(p+1, 0, 10);
- else if(p[0]=='#')
- Bprint(w->win->body, "%s\n", p+1);
- }
- }
- winclean(w->win);
- free(bin);
- close(fd);
- }
- static int
- iscmd(char *s, char *cmd)
- {
- int len;
- len = strlen(cmd);
- return strncmp(s, cmd, len)==0 && (s[len]=='\0' || s[len]==' ' || s[len]=='\t' || s[len]=='\n');
- }
- static char*
- skip(char *s, char *cmd)
- {
- s += strlen(cmd);
- while(*s==' ' || *s=='\t' || *s=='\n')
- s++;
- return s;
- }
- int
- wikiload(Wiki *w, char *arg)
- {
- char *p, *q, *path, *addr;
- int rv;
- p = nil;
- if(arg[0] == '/')
- path = arg;
- else{
- p = emalloc(strlen(w->arg)+1+strlen(arg)+1);
- strcpy(p, w->arg);
- if(q = strrchr(p, '/')){
- ++q;
- *q = '\0';
- }else
- *p = '\0';
- strcat(p, arg);
- cleanname(p);
- path = p;
- }
- if(addr=strchr(path, ':'))
- *addr++ = '\0';
- rv = wikiopen(path, addr)==0;
- free(p);
- if(rv)
- return 1;
- return wikiopen(arg, 0)==0;
- }
- /* return 1 if handled, 0 otherwise */
- int
- wikicmd(Wiki *w, char *s)
- {
- char *p;
- s = skip(s, "");
- if(iscmd(s, "Del")){
- if(windel(w->win, 0))
- w->dead = 1;
- return 1;
- }
- if(iscmd(s, "New")){
- wikinew(skip(s, "New"));
- return 1;
- }
- if(iscmd(s, "History"))
- return wikiload(w, "history.txt");
- if(iscmd(s, "Diff"))
- return wikidiff(w);
- if(iscmd(s, "Get")){
- if(winisdirty(w->win) && !w->win->warned){
- w->win->warned = 1;
- fprint(2, "%s/%s modified\n", dir, w->arg);
- }else{
- w->win->warned = 0;
- wikiget(w);
- }
- return 1;
- }
- if(iscmd(s, "Put")){
- if((p=strchr(w->arg, '/')) && p[1]!='\0')
- fprint(2, "%s/%s is read-only\n", dir, w->arg);
- else
- wikiput(w);
- return 1;
- }
- return 0;
- }
- /* need to expand selection more than default word */
- static long
- eval(Window *w, char *s, ...)
- {
- char buf[64];
- va_list arg;
- va_start(arg, s);
- vsnprint(buf, sizeof buf, s, arg);
- va_end(arg);
- if(winsetaddr(w, buf, 1)==0)
- return -1;
- if(pread(w->addr, buf, 24, 0) != 24)
- return -1;
- return strtol(buf, 0, 10);
- }
- static int
- getdot(Window *w, long *q0, long *q1)
- {
- char buf[24];
- ctlprint(w->ctl, "addr=dot\n");
- if(pread(w->addr, buf, 24, 0) != 24)
- return -1;
- *q0 = atoi(buf);
- *q1 = atoi(buf+12);
- return 0;
- }
- static Event*
- expand(Window *w, Event *e, Event *eacme)
- {
- long q0, q1, x;
- if(getdot(w, &q0, &q1)==0 && q0 <= e->q0 && e->q0 <= q1){
- e->q0 = q0;
- e->q1 = q1;
- return e;
- }
- q0 = eval(w, "#%lud-/\\[/", e->q0);
- if(q0 < 0)
- return eacme;
- if(eval(w, "#%lud+/\\]/", q0) < e->q0) /* [ closes before us */
- return eacme;
- q1 = eval(w, "#%lud+/\\]/", e->q1);
- if(q1 < 0)
- return eacme;
- if((x=eval(w, "#%lud-/\\[/", q1))==-1 || x > e->q1) /* ] opens after us */
- return eacme;
- e->q0 = q0+1;
- e->q1 = q1;
- return e;
- }
- void
- acmeevent(Wiki *wiki, Event *e)
- {
- Event *ea, *e2, *eq;
- Window *w;
- char *s, *t, *buf;
- int na;
- w = wiki->win;
- switch(e->c1){ /* origin of action */
- default:
- Unknown:
- fprint(2, "unknown message %c%c\n", e->c1, e->c2);
- break;
- case 'F': /* generated by our actions; ignore */
- break;
- case 'E': /* write to body or tag; can't affect us */
- break;
- case 'K': /* type away; we don't care */
- if(e->c2 == 'I' || e->c2 == 'D')
- w->warned = 0;
- break;
- case 'M': /* mouse event */
- switch(e->c2){ /* type of action */
- case 'x': /* mouse: button 2 in tag */
- case 'X': /* mouse: button 2 in body */
- ea = nil;
- //e2 = nil;
- s = e->b;
- if(e->flag & 2){ /* null string with non-null expansion */
- e2 = recvp(w->cevent);
- if(e->nb==0)
- s = e2->b;
- }
- if(e->flag & 8){ /* chorded argument */
- ea = recvp(w->cevent); /* argument */
- na = ea->nb;
- recvp(w->cevent); /* ignore origin */
- }else
- na = 0;
-
- /* append chorded arguments */
- if(na){
- t = emalloc(strlen(s)+1+na+1);
- sprint(t, "%s %s", s, ea->b);
- s = t;
- }
- /* if it's a known command, do it */
- /* if it's a long message, it can't be for us anyway */
- // DPRINT(2, "exec: %s\n", s);
- if(!wikicmd(wiki, s)) /* send it back */
- winwriteevent(w, e);
- if(na)
- free(s);
- break;
- case 'l': /* mouse: button 3 in tag */
- case 'L': /* mouse: button 3 in body */
- //buf = nil;
- eq = e;
- if(e->flag & 2){ /* we do our own expansion for loads */
- e2 = recvp(w->cevent);
- eq = expand(w, eq, e2);
- }
- s = eq->b;
- if(eq->q1>eq->q0 && eq->nb==0){
- buf = emalloc((eq->q1-eq->q0)*UTFmax+1);
- winread(w, eq->q0, eq->q1, buf);
- s = buf;
- }
- if(!wikiload(wiki, s))
- winwriteevent(w, e);
- break;
- case 'i': /* mouse: text inserted in tag */
- case 'd': /* mouse: text deleted from tag */
- break;
- case 'I': /* mouse: text inserted in body */
- case 'D': /* mouse: text deleted from body */
- w->warned = 0;
- break;
- default:
- goto Unknown;
- }
- }
- }
- void
- wikithread(void *v)
- {
- char tmp[40];
- Event *e;
- Wiki *w;
- w = v;
- if(w->isnew){
- sprint(tmp, "+new+%d", w->isnew);
- wikiname(w->win, tmp);
- if(w->arg){
- winopenbody(w->win, OWRITE);
- Bprint(w->win->body, "%s\n\n", w->arg);
- }
- winclean(w->win);
- }else if(!w->special){
- wikiget(w);
- wikiname(w->win, w->arg);
- if(w->addr)
- winselect(w->win, w->addr, 1);
- }
- fprint(w->win->ctl, "menu\n");
- wintagwrite(w->win, "Get History Diff New", 4+8+4+4);
- winclean(w->win);
-
- while(!w->dead && (e = recvp(w->win->cevent)))
- acmeevent(w, e);
- windormant(w->win);
- unlink(w);
- free(w->win);
- free(w->arg);
- free(w);
- threadexits(nil);
- }
- int
- wikiopen(char *arg, char *addr)
- {
- Dir *d;
- char *p;
- Wiki *w;
- /*
- if(arg==nil){
- if(write(mapfd, title, strlen(title)) < 0
- || seek(mapfd, 0, 0) < 0 || (n=read(mapfd, tmp, sizeof(tmp)-2)) < 0){
- fprint(2, "Wiki: no page '%s' found: %r\n", title);
- return -1;
- }
- if(tmp[n-1] == '\n')
- tmp[--n] = '\0';
- tmp[n++] = '/';
- tmp[n] = '\0';
- arg = tmp;
- }
- */
- /* replace embedded '\n' in links by ' ' */
- for(p=arg; *p; p++)
- if(*p=='\n')
- *p = ' ';
- if(strncmp(arg, dir, strlen(dir))==0 && arg[strlen(dir)]=='/' && arg[strlen(dir)+1])
- arg += strlen(dir)+1;
- else if(arg[0] == '/')
- return -1;
- if((d = dirstat(arg)) == nil)
- return -1;
- if((d->mode&DMDIR) && arg[strlen(arg)-1] != '/'){
- p = emalloc(strlen(arg)+2);
- strcpy(p, arg);
- strcat(p, "/");
- arg = p;
- }else if(!(d->mode&DMDIR) && arg[strlen(arg)-1]=='/'){
- arg = estrdup(arg);
- arg[strlen(arg)-1] = '\0';
- }else
- arg = estrdup(arg);
- free(d);
- /* rewrite /current into / */
- if(strlen(arg) > 8 && strcmp(arg+strlen(arg)-8, "/current")==0)
- arg[strlen(arg)-8+1] = '\0';
- /* look for window already open */
- for(w=wlist; w; w=w->next){
- if(strcmp(w->arg, arg)==0){
- ctlprint(w->win->ctl, "show\n");
- return 0;
- }
- }
- w = emalloc(sizeof *w);
- w->arg = arg;
- w->addr = addr;
- w->win = newwindow();
- link(w);
- proccreate(wineventproc, w->win, STACK);
- threadcreate(wikithread, w, STACK);
- return 0;
- }
- void
- wikinew(char *arg)
- {
- static int n;
- Wiki *w;
- w = emalloc(sizeof *w);
- if(arg)
- arg = estrdup(arg);
- w->arg = arg;
- w->win = newwindow();
- w->isnew = ++n;
- proccreate(wineventproc, w->win, STACK);
- threadcreate(wikithread, w, STACK);
- }
- typedef struct Diffarg Diffarg;
- struct Diffarg {
- Wiki *w;
- char *dir;
- };
- void
- execdiff(void *v)
- {
- char buf[64];
- Diffarg *a;
- a = v;
- rfork(RFFDG);
- close(0);
- open("/dev/null", OREAD);
- sprint(buf, "/mnt/wsys/%d/body", a->w->win->id);
- close(1);
- open(buf, OWRITE);
- close(2);
- open(buf, OWRITE);
- sprint(buf, "/mnt/wsys/%d", a->w->win->id);
- bind(buf, "/dev", MBEFORE);
-
- procexecl(nil, "/acme/wiki/wiki.diff", "wiki.diff", a->dir, nil);
- }
- int
- wikidiff(Wiki *w)
- {
- Diffarg *d;
- char *p, *q, *r;
- Wiki *nw;
- p = emalloc(strlen(w->arg)+10);
- strcpy(p, w->arg);
- if(q = strchr(p, '/'))
- *q = '\0';
- r = estrdup(p);
- strcat(p, "/+Diff");
- nw = emalloc(sizeof *w);
- nw->arg = p;
- nw->win = newwindow();
- nw->special = 1;
- d = emalloc(sizeof(*d));
- d->w = nw;
- d->dir = r;
- wikiname(nw->win, p);
- proccreate(wineventproc, nw->win, STACK);
- proccreate(execdiff, d, STACK);
- threadcreate(wikithread, nw, STACK);
- return 1;
- }
|