2974bc | 1997-11-10 | Mirar (Pontus Hagland) | |
import Stdio;
import Array;
mapping parse=([]);
int illustration_counter;
#define error(X) throw( ({ (X), backtrace()[0..sizeof(backtrace())-2] }) )
mapping moduleM, classM, methodM, argM, nowM, descM;
mapping focM(mapping dest,string name,int line)
{
return dest[name] || (dest[name]=(["_line":line]));
}
string stripws(string s)
{
sscanf(s,"%*[ \t\n\r]%s",s);
s=reverse(s);
sscanf(s,"%*[ \t\n\r]%s",s);
return reverse(s);
}
mapping lower_nowM()
{
if (nowM &&
(nowM==parse
|| nowM==classM
|| nowM==methodM
|| nowM==moduleM)) return nowM;
else return nowM=methodM;
}
void report(string s)
{
stderr->write(s+"\n");
}
#define complain(X) (X)
mapping keywords=
(["module":lambda(string arg,int line)
{ classM=descM=nowM=moduleM=focM(parse,stripws(arg),line);
methodM=0;
if (!nowM->classes) nowM->classes=([]);
if (!nowM->modules) nowM->modules=([]);
report("module "+arg); },
"class":lambda(string arg,int line)
{ if (!moduleM) return complain("class w/o module");
descM=nowM=classM=focM(moduleM->classes,stripws(arg),line);
methodM=0; report("class "+arg); },
"submodule":lambda(string arg,int line)
{ if (!moduleM) return complain("submodule w/o module");
classM=descM=nowM=moduleM=focM(moduleM->modules,stripws(arg),line);
methodM=0;
if (!nowM->classes) nowM->classes=([]);
if (!nowM->modules) nowM->modules=([]);
report("submodule "+arg); },
"method":lambda(string arg,int line)
{ if (!classM) return complain("method w/o class");
if (!nowM || methodM!=nowM || methodM->desc || methodM->args || descM==methodM)
{ if (!classM->methods) classM->methods=({});
classM->methods+=({methodM=nowM=(["decl":({}),"_line":line])}); }
methodM->decl+=({stripws(arg)}); descM=0; },
"arg":lambda(string arg,int line)
{
if (!methodM) return complain("arg w/o method");
if (!methodM->args) methodM->args=({});
methodM->args+=({argM=nowM=(["args":({}),"_line":line])});
argM->args+=({arg}); descM=argM;
},
"note":lambda(string arg,int line)
{
if (!lower_nowM())
return complain("note w/o method, class or module");
descM=nowM->note||(nowM->note=(["_line":line]));
},
"bugs":lambda(string arg,int line)
{
if (!lower_nowM())
return complain("bugs w/o method, class or module");
descM=nowM->bugs||(nowM->bugs=(["_line":line]));
},
"see":lambda(string arg,int line)
{
if (arg[0..4]!="also:")
return complain("see w/o 'also:'\n");
if (!lower_nowM())
return complain("see also w/o method, class or module");
nowM["see also"]=map(arg[5..]/",",stripws);
},
"returns":lambda(string arg)
{
if (!methodM)
return complain("returns w/o method");
methodM->returns=stripws(arg);
descM=0; nowM=0;
}
]);
string getridoftabs(string s)
{
string res="";
for (;;)
{
int i;
if ((i=search(s,"\t"))==-1) return res+s;
res+=s[0..i-1];
s=s[i+1..];
res+=" "[(strlen(res)%8)..7];
}
}
object(File) make_file(string filename)
{
stderr->write("creating "+filename+"...\n");
if (file_size(filename)>0)
{
rm(filename+"~");
mv(filename,filename+"~");
}
object f=File();
if (!f->open(filename,"wtc"))
{
stderr->write("failed.");
exit(1);
}
return f;
}
string synopsis_to_html(string s)
{
string type,name,arg;
if (sscanf(s,"%s%*[ \t]%s(%s",type,name,arg)!=4)
sscanf(s,"%s(%s",name,arg),type="";
return
type+" <b>"+name+"</b>("+
replace(arg,({","," "}),({", ","\240"}));
}
string htmlify(string s)
{
#define HTMLIFY(S) \
(replace((S),({"->","&","\240"}),({"->","&"," "})))
string t="",u,v;
while (sscanf(s,"%s<%s>%s",u,v,s)==3)
t+=HTMLIFY(u)+"<"+v+">";
return t+HTMLIFY(s);
}
#define linkify(S) (replace((S),({"->","()"}),({".",""})))
string make_nice_reference(string what,string prefix)
{
string q;
if (search(what,".")==-1 &&
search(what,"->")==-1 &&
!parse[what])
q=prefix+what;
else
q=what;
return "<link to="+linkify(q)+">"+what+"</link>";
}
string fixdesc(string s,string prefix,string where)
{
s=stripws(s);
string t,u,v;
t=s; s="";
while (sscanf(t,"%s<ref>%s</ref>%s",t,u,v)==3)
{
s+=t+make_nice_reference(u,prefix);
t=v;
}
s+=t;
t=s; s="";
while (sscanf(t,"%s<illustration>%s</illustration>%s",t,u,v)==3)
{
s+=htmlify(replace(t,"\n\n","\n\n<p>"));
s+="<illustration __from__='"+where+"' src=lena.gif>\n"
+replace(u,"lena()","src")+"</illustration>";
t=v;
}
s+=htmlify(replace(t,"\n\n","\n\n<p>"));
return s;
}
multiset(string) get_method_names(string *decls)
{
string decl,name;
multiset(string) names=(<>);
foreach (decls,decl)
{
sscanf(decl,"%*s%*[\t ]%s%*[\t (]%*s",name);
names[name]=1;
}
return names;
}
string addprefix(string suffix,string prefix)
{
return prefix+suffix;
}
void document(mapping huh,string name,string prefix,object f)
{
string *names;
if (huh->names)
names=map(indices(huh->names),addprefix,name);
else
names=({name});
werror(name+" : "+names*","+"\n");
f->write("<hr newpage>\n");
foreach (names,string n)
f->write("<anchor name="+linkify(n)+">\n");
f->write("<dl>\n");
f->write("<dt><encaps>NAME</encaps><dd>\n");
foreach (names,n)
f->write("\t<tt>"+n+"</tt><br>\n");
f->write("<p>\n");
if (huh->decl)
{
f->write("<dt><encaps>SYNTAX</encaps><dd>\n");
f->write(replace(htmlify(map(huh->decl,synopsis_to_html)*
"<br>\n"),"\n","\n\t")+"\n");
f->write("<p>\n\n");
}
if (huh->desc)
{
f->write("<dt><encaps>DESCRIPTION</encaps><dd>\n");
f->write(fixdesc(huh->desc,prefix,huh->_line)+"\n");
f->write("<p>\n\n");
}
if (huh->args)
{
string rarg="";
f->write("<dt><encaps>ARGUMENTS</encaps><dd>\n");
f->write("\t<table border=1 cellspacing=0><tr>\n"
"\t<td align=left><font size=-2>argument(s)</font></td>"
"\t<td align=left><font size=-2>description</font></td>"
"</tr>\n\n");
foreach (huh->args,mapping arg)
{
if (arg->desc)
{
f->write("\t<tr align=left><td valign=top>\n"
+rarg+"\t\t<tt>"
+arg->args*"</tt><br>\n\t\t<tt>"
+"</tt></td>\n"
+"\t<td valign=bottom>"
+fixdesc(arg->desc,prefix,arg->_line)
+"</td></tr>\n\n");
rarg="";
}
else
{
rarg+="\t\t<tt>"
+arg->args*"</tt><br>\n\t\t<tt>"+
"</tt><br>\n";
}
}
if (rarg!="") error("trailing args w/o desc on "+arg->_line+"\n");
f->write("</table><p>\n\n");
}
if (huh->returns)
{
f->write("<dt><encaps>RETURN VALUE</encaps><dd>\n");
f->write(fixdesc(huh->returns,prefix,huh->_line)+"\n");
f->write("<p>\n\n");
}
if (huh->note && huh->note->desc)
{
f->write("<dt><encaps>NOTA BENE</encaps><dd>\n");
f->write(fixdesc(huh->note->desc,prefix,huh->_line)+"\n");
f->write("<p>\n\n");
}
if (huh["see also"])
{
f->write("<dt><encaps>SEE ALSO</encaps><dd>\n");
f->write(map(huh["see also"],
make_nice_reference,prefix)*",\n "+"\n");
f->write("<p>\n\n");
}
f->write("</dl>\n\n");
if (huh->methods)
{
multiset(string) method_names=(<>);
string *method_names_arr,method_name;
mapping method;
if (huh->methods)
foreach (huh->methods,method)
method_names|=(method->names=get_method_names(method->decl));
method_names_arr=sort(indices(method_names));
foreach (method_names_arr,method_name)
if (method_names[method_name])
{
foreach (huh->methods,method)
if ( method->names[method_name] )
{
document(method,prefix,prefix,f);
method_names-=method->names;
}
if (method_names[method_name])
stderr->write("failed to find "+method_name+" again, wierd...\n");
}
foreach(huh->methods,mapping child)
{
document(child,prefix,prefix,f);
}
}
if (huh->classes)
{
foreach(indices(huh->classes),string n)
{
f->write("\n\n\n<section title=\""+prefix+n+"\">\n");
document(huh->classes[n],
prefix+n,prefix+n+"->",f);
f->write("</section title=\""+prefix+n+"\">\n");
}
}
if (huh->modules)
{
foreach(indices(huh->modules),string n)
{
f->write("\n\n\n<section title=\""+prefix+n+"\">\n");
document(huh->modules[n],
prefix+n,prefix+n+".",f);
f->write("</section title=\""+prefix+n+"\">\n");
}
}
foreach (names,string n)
f->write("</anchor name="+linkify(n)+">\n");
f->write("\n\n\n");
}
void make_doc_files()
{
stderr->write("modules: "+sort(indices(parse))*", "+"\n");
foreach (sort(indices(parse)),string module)
document(parse[module],module,module+".",stdout);
}
int main(int ac,string *files)
{
string s,t;
int line;
string *ss=({""});
object f;
string currentfile;
nowM=parse;
stderr->write("reading and parsing data...\n");
files=files[1..];
for (;;)
{
int i;
if (!f)
{
if (!sizeof(files)) break;
stderr->write("reading "+files[0]+"...\n");
f=File();
currentfile=files[0];
files=files[1..];
if (!f->open(currentfile,"r")) { f=0; continue; }
t=0;
ss=({""});
line=0;
}
if (sizeof(ss)<2)
{
if (t=="") { f=0; continue; }
t=f->read(8192);
s=ss[0];
ss=t/"\n";
ss[0]=s+ss[0];
}
s=ss[0]; ss=ss[1..];
line++;
if ((i=search(s,"**!"))!=-1)
{
string kw,arg;
sscanf(s[i+3..],"%*[ \t]%s%*[ \t]%s",kw,arg);
if (keywords[kw])
{
string err;
if ( (err=keywords[kw](arg,currentfile+" line "+line)) )
{
stderr->write(currentfile+" line "+line+": "+err+"\n");
return 1;
}
}
else
{
if (!descM) descM=methodM;
if (!descM)
{
stderr->write("Error on line "+line+": illegal description position\n");
return 1;
}
if (!descM->desc) descM->desc="";
else descM->desc+="\n";
s=getridoftabs(s);
descM->desc+=s[search(s,"**!")+3..];
}
}
}
stderr->write("making docs...\n\n");
make_doc_files();
return 0;
}
|