9 * Get HTML and text templates from underlying file system.
10 * Caches them, which means changes don't take effect for
11 * up to Tcache seconds after they are made.
13 * If the files are deleted, we keep returning the last
20 static char *name[2*Ntemplate] = {
24 [Thistory] "history.html",
26 [Toldpage] "oldpage.html",
27 [Twerror] "werror.html",
28 [Ntemplate+Tpage] "page.txt",
29 [Ntemplate+Tdiff] "diff.txt",
30 [Ntemplate+Thistory] "history.txt",
31 [Ntemplate+Toldpage] "oldpage.txt",
32 [Ntemplate+Twerror] "werror.txt",
57 for(i=0; i<2*Ntemplate; i++)
59 cache[i].s = s_copy("");
78 if(0 && cache[type].t+Tcache >= time(0)){
79 s = s_incref(cache[type].s);
80 runlock(&cache[type]);
83 runlock(&cache[type]);
87 if(0 && cache[type].t+Tcache >= time(0) || (d = wdirstat(name[type])) == nil)
90 if(0 && d->qid.vers == cache[type].qid.vers && d->qid.path == cache[type].qid.path){
91 cache[type].t = time(0);
95 if((b = wBopen(name[type], OREAD)) == nil)
100 n = s_read(b, ns, Bsize);
108 s_free(cache[type].s);
110 cache[type].qid = d->qid;
111 cache[type].t = time(0);
115 s = s_incref(cache[type].s);
116 wunlock(&cache[type]);
122 * Write wiki document in HTML.
125 s_escappend(String *s, char *p, int pre)
129 while(q = strpbrk(p, pre ? "<>&" : " <>&")){
130 s = s_nappend(s, p, q-p);
133 s = s_append(s, "<");
136 s = s_append(s, ">");
139 s = s_append(s, "&");
142 s = s_append(s, "\n");
151 mkurl(char *s, int ty)
155 if(strncmp(s, "http:", 5)==0
156 || strncmp(s, "https:", 6)==0
157 || strncmp(s, "#", 1)==0
158 || strncmp(s, "ftp:", 4)==0
159 || strncmp(s, "mailto:", 7)==0
160 || strncmp(s, "telnet:", 7)==0
161 || strncmp(s, "file:", 5)==0)
164 if(strchr(s, ' ')==nil && strchr(s, '@')!=nil){
165 p = emalloc(strlen(s)+8);
166 strcpy(p, "mailto:");
172 p = smprint("../../%s", s);
174 p = smprint("../%s", s);
182 int okayinlist[Nwtxt] =
190 int okayinpre[Nwtxt] =
197 int okayinpara[Nwtxt] =
219 pagehtml(String *s, Wpage *wtxt, int ty)
222 int inlist, inpara, inpre, t, tnext;
229 for(w=wtxt; w; w=w->next){
233 tnext = w->next->type;
235 if(inlist && !okayinlist[t]){
237 s = s_append(s, "\n</li>\n</ul>\n");
239 if(inpre && !okayinpre[t]){
241 s = s_append(s, "</pre>\n");
246 p = nospaces(w->text);
248 "\n<a name=\"", p, "\" /><h3>",
249 w->text, "</h3>\n", nil);
255 s = s_append(s, "\n</p>\n");
258 if(okayinpara[tnext]){
259 s = s_append(s, "\n<p class='para'>\n");
267 s = s_append(s, "\n<ul>\n");
269 s = s_append(s, "\n</li>\n");
270 s = s_append(s, "\n<li>\n");
275 p = mkurl(w->text, ty);
278 s = s_appendlist(s, "<a href=\"", p, "\">", nil);
279 s = s_escappend(s, w->text, 0);
280 s = s_append(s, "</a>");
286 sprint(tmp, "%d", w->section);
288 "<a href=\"http://plan9.bell-labs.com/magic/man2html/",
289 tmp, "/", w->text, "\"><i>", w->text, "</i>(",
296 s = s_append(s, "\n<pre>\n");
298 s = s_escappend(s, w->text, 1);
299 s = s_append(s, "\n");
303 s = s_append(s, "<hr />");
307 s = s_escappend(s, w->text, 0);
312 s = s_append(s, "\n</li>\n</ul>\n");
314 s = s_append(s, "</pre>\n");
316 s = s_append(s, "\n</p>\n");
321 copythru(String *s, char **newp, int *nlinep, int l)
330 if(r = strchr(q, '\n'))
341 return s_nappend(s, oq, q-oq);
345 dodiff(char *f1, char *f2)
360 execl("/bin/diff", "diff", f1, f2, nil);
368 /* print document i grayed out, with only diffs relative to j in black */
370 s_diff(String *s, Whist *h, int i, int j)
373 int fdiff, fd1, fd2, n1, n2;
375 char fn1[40], fn2[40];
380 return pagehtml(s, h->doc[i].wtxt, Tpage);
382 strcpy(fn1, "/tmp/wiki.XXXXXX");
383 strcpy(fn2, "/tmp/wiki.XXXXXX");
384 if((fd1 = opentemp(fn1)) < 0 || (fd2 = opentemp(fn2)) < 0){
386 s = s_append(s, "\nopentemp failed; sorry\n");
390 new = pagehtml(s_reset(nil), h->doc[i].wtxt, Tpage);
391 old = pagehtml(s_reset(nil), h->doc[j].wtxt, Tpage);
392 write(fd1, s_to_c(new), s_len(new));
393 write(fd2, s_to_c(old), s_len(old));
395 fdiff = dodiff(fn2, fn1);
397 s = s_append(s, "\ndiff failed; sorry\n");
401 Binit(&b, fdiff, OREAD);
402 while(p = Brdline(&b, '\n')){
403 if(p[0]=='<' || p[0]=='>' || p[0]=='-')
405 p[Blinelen(&b)-1] = '\0';
406 if((p = strpbrk(p, "acd")) == nil)
409 if(q = strchr(p, ','))
416 s = s_append(s, "<span class='old_text'>");
417 s = copythru(s, &pnew, &nline, n1-1);
418 s = s_append(s, "</span><span class='new_text'>");
419 s = copythru(s, &pnew, &nline, n2);
420 s = s_append(s, "</span>");
425 s = s_append(s, "<span class='old_text'>");
426 s = s_append(s, pnew);
427 s = s_append(s, "</span>");
438 diffhtml(String *s, Whist *h)
444 for(i=h->ndoc-1; i>=0; i--){
445 s = s_append(s, "<hr /><div class='diff_head'>\n");
447 sprint(tmp, "index.html");
449 sprint(tmp, "%lud", h->doc[i].time);
450 atime = ctime(h->doc[i].time);
451 atime[strlen(atime)-1] = '\0';
453 "<a href=\"", tmp, "\">",
456 s = s_appendlist(s, ", ", h->doc[i].author, nil);
457 if(h->doc[i].conflict)
458 s = s_append(s, ", conflicting write");
459 s = s_append(s, "\n");
460 if(h->doc[i].comment)
461 s = s_appendlist(s, "<br /><i>", h->doc[i].comment, "</i>\n", nil);
462 s = s_append(s, "</div><hr />");
463 s = s_diff(s, h, i, i-1);
465 s = s_append(s, "<hr>");
470 historyhtml(String *s, Whist *h)
476 s = s_append(s, "<ul>\n");
477 for(i=h->ndoc-1; i>=0; i--){
479 sprint(tmp, "index.html");
481 sprint(tmp, "%lud", h->doc[i].time);
482 atime = ctime(h->doc[i].time);
483 atime[strlen(atime)-1] = '\0';
485 "<li><a href=\"", tmp, "\">",
488 s = s_appendlist(s, ", ", h->doc[i].author, nil);
489 if(h->doc[i].conflict)
490 s = s_append(s, ", conflicting write");
491 s = s_append(s, "\n");
492 if(h->doc[i].comment)
493 s = s_appendlist(s, "<br><i>", h->doc[i].comment, "</i>\n", nil);
495 s = s_append(s, "</ul>");
500 tohtml(Whist *h, Wdoc *d, int ty)
503 char *p, *q, ver[40];
509 if(p = strstr(s_to_c(t), "PAGE"))
512 p = s_to_c(t)+s_len(t);
518 sub[nsub] = (Sub){ "TITLE", h->title };
522 sprint(ver, "%lud", d->time);
523 sub[nsub] = (Sub){ "VERSION", ver };
525 atime = ctime(d->time);
526 atime[strlen(atime)-1] = '\0';
527 sub[nsub] = (Sub){ "DATE", atime };
532 s = s_appendsub(s, s_to_c(t), p-s_to_c(t), sub, nsub);
536 s = pagehtml(s, d->wtxt, ty);
539 s = pagetext(s, d->wtxt, 0);
545 s = historyhtml(s, h);
552 s = s_appendsub(s, q, strlen(q), sub, nsub);
562 s_appendbrk(String *s, char *p, char *prefix, int dosharp)
571 e = strrchr(s_to_c(s), '\n');
576 if(utflen(e) <= LINELEN)
580 x+=chartorune(&r, x);
589 if(w-s_to_c(s) < strlen(prefix))
610 s_endline(String *s, int dosharp)
613 if(s->ptr == s->base+1 && s->ptr[-1] == '#')
616 if(s->ptr > s->base+1 && s->ptr[-1] == '#' && s->ptr[-2] == '\n')
620 if(s->ptr > s->base+1 && s->ptr[-1] == '\n')
627 pagetext(String *s, Wpage *page, int dosharp)
630 char *prefix, *sharp, tmp[40];
637 sharp = dosharp ? "#" : "";
638 s = s_append(s, sharp);
639 for(w=page; w; w=w->next){
646 s_endline(s, dosharp);
649 s = s_appendlist(s, "\n", sharp, nil);
651 s = s_appendlist(s, w->text, "\n", sharp, "\n", sharp, nil);
655 s_endline(s, dosharp);
662 s = s_appendlist(s, "\n", sharp, nil);
667 s_endline(s, dosharp);
672 s = s_append(s, " *\t");
679 t = s_append(s_copy("["), w->text);
681 t = s_append(t, "]");
683 t = s_append(t, " | ");
684 t = s_append(t, w->url);
685 t = s_append(t, "]");
687 s = s_appendbrk(s, s_to_c(t), prefix, dosharp);
694 s = s_appendbrk(s, w->text, prefix, dosharp);
695 sprint(tmp, "(%d)", w->section);
696 s = s_appendbrk(s, tmp, prefix, dosharp);
706 s_endline(s, dosharp);
707 s = s_appendlist(s, "! ", w->text, "\n", sharp, nil);
710 s_endline(s, dosharp);
711 s = s_appendlist(s, "------------------------------------------------------ \n", sharp, nil);
717 s = s_appendbrk(s, w->text, prefix, dosharp);
721 s_endline(s, dosharp);
728 historytext(String *s, Whist *h)
734 for(i=h->ndoc-1; i>=0; i--){
736 sprint(tmp, "[current]");
738 sprint(tmp, "[%lud/]", h->doc[i].time);
739 atime = ctime(h->doc[i].time);
740 atime[strlen(atime)-1] = '\0';
741 s = s_appendlist(s, " * ", tmp, " ", atime, nil);
743 s = s_appendlist(s, ", ", h->doc[i].author, nil);
744 if(h->doc[i].conflict)
745 s = s_append(s, ", conflicting write");
746 s = s_append(s, "\n");
747 if(h->doc[i].comment)
748 s = s_appendlist(s, "<i>", h->doc[i].comment, "</i>\n", nil);
754 totext(Whist *h, Wdoc *d, int ty)
757 char *p, *q, ver[40];
762 t = gettemplate(Ntemplate+ty);
763 if(p = strstr(s_to_c(t), "PAGE"))
766 p = s_to_c(t)+s_len(t);
772 sub[nsub] = (Sub){ "TITLE", h->title };
776 sprint(ver, "%lud", d->time);
777 sub[nsub] = (Sub){ "VERSION", ver };
779 atime = ctime(d->time);
780 atime[strlen(atime)-1] = '\0';
781 sub[nsub] = (Sub){ "DATE", atime };
786 s = s_appendsub(s, s_to_c(t), p-s_to_c(t), sub, nsub);
790 s = pagetext(s, d->wtxt, 0);
793 s = historytext(s, h);
800 s = s_appendsub(s, q, strlen(q), sub, nsub);
806 doctext(String *s, Wdoc *d)
810 sprint(tmp, "D%lud", d->time);
811 s = s_append(s, tmp);
813 s = s_append(s, "\nC");
814 s = s_append(s, d->comment);
817 s = s_append(s, "\nA");
818 s = s_append(s, d->author);
821 s = s_append(s, "\nX");
822 s = s_append(s, "\n");
823 s = pagetext(s, d->wtxt, 1);