92a42c1996-02-26Fredrik Hübinette (Hubbe) #!/usr/local/bin/ulpc // Parse BMML (Black Magic Markup Language) to HTML // Written by Fredrik Hubinette, dark sourceror and inventor of BMML mapping efuns = all_efuns(); mapping pages = ([]); mapping short_descs = ([]); mapping keywords = ([]); mapping subpages = ([]); string new_path; /* * Implode an array of strings to an english 'list' * ie. ({"foo","bar","gazonk"}) beomces "foo bar, gazonk" */ string implode_nicely(string *foo) { switch(sizeof(foo)) { case 0: return ""; case 1: return foo[0]; default: return foo[0..sizeof(foo)-2]*", "+" and "+foo[-1]; } } /* * Make a 'header' */ string smallcaps(string foo) { string *ret; ret=({"<b>"}); foreach(explode(foo," "),foo) { ret+=({"<font size=+1>"+foo[0..0]+"</font><font size=-1>"+foo[1..0x7fffffff]+"</font>"}); } return implode(ret," ")+"</b>"; } /* * convert original path to internal format */ string fippel_path(string path) { sscanf(path,"./%s",path);
99b6701996-03-24Fredrik Hübinette (Hubbe)  path=replace(path,"/","_"); if(path[strlen(path)-5..]!=".html") path+=".html"; return path;
92a42c1996-02-26Fredrik Hübinette (Hubbe) }
99b6701996-03-24Fredrik Hübinette (Hubbe) /* * Three step conversion process... */
92a42c1996-02-26Fredrik Hübinette (Hubbe) string even_more_magic(string block, int indent) { if(-1==search(block,"\t")) { return replace(block,"\n","<br>\n"); }else{ int e,d; mixed tmp,tmp2; tmp=explode(block,"\n")+({}); for(e=0;e<sizeof(tmp);e++) { tmp[e]=explode(tmp[e],"\t"); if(sscanf(tmp[e][0],"%*[ ]%s",tmp2) && tmp2=="") { int q; for(q=e-1;q>0;q--) { if(!tmp[q]) continue; if(sizeof(tmp[q])>=sizeof(tmp[e])) { for(d=1;d<sizeof(tmp[e]);d++) { tmp[q][d]+=" "+tmp[e][d]; } tmp[e]=0; } break; } } } tmp-=({0}); for(e=0;e<sizeof(tmp);e++) { tmp[e]=implode(tmp[e]," </td><td> "); } return "<table border=0 cellpadding=0 cellspacing=0>\n<tr valign=top><td>"+ implode(tmp,"<br></td></tr>\n<tr valign=top><td>")+ "<br></td></tr>\n</table>\n"; } } string more_magic(string s, int quote) { int e; string *tmp; int *ilevel=({0}); string output=""; string accumulator=""; if(!quote && -1==search("\n"+s,"\n ") && -1==search(s,"\t")) { return s; } #define FLUSH() output+=even_more_magic(accumulator,ilevel[-1]); accumulator="" #define POP() output+="</dl>"; ilevel=ilevel[0..sizeof(ilevel)-2] tmp=explode(s,"\n"); for(e=0;e<sizeof(tmp);e++) { string spaces, rest; sscanf(tmp[e],"%[ ]%s",spaces,rest); if(strlen(spaces) > ilevel[-1]) { FLUSH(); output+="<dl><dt><dd>"; ilevel+=({ strlen(spaces) }); } else if(strlen(spaces) < ilevel[-1]) { FLUSH(); while(strlen(spaces) < ilevel[-1] && strlen(spaces) <= ilevel[-2]) { POP(); } } accumulator+=rest+"\n"; } FLUSH(); while(sizeof(ilevel)>1) { POP(); } return output; } string magic(string s, int quote) { string *ret; ret=({}); foreach(explode(s,"\n\n"),s) { sscanf(s,"\t%s",s); s=replace(s,"\n\t","\n"); ret += ({ more_magic(s, quote) }); } return implode(ret,"\n<p>"); }
99b6701996-03-24Fredrik Hübinette (Hubbe)  /* * Magic to convert SYNTAX sections */
92a42c1996-02-26Fredrik Hübinette (Hubbe) inherit "/precompiled/regexp" : lastident; inherit "/precompiled/regexp" : megamagic; string syntax_magic(string s) { string *tmp; int e; while(tmp=megamagic::split(s)) { s=tmp[0]+"<I>"+tmp[1]+"</I>"+tmp[2]; } tmp=explode(s,"\n"); for(e=0;e<sizeof(tmp);e++) { string a,b; if(sscanf(tmp[e],"%s(%s",a,b) && strlen(b)>1 && b[-1]==';' && b[-2]==')') { string *tmp2; int d; tmp2=explode(b[0..strlen(b)-3],","); for(d=0;d<sizeof(tmp2);d++) { string *tmp3; // perror("<"+tmp2[d]+">"); if(tmp3=lastident::split(tmp2[d])) { tmp2[d]=tmp3[0]+"<I>"+tmp3[1]+"</I>"+tmp3[2]; } } tmp[e]=a+"("+implode(tmp2,",")+");"; } } s=implode(tmp,"\n"); return "<tt>"+magic(s,1)+"</tt>"; }
99b6701996-03-24Fredrik Hübinette (Hubbe)  /* HTML quoting / unquoting */
92a42c1996-02-26Fredrik Hübinette (Hubbe) string html_quote(string s) { return replace(s,({"&","<",">"}),({"&amp;","&lt;","&gt;"})); } string html_unquote(string s) { return replace(s,({"&amp;","&lt;","&gt;"}),({"&","<",">"})); }
57145a1996-03-22Fredrik Hübinette (Hubbe) string mkdocument(string s,string title) { return ("<html>"+ "<title>"+ html_quote(title)+ "</title>"+ "<body bgcolor=\"#A0E0C0\">"+ s+ "</body>"+ "</html>"); }
99b6701996-03-24Fredrik Hübinette (Hubbe) inherit "/precompiled/regexp":is_example; /* Convert a page */
92a42c1996-02-26Fredrik Hübinette (Hubbe) string convert_page(string path, string fname) { string output, short; int headno; string cont, section, name, part; output=""; cont=read_bytes(path); if(sscanf(cont,"NAME\n\t%s - %s\n",name,short)) { int partno;
99b6701996-03-24Fredrik Hübinette (Hubbe)  cont=html_quote(cont); short_descs[html_quote(name)]=short;
92a42c1996-02-26Fredrik Hübinette (Hubbe)  string *parts=explode(cont,"============================================================================\n"); for(partno=0;partno<sizeof(parts);partno++) { string part_name="error"; string *sections; string part; int section; part=parts[partno]; if(!strlen(part)) continue; sections=explode(part,"\n\n"); for(section=0;section<sizeof(sections);section++) { if(!strlen(sections[section]) || sections[section][0] < 'A' || sections[section][0] > 'Z') { sections[section-1]+="\n\n"+sections[section]; sections=sections[0..section-1]+sections[section+1..0x7fffffff]; section--; } } for(headno=0;headno<sizeof(sections);headno++) { string type, rest; mixed a, b; sscanf(sections[headno],"%s\n%s",type,rest); switch(type) { case "NAME": if(sscanf(rest,"\t%s - %s",part_name,b)!=2) perror("Warning NAME section broken!\n"); rest="\t<tt>"+part_name+"</tt> - "+b; case "DESCRIPTION": case "NOTA BENE": case "BUGS": rest=magic(rest,0); break; default: perror("Warning: Unknown header: "+type+".\n"); rest=magic(rest,0); break; case "KEYWORDS": a=replace(rest,({"\n"," ","\t"}),({"","",""}))/","; b=({}); foreach(a,a) { // fixme!! keywords[a] = ( keywords[a] || ({}) ) + ({ name }); b+=({ "<a href=index.html#"+a+">"+a+"</a>" }); } rest=implode_nicely(b); break; case "SEE ALSO": rest=replace(rest,({"\n"," ","\t"}),({"","",""})); a=rest/","; b=({}); foreach(a,a) { string tmp; tmp=a; a=explode(a,"/")[-1]; if(pages[a]) { b+=({ "<a href="+pages[a]+">" + a + "</a>" }); }else if(subpages[a]){ b+=({ "<a href="+subpages[a]+">" + a + "</a>" }); }else if(subpages[fname+"-&gt;"+a]){ b+=({ "<a href="+subpages[name+"-&gt;"+a]+">" + a + "</a>" }); }else{ perror("Warning, unlinked SEE ALSO: "+a+"\n"); b+=({ tmp }); } } rest=implode_nicely(b); break; case "SYNTAX": case "SYNTAX EXAMPLE": rest=syntax_magic(rest); break; case "EXAMPLES": case "EXAMPLE": case "DIRECTIVE": case "PREPROCESSOR DIRECTIVES": rest="<tt>"+magic(rest,1)+"</tt>"; } sections[headno]="<dt>"+ smallcaps(type)+ "<dd>\n"+rest+"\n<p>"; } parts[partno]="<dl>\n"+implode(sections,"\n")+"\n</dl>\n"; if(part_name) { parts[partno]="<a name="+part_name+">\n"+ parts[partno]+ "\n</a>\n"; } }
57145a1996-03-22Fredrik Hübinette (Hubbe)  output=mkdocument(implode(parts,"<hr noshade size=1>\n"),"uLPC: "+name);
92a42c1996-02-26Fredrik Hübinette (Hubbe)  }
99b6701996-03-24Fredrik Hübinette (Hubbe)  else if(path[strlen(path)-5..]==".html") { if(sscanf(cont,"<title>%s</title>",part)) short_descs[(path/"/")[-1]]=part; output=cont; } else if(is_example::match(cont)) { /** Hmm, this looks like an example file to me... */ string line,tmp; int pre,p; if(sscanf(cont,"%*[0-9.] %s\n",part)==2) short_descs[(path/"/")[-1]]=part; tmp=""; pre=2; cont=html_quote(cont); foreach(cont/"\n"+({"."}),line) { if(strlen(line)) { switch(line[0]) { case ' ': p=0; sscanf(line," %s",line); break; case '\t': p=1; sscanf(line,"\t",line); break; default: p=2; break; } if(p!=pre) { switch(pre) { case 2: output+="<h2>"+tmp+"</h2>"; break; case 1: if(tmp[-1]=='\n' && tmp[-2]=='\n') tmp=tmp[..strlen(tmp)-2]; output+="<pre>\n"+tmp+"</pre>\n"; break; case 0: output+=replace(tmp,"\n\n","\n<p>\n"); break; } pre=p; tmp=""; } } tmp+=line+"\n"; } output=mkdocument(output,"uLPC: "+ replace(explode(fname,"/")[-1],"_"," ")); }
92a42c1996-02-26Fredrik Hübinette (Hubbe)  return output; }
99b6701996-03-24Fredrik Hübinette (Hubbe) 
92a42c1996-02-26Fredrik Hübinette (Hubbe) void scanfiles(string path, string fname) { string nf,np; nf=convert_page(path, fname); if(nf && strlen(nf)) { np=combine_path(new_path,fippel_path(path));
99b6701996-03-24Fredrik Hübinette (Hubbe) // write("Writing "+np+".\n");
92a42c1996-02-26Fredrik Hübinette (Hubbe)  if(file_size(np)>=0) rm (np); write_file(np,nf); } }
99b6701996-03-24Fredrik Hübinette (Hubbe) /* * Pre-read all files and sort out where to link it to */
92a42c1996-02-26Fredrik Hübinette (Hubbe) void scanlinks(string path, string fname) { string cont,name; cont=read_bytes(path); cont=html_quote(cont); if(sscanf(cont,"NAME\n\t%s -",name)) { path=fippel_path(path); pages[name]=path; int e; string *parts=explode(cont,"============================================================================\n"); for(e=1;e<sizeof(parts);e++) { string part_name; if(sscanf(parts[e],"NAME\n\t%s -",part_name)) { subpages[fname+"-&gt;"+part_name]=path+"#"+part_name; } }
99b6701996-03-24Fredrik Hübinette (Hubbe)  } else if(path[strlen(path)-5..]==".html") { pages[(path[..strlen(path)-6]/"/")[-1]]=fippel_path(path); } else if(is_example::match(cont)) { pages[(path/"/")[-1]]=fippel_path(path); } else { string tmp; int l, i; foreach(cont/"\n", tmp) { if(is_example::match(tmp+"\n")) { l++; }else{ i++; } } if(l > i*2) { l=0; foreach(cont/"\n", tmp) { l++; if(!is_example::match(tmp+"\n")) { perror(path+":"+l+": not on example form.\n"); } } }
92a42c1996-02-26Fredrik Hübinette (Hubbe)  perror("Warning: not converting "+path+".\n"); } }
99b6701996-03-24Fredrik Hübinette (Hubbe)  /** Traverse directory **/
92a42c1996-02-26Fredrik Hübinette (Hubbe) void traversedir(string path,function fun) { string file; foreach(get_dir(path) - ({"CVS","RCS"}),file) { string tmp; if(file[-1]=='~') continue; if(file[0]=='#' && file[-1]=='#') continue; if(file[0]=='.' && file[1]=='#') continue; tmp=path+"/"+file; if(file_size(tmp)==-2) { traversedir(tmp,fun); }else{ fun(tmp,file); } } }
99b6701996-03-24Fredrik Hübinette (Hubbe) string short(string s) { return short_descs[s] ? " - "+short_descs[s] : ""; } /** Create an index for our newly created stuff **/
92a42c1996-02-26Fredrik Hübinette (Hubbe) string mkindex() { string ret; string a,b; mapping tmp=pages+([]); ret="";
57145a1996-03-22Fredrik Hübinette (Hubbe)  ret+="<H1>"+version()+" index</h1>\n";
92a42c1996-02-26Fredrik Hübinette (Hubbe) 
57145a1996-03-22Fredrik Hübinette (Hubbe)  ret+="<H2><b>Keyword lists</b></H2>\n<dl>\n";
92a42c1996-02-26Fredrik Hübinette (Hubbe)  foreach(sort_array(m_indices(keywords)),b) { ret+="<a name="+b+">"; ret+="<dt><h2>"+capitalize(b);
99b6701996-03-24Fredrik Hübinette (Hubbe)  ret+=short(b);
92a42c1996-02-26Fredrik Hübinette (Hubbe)  ret+="</h2><dd>\n"; ret+="<ul>\n"; foreach(keywords[b],a) {
99b6701996-03-24Fredrik Hübinette (Hubbe)  a=html_quote(a); ret+="<li><a href="+pages[a]+">"+a+"</a>"+ short(a) +"\n";
92a42c1996-02-26Fredrik Hübinette (Hubbe)  m_delete(tmp,a); } ret+="</ul></a>\n"; } ret+="</dl>\n"; ret+="<H1>All builtin functions:</H1>\n<ul>\n"; foreach(sort_array(m_indices(all_efuns())),a) { a=html_quote(a); if(pages[a]) {
99b6701996-03-24Fredrik Hübinette (Hubbe)  ret+="<li><a href="+pages[a]+">"+a+"</a>"+short(a)+"\n";
92a42c1996-02-26Fredrik Hübinette (Hubbe)  }else{ perror("Warning: no page for function: "+a+".\n"); } m_delete(tmp,a); } ret+="</ul>\n"; ret+="</dl><H1>Builtin programs:</H1>\n<ul>\n"; foreach(sort_array(m_indices(tmp)),a) { if(-1 == search(a,"/")) continue;
99b6701996-03-24Fredrik Hübinette (Hubbe)  ret+="<li><a href="+pages[a]+">"+a+"</a>"+short(a)+"\n";
92a42c1996-02-26Fredrik Hübinette (Hubbe)  m_delete(tmp,a); } ret+="</ul>\n"; ret+="<H1>Other pages</H1>\n<ul>\n"; foreach(sort_array(m_indices(tmp)),a) {
99b6701996-03-24Fredrik Hübinette (Hubbe)  ret+="<li><a href="+pages[a]+">"+a+"</a>"+short(a)+"\n";
92a42c1996-02-26Fredrik Hübinette (Hubbe)  } ret+="</ul>\n";
57145a1996-03-22Fredrik Hübinette (Hubbe)  return mkdocument(ret,"uLPC documentation index");
92a42c1996-02-26Fredrik Hübinette (Hubbe) } int main(int argc, string *argv) { string np;
99b6701996-03-24Fredrik Hübinette (Hubbe)  megamagic::create("^(.*)&lt;([a-z_0-9]+)&gt;(.*)$"); lastident::create("^(.*[^<>a-z_0-9])([a-z_0-9]+)([^<>a-z_0-9]*)$"); #define BEGIN1 "[0-9]+(\\.[0-9]+)*(\\.|) " #define BEGIN2 "\t" #define BEGIN3 " " #define LEND "[^\n]*" #define LINE "(" BEGIN1 LEND ")|(" BEGIN2 LEND ")|(" BEGIN3 LEND ")|()\n" is_example::create("^(" LINE ")+$");
92a42c1996-02-26Fredrik Hübinette (Hubbe)  write("Scanning links.\n"); new_path=combine_path(getcwd(),argv[2]); cd(argv[1]); traversedir(".",scanlinks); write("Processing pages.\n"); traversedir(".",scanfiles); write("Making index.\n"); np=combine_path(new_path,"index.html"); if(file_size(np)>=0) rm(np); write_file(np,mkindex()); }