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,"/","_");
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  if(path[strlen(path)-5..]==".bmml") path=path[..strlen(path)-6];
99b6701996-03-24Fredrik Hübinette (Hubbe)  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) {
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  return replace(s,({"uLPC","&","<",">"}),({"µLPC","&amp;","&lt;","&gt;"}));
92a42c1996-02-26Fredrik Hübinette (Hubbe) } 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;
f5c90a1996-03-24Fredrik Hübinette (Hubbe) list(string) indexes_done=(<>); string mkindex(string topic, int head) { string head; string a,ret; ret=""; indexes_done[topic]=1; switch(topic) { case "programs": head="<b>Builtin programs:</b>\n"; ret="<ul>\n"; foreach(sort_array(m_indices(pages)),a) { if(-1 == search(a,"/")) continue; ret+="<li><a href="+pages[a]+">"+a+"</a>"+short(a)+"\n"; } ret+="</ul>\n"; break; case "other": head="<b>Other pages</b>\n"; ret="<ul>\n"; foreach(sort_array(m_indices(pages) - `+(@m_values(keywords))),a) { if(-1 != search(a,"/")) continue; ret+="<li><a href="+pages[a]+">"+a+"</a>"+short(a)+"\n"; } ret+="</ul>\n"; break; case "efuns": head="<b>All builtin functions:</b>\n"; ret="<ul>\n"; foreach(sort_array(m_indices(all_efuns())),a) { a=html_quote(a); if(pages[a]) { ret+="<li><a href="+pages[a]+">"+a+"</a>"+short(a)+"\n"; }else{ perror("Warning: no page for function: "+a+".\n"); } } ret+="</ul>\n"; break; default: if(!keywords[topic]) { perror("Unknown keyword "+topic+".\n"); return ""; } head="<a name="+topic+">"; head+="<b>"+capitalize(b)+"</a>"; head+=short(b); head+="</b>\n"; ret="<ul>\n"; foreach(keywords[b],a) { a=html_quote(a); ret+="<li><a href="+pages[a]+">"+a+"</a>"+ short(a) +"\n"; } ret+="</ul></a>\n"; break; } if(head) ret=head+ret; return ret; }
99b6701996-03-24Fredrik Hübinette (Hubbe) /* 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");
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  /* Merge sections that does not have a header together */
92a42c1996-02-26Fredrik Hübinette (Hubbe)  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>";
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  case "RELATED FUNCTIONS": a=name; sscanf(rest,"%*skeyword %[a-z/A-Z0-9]",a); rest=mkindex(a, 0);
92a42c1996-02-26Fredrik Hübinette (Hubbe)  } 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)  }
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  else if(path[strlen(path)-5..]==".bmml") { string *sections; string title; int section; cont=replace(cont,"$version",version()); cont=html_quote(cont); sections=explode(cont,"\n\n"); for(section=0;section<sizeof(sections);section++) { string tmp,pre,a; tmp=sections[section]; sscanf(tmp,"%[\t ]",per); switch(space) { case "": tmp="<h1><center>"+tmp+"</center></h1>"; title=tmp; break; case " ": sscanf(tmp," %s",tmp); tmp="<h2>"+tmp+"</h2>"; break; case " ": sscanf(tmp," %s",tmp); tmp=replace(tmp,"\n ","\n"); tmp=more_magic(tmp); break; case "\t": sscanf(tmp,"\t%s %s",pre, a); switch(pre) { case "KEYWORD_INDEX": tmp=mkindex(a, 1); default: perror("Unknown directive: "+pre+".\n"); } } } cont=implode(sections,"\n<p>\n"); return mkdocument(cont, title || "uLPC manual"); }
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) 
f5c90a1996-03-24Fredrik Hübinette (Hubbe) string short(string s) { return short_descs[s] ? " - "+short_descs[s] : ""; } string convert_dot_bmml(string path, string fname) { string output; output=""; if(path[strlen(path)-5..]==".bmml") { } return 0; } int writepages;
92a42c1996-02-26Fredrik Hübinette (Hubbe) void scanfiles(string path, string fname) { string nf,np;
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  nf=convert(path, fname);
92a42c1996-02-26Fredrik Hübinette (Hubbe) 
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  if(nf && strlen(nf) && writepages)
92a42c1996-02-26Fredrik Hübinette (Hubbe)  { 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;
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  foreach(get_dir(path) - ({"CVS","RCS",".cvsignore"}),file)
92a42c1996-02-26Fredrik Hübinette (Hubbe)  { 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); } } } 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);
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  write("Scanning pages.\n"); writepages=0; traversedir(".",scanfiles); write("Writing html.\n"); writepages=0;
92a42c1996-02-26Fredrik Hübinette (Hubbe)  traversedir(".",scanfiles);
f5c90a1996-03-24Fredrik Hübinette (Hubbe)  foreach(indices(keywords) - indices(indexes_done),np) { perror("Keywords never indexed: "+np+"\n"); }
92a42c1996-02-26Fredrik Hübinette (Hubbe) }