19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <bio.h>
49a747e4fSDavid du Colombier #include <String.h>
59a747e4fSDavid du Colombier #include <ctype.h>
69a747e4fSDavid du Colombier #include <thread.h>
79a747e4fSDavid du Colombier #include "wiki.h"
89a747e4fSDavid du Colombier
99a747e4fSDavid du Colombier static Wpage*
mkwtxt(int type,char * text)109a747e4fSDavid du Colombier mkwtxt(int type, char *text)
119a747e4fSDavid du Colombier {
129a747e4fSDavid du Colombier Wpage *w;
139a747e4fSDavid du Colombier
149a747e4fSDavid du Colombier w = emalloc(sizeof(*w));
159a747e4fSDavid du Colombier w->type = type;
169a747e4fSDavid du Colombier w->text = text;
17af2e6ba6SDavid du Colombier setmalloctag(w, getcallerpc(&type));
189a747e4fSDavid du Colombier return w;
199a747e4fSDavid du Colombier }
209a747e4fSDavid du Colombier
219a747e4fSDavid du Colombier /*
229a747e4fSDavid du Colombier * turn runs of whitespace into single spaces,
239a747e4fSDavid du Colombier * eliminate whitespace at beginning and end.
249a747e4fSDavid du Colombier */
259a747e4fSDavid du Colombier char*
strcondense(char * s,int cutbegin)269a747e4fSDavid du Colombier strcondense(char *s, int cutbegin)
279a747e4fSDavid du Colombier {
289a747e4fSDavid du Colombier char *r, *w, *es;
299a747e4fSDavid du Colombier int inspace;
309a747e4fSDavid du Colombier
319a747e4fSDavid du Colombier es = s+strlen(s);
329a747e4fSDavid du Colombier inspace = cutbegin;
339a747e4fSDavid du Colombier for(r=w=s; *r; r++){
349a747e4fSDavid du Colombier if(isspace(*r)){
359a747e4fSDavid du Colombier if(!inspace){
369a747e4fSDavid du Colombier inspace=1;
379a747e4fSDavid du Colombier *w++ = ' ';
389a747e4fSDavid du Colombier }
399a747e4fSDavid du Colombier }else{
409a747e4fSDavid du Colombier inspace=0;
419a747e4fSDavid du Colombier *w++ = *r;
429a747e4fSDavid du Colombier }
439a747e4fSDavid du Colombier }
449a747e4fSDavid du Colombier assert(w <= es);
459a747e4fSDavid du Colombier if(inspace && w>s){
469a747e4fSDavid du Colombier --w;
479a747e4fSDavid du Colombier *w = '\0';
489a747e4fSDavid du Colombier }
499a747e4fSDavid du Colombier else
509a747e4fSDavid du Colombier *w = '\0';
519a747e4fSDavid du Colombier return s;
529a747e4fSDavid du Colombier }
539a747e4fSDavid du Colombier
549a747e4fSDavid du Colombier /*
559a747e4fSDavid du Colombier * turn runs of Wplain into single Wplain.
569a747e4fSDavid du Colombier */
579a747e4fSDavid du Colombier static Wpage*
wcondense(Wpage * wtxt)589a747e4fSDavid du Colombier wcondense(Wpage *wtxt)
599a747e4fSDavid du Colombier {
609a747e4fSDavid du Colombier Wpage *ow, *w;
619a747e4fSDavid du Colombier
629a747e4fSDavid du Colombier for(w=wtxt; w; ){
639a747e4fSDavid du Colombier if(w->type == Wplain)
649a747e4fSDavid du Colombier strcondense(w->text, 1);
659a747e4fSDavid du Colombier
669a747e4fSDavid du Colombier if(w->type != Wplain || w->next==nil
679a747e4fSDavid du Colombier || w->next->type != Wplain){
689a747e4fSDavid du Colombier w=w->next;
699a747e4fSDavid du Colombier continue;
709a747e4fSDavid du Colombier }
719a747e4fSDavid du Colombier
729a747e4fSDavid du Colombier w->text = erealloc(w->text, strlen(w->text)+1+strlen(w->next->text)+1);
739a747e4fSDavid du Colombier strcat(w->text, " ");
749a747e4fSDavid du Colombier strcat(w->text, w->next->text);
759a747e4fSDavid du Colombier
769a747e4fSDavid du Colombier ow = w->next;
77*1052a86aSDavid du Colombier w->next = ow->next;
78*1052a86aSDavid du Colombier ow->next = nil;
79*1052a86aSDavid du Colombier freepage(ow);
809a747e4fSDavid du Colombier }
819a747e4fSDavid du Colombier return wtxt;
829a747e4fSDavid du Colombier }
839a747e4fSDavid du Colombier
849a747e4fSDavid du Colombier /*
859a747e4fSDavid du Colombier * Parse a link, without the brackets.
869a747e4fSDavid du Colombier */
879a747e4fSDavid du Colombier static Wpage*
mklink(char * s)889a747e4fSDavid du Colombier mklink(char *s)
899a747e4fSDavid du Colombier {
909a747e4fSDavid du Colombier char *q;
919a747e4fSDavid du Colombier Wpage *w;
929a747e4fSDavid du Colombier
939a747e4fSDavid du Colombier for(q=s; *q && *q != '|'; q++)
949a747e4fSDavid du Colombier ;
959a747e4fSDavid du Colombier
969a747e4fSDavid du Colombier if(*q == '\0'){
979a747e4fSDavid du Colombier w = mkwtxt(Wlink, estrdup(strcondense(s, 1)));
989a747e4fSDavid du Colombier w->url = nil;
999a747e4fSDavid du Colombier }else{
1009a747e4fSDavid du Colombier *q = '\0';
1019a747e4fSDavid du Colombier w = mkwtxt(Wlink, estrdup(strcondense(s, 1)));
1029a747e4fSDavid du Colombier w->url = estrdup(strcondense(q+1, 1));
1039a747e4fSDavid du Colombier }
104af2e6ba6SDavid du Colombier setmalloctag(w, getcallerpc(&s));
1059a747e4fSDavid du Colombier return w;
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier
1089a747e4fSDavid du Colombier /*
1099a747e4fSDavid du Colombier * Parse Wplains, inserting Wlink nodes where appropriate.
1109a747e4fSDavid du Colombier */
1119a747e4fSDavid du Colombier static Wpage*
wlink(Wpage * wtxt)1129a747e4fSDavid du Colombier wlink(Wpage *wtxt)
1139a747e4fSDavid du Colombier {
1149a747e4fSDavid du Colombier char *p, *q, *r, *s;
1159a747e4fSDavid du Colombier Wpage *w, *nw;
1169a747e4fSDavid du Colombier
1179a747e4fSDavid du Colombier for(w=wtxt; w; w=nw){
1189a747e4fSDavid du Colombier nw = w->next;
1199a747e4fSDavid du Colombier if(w->type != Wplain)
1209a747e4fSDavid du Colombier continue;
1219a747e4fSDavid du Colombier while(w->text[0]){
1229a747e4fSDavid du Colombier p = w->text;
1239a747e4fSDavid du Colombier for(q=p; *q && *q != '['; q++)
1249a747e4fSDavid du Colombier ;
1259a747e4fSDavid du Colombier if(*q == '\0')
1269a747e4fSDavid du Colombier break;
1279a747e4fSDavid du Colombier for(r=q; *r && *r != ']'; r++)
1289a747e4fSDavid du Colombier ;
1299a747e4fSDavid du Colombier if(*r == '\0')
1309a747e4fSDavid du Colombier break;
1319a747e4fSDavid du Colombier *q = '\0';
1329a747e4fSDavid du Colombier *r = '\0';
1339a747e4fSDavid du Colombier s = w->text;
1349a747e4fSDavid du Colombier w->text = estrdup(w->text);
1359a747e4fSDavid du Colombier w->next = mklink(q+1);
1369a747e4fSDavid du Colombier w = w->next;
1379a747e4fSDavid du Colombier w->next = mkwtxt(Wplain, estrdup(r+1));
1389a747e4fSDavid du Colombier free(s);
1399a747e4fSDavid du Colombier w = w->next;
1409a747e4fSDavid du Colombier w->next = nw;
1419a747e4fSDavid du Colombier }
1429a747e4fSDavid du Colombier assert(w->next == nw);
1439a747e4fSDavid du Colombier }
1449a747e4fSDavid du Colombier return wtxt;
1459a747e4fSDavid du Colombier }
1469a747e4fSDavid du Colombier
1479a747e4fSDavid du Colombier static int
ismanchar(int c)1489a747e4fSDavid du Colombier ismanchar(int c)
1499a747e4fSDavid du Colombier {
1509a747e4fSDavid du Colombier return ('a' <= c && c <= 'z')
1519a747e4fSDavid du Colombier || ('A' <= c && c <= 'Z')
1529a747e4fSDavid du Colombier || ('0' <= c && c <= '9')
1539a747e4fSDavid du Colombier || c=='_' || c=='-' || c=='.' || c=='/'
1549a747e4fSDavid du Colombier || (c < 0); /* UTF */
1559a747e4fSDavid du Colombier }
1569a747e4fSDavid du Colombier
1579a747e4fSDavid du Colombier static Wpage*
findmanref(char * p,char ** beginp,char ** endp)1589a747e4fSDavid du Colombier findmanref(char *p, char **beginp, char **endp)
1599a747e4fSDavid du Colombier {
1609a747e4fSDavid du Colombier char *q, *r;
1619a747e4fSDavid du Colombier Wpage *w;
1629a747e4fSDavid du Colombier
1639a747e4fSDavid du Colombier q=p;
1649a747e4fSDavid du Colombier for(;;){
1659a747e4fSDavid du Colombier for(; q[0] && (q[0] != '(' || !isdigit(q[1]) || q[2] != ')'); q++)
1669a747e4fSDavid du Colombier ;
1679a747e4fSDavid du Colombier if(*q == '\0')
1689a747e4fSDavid du Colombier break;
1699a747e4fSDavid du Colombier for(r=q; r>p && ismanchar(r[-1]); r--)
1709a747e4fSDavid du Colombier ;
1719a747e4fSDavid du Colombier if(r==q){
1729a747e4fSDavid du Colombier q += 3;
1739a747e4fSDavid du Colombier continue;
1749a747e4fSDavid du Colombier }
1759a747e4fSDavid du Colombier *q = '\0';
1769a747e4fSDavid du Colombier w = mkwtxt(Wman, estrdup(r));
1779a747e4fSDavid du Colombier *beginp = r;
1789a747e4fSDavid du Colombier *q = '(';
1799a747e4fSDavid du Colombier w->section = q[1]-'0';
1809a747e4fSDavid du Colombier *endp = q+3;
181af2e6ba6SDavid du Colombier setmalloctag(w, getcallerpc(&p));
1829a747e4fSDavid du Colombier return w;
1839a747e4fSDavid du Colombier }
1849a747e4fSDavid du Colombier return nil;
1859a747e4fSDavid du Colombier }
1869a747e4fSDavid du Colombier
1879a747e4fSDavid du Colombier /*
1889a747e4fSDavid du Colombier * Parse Wplains, looking for man page references.
1899a747e4fSDavid du Colombier * This should be done by using a plumb(6)-style
1909a747e4fSDavid du Colombier * control file rather than hard-coding things here.
1919a747e4fSDavid du Colombier */
1929a747e4fSDavid du Colombier static Wpage*
wman(Wpage * wtxt)1939a747e4fSDavid du Colombier wman(Wpage *wtxt)
1949a747e4fSDavid du Colombier {
1959a747e4fSDavid du Colombier char *q, *r;
1969a747e4fSDavid du Colombier Wpage *w, *mw, *nw;
1979a747e4fSDavid du Colombier
1989a747e4fSDavid du Colombier for(w=wtxt; w; w=nw){
1999a747e4fSDavid du Colombier nw = w->next;
2009a747e4fSDavid du Colombier if(w->type != Wplain)
2019a747e4fSDavid du Colombier continue;
2029a747e4fSDavid du Colombier while(w->text[0]){
2039a747e4fSDavid du Colombier if((mw = findmanref(w->text, &q, &r)) == nil)
2049a747e4fSDavid du Colombier break;
2059a747e4fSDavid du Colombier *q = '\0';
2069a747e4fSDavid du Colombier w->next = mw;
2079a747e4fSDavid du Colombier w = w->next;
2089a747e4fSDavid du Colombier w->next = mkwtxt(Wplain, estrdup(r));
2099a747e4fSDavid du Colombier w = w->next;
2109a747e4fSDavid du Colombier w->next = nw;
2119a747e4fSDavid du Colombier }
2129a747e4fSDavid du Colombier assert(w->next == nw);
2139a747e4fSDavid du Colombier }
2149a747e4fSDavid du Colombier return wtxt;
2159a747e4fSDavid du Colombier }
2169a747e4fSDavid du Colombier
isheading(char * p)217fcdc259eSDavid du Colombier static int isheading(char *p) {
218fcdc259eSDavid du Colombier Rune r;
219fcdc259eSDavid du Colombier int hasupper=0;
220fcdc259eSDavid du Colombier while(*p) {
221fcdc259eSDavid du Colombier p+=chartorune(&r,p);
222fcdc259eSDavid du Colombier if(isupperrune(r))
223fcdc259eSDavid du Colombier hasupper=1;
224fcdc259eSDavid du Colombier else if(islowerrune(r))
225fcdc259eSDavid du Colombier return 0;
226fcdc259eSDavid du Colombier }
227fcdc259eSDavid du Colombier return hasupper;
228fcdc259eSDavid du Colombier }
229fcdc259eSDavid du Colombier
2309a747e4fSDavid du Colombier Wpage*
Brdpage(char * (* rdline)(void *,int),void * b)2319a747e4fSDavid du Colombier Brdpage(char *(*rdline)(void*,int), void *b)
2329a747e4fSDavid du Colombier {
23313ec2712SDavid du Colombier char *p, *c;
2349a747e4fSDavid du Colombier int waspara;
2359a747e4fSDavid du Colombier Wpage *w, **pw;
2369a747e4fSDavid du Colombier
2379a747e4fSDavid du Colombier w = nil;
2389a747e4fSDavid du Colombier pw = &w;
2399a747e4fSDavid du Colombier waspara = 1;
2409a747e4fSDavid du Colombier while((p = rdline(b, '\n')) != nil){
2419a747e4fSDavid du Colombier if(p[0] != '!')
2429a747e4fSDavid du Colombier p = strcondense(p, 1);
2439a747e4fSDavid du Colombier if(p[0] == '\0'){
2449a747e4fSDavid du Colombier if(waspara==0){
2459a747e4fSDavid du Colombier waspara=1;
2469a747e4fSDavid du Colombier *pw = mkwtxt(Wpara, nil);
2479a747e4fSDavid du Colombier pw = &(*pw)->next;
2489a747e4fSDavid du Colombier }
2499a747e4fSDavid du Colombier continue;
2509a747e4fSDavid du Colombier }
2519a747e4fSDavid du Colombier waspara = 0;
2529a747e4fSDavid du Colombier switch(p[0]){
2539a747e4fSDavid du Colombier case '*':
2549a747e4fSDavid du Colombier *pw = mkwtxt(Wbullet, nil);
2559a747e4fSDavid du Colombier pw = &(*pw)->next;
2569a747e4fSDavid du Colombier *pw = mkwtxt(Wplain, estrdup(p+1));
2579a747e4fSDavid du Colombier pw = &(*pw)->next;
2589a747e4fSDavid du Colombier break;
2599a747e4fSDavid du Colombier case '!':
2609a747e4fSDavid du Colombier *pw = mkwtxt(Wpre, estrdup(p[1]==' '?p+2:p+1));
2619a747e4fSDavid du Colombier pw = &(*pw)->next;
2629a747e4fSDavid du Colombier break;
26313ec2712SDavid du Colombier case '-':
26413ec2712SDavid du Colombier for(c = p; *c != '\0'; c++) {
26513ec2712SDavid du Colombier if(*c != '-') {
26613ec2712SDavid du Colombier c = p;
26713ec2712SDavid du Colombier break;
26813ec2712SDavid du Colombier }
26913ec2712SDavid du Colombier }
27013ec2712SDavid du Colombier
27113ec2712SDavid du Colombier if( (c-p) > 4) {
27213ec2712SDavid du Colombier *pw = mkwtxt(Whr, nil);
27313ec2712SDavid du Colombier pw = &(*pw)->next;
27413ec2712SDavid du Colombier break;
27513ec2712SDavid du Colombier }
27613ec2712SDavid du Colombier /* else fall thru */
2779a747e4fSDavid du Colombier default:
278fcdc259eSDavid du Colombier if(isheading(p)){
2799a747e4fSDavid du Colombier *pw = mkwtxt(Wheading, estrdup(p));
2809a747e4fSDavid du Colombier pw = &(*pw)->next;
2819a747e4fSDavid du Colombier continue;
2829a747e4fSDavid du Colombier }
2839a747e4fSDavid du Colombier *pw = mkwtxt(Wplain, estrdup(p));
2849a747e4fSDavid du Colombier pw = &(*pw)->next;
2859a747e4fSDavid du Colombier break;
2869a747e4fSDavid du Colombier }
2879a747e4fSDavid du Colombier }
2889a747e4fSDavid du Colombier if(w == nil)
2899a747e4fSDavid du Colombier werrstr("empty page");
2909a747e4fSDavid du Colombier
2919a747e4fSDavid du Colombier *pw = nil;
2929a747e4fSDavid du Colombier w = wcondense(w);
2939a747e4fSDavid du Colombier w = wlink(w);
2949a747e4fSDavid du Colombier w = wman(w);
295af2e6ba6SDavid du Colombier setmalloctag(w, getcallerpc(&rdline));
2969a747e4fSDavid du Colombier
2979a747e4fSDavid du Colombier return w;
2989a747e4fSDavid du Colombier }
2999a747e4fSDavid du Colombier
3009a747e4fSDavid du Colombier void
printpage(Wpage * w)3019a747e4fSDavid du Colombier printpage(Wpage *w)
3029a747e4fSDavid du Colombier {
3039a747e4fSDavid du Colombier for(; w; w=w->next){
3049a747e4fSDavid du Colombier switch(w->type){
3059a747e4fSDavid du Colombier case Wpara:
3069a747e4fSDavid du Colombier print("para\n");
3079a747e4fSDavid du Colombier break;
3089a747e4fSDavid du Colombier case Wheading:
3099a747e4fSDavid du Colombier print("heading '%s'\n", w->text);
3109a747e4fSDavid du Colombier break;
3119a747e4fSDavid du Colombier case Wbullet:
3129a747e4fSDavid du Colombier print("bullet\n");
3139a747e4fSDavid du Colombier break;
3149a747e4fSDavid du Colombier case Wlink:
3159a747e4fSDavid du Colombier print("link '%s' '%s'\n", w->text, w->url);
3169a747e4fSDavid du Colombier break;
3179a747e4fSDavid du Colombier case Wman:
3189a747e4fSDavid du Colombier print("man %d %s\n", w->section, w->text);
3199a747e4fSDavid du Colombier break;
3209a747e4fSDavid du Colombier case Wplain:
3219a747e4fSDavid du Colombier print("plain '%s'\n", w->text);
3229a747e4fSDavid du Colombier break;
32313ec2712SDavid du Colombier case Whr:
32413ec2712SDavid du Colombier print("hr\n");
32513ec2712SDavid du Colombier break;
3269a747e4fSDavid du Colombier case Wpre:
3279a747e4fSDavid du Colombier print("pre '%s'\n", w->text);
3289a747e4fSDavid du Colombier break;
3299a747e4fSDavid du Colombier }
3309a747e4fSDavid du Colombier }
3319a747e4fSDavid du Colombier }
332