|
|
import Stdio; |
import Array; |
|
mapping parse=([]); |
int illustration_counter; |
|
mapping manpage_suffix= |
([ |
"Image":"i", |
"Image.image":"i", |
]); |
|
|
function verbose=werror; |
|
#define error(X) throw( ({ (X), backtrace()[0..sizeof(backtrace())-2] }) ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping moduleM, classM, methodM, argM, nowM, descM; |
|
mapping focM(mapping dest,string name,string line) |
{ |
if (!dest->_order) dest->_order=({}); |
if (-1==search(dest->_order,name)) dest->_order+=({name}); |
return dest[name] || (dest[name]=(["_line":line])); |
} |
|
string stripws(string s) |
{ |
return desc_stripws(s); |
} |
|
string desc_stripws(string s) |
{ |
if (s=="") return s; |
array lines = s / "\n"; |
int m=10000; |
foreach (lines,string s) |
if (s!="") |
{ |
sscanf(s,"%[ ]%s",string a,string b); |
if (b!="") m=min(strlen(a),m); |
} |
return map(lines,lambda(string s) { return s[m..]; })*"\n"; |
} |
|
mapping lower_nowM() |
{ |
if (nowM && |
(nowM==parse |
|| nowM==classM |
|| nowM==methodM |
|| nowM==moduleM)) return nowM; |
else return nowM=methodM; |
} |
|
void report(string s) |
{ |
verbose("mkxml: "+s+"\n"); |
} |
|
#define complain(X) (X) |
|
mapping keywords= |
(["module":lambda(string arg,string line) |
{ classM=descM=nowM=moduleM=focM(parse,stripws(arg),line); |
methodM=0; |
if (!nowM->classes) nowM->classes=(["_order":({})]); |
if (!nowM->modules) nowM->modules=(["_order":({})]); |
report("module "+arg); }, |
"class":lambda(string arg,string 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,string 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=(["_order":({})]); |
if (!nowM->modules) nowM->modules=(["_order":({})]); |
report("submodule "+arg); }, |
"method":lambda(string arg,string 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; }, |
"inherits":lambda(string arg,string line) |
{ if (!nowM) return complain("inherits w/o class or module"); |
if (nowM != classM) return complain("inherits outside class or module"); |
if (!classM->inherits) classM->inherits=({}); |
classM->inherits+=({stripws(arg)}); }, |
|
"variable":lambda(string arg,string line) |
{ |
if (!classM) return complain("variable w/o class"); |
if (!classM->variables) classM->variables=({}); |
classM->variables+=({descM=nowM=(["_line":line])}); |
nowM->decl=stripws(arg); |
}, |
"constant":lambda(string arg,string line) |
{ |
if (!classM) return complain("constant w/o class"); |
if (!classM->constants) classM->constants=({}); |
classM->constants+=({descM=nowM=(["_line":line])}); |
nowM->decl=stripws(arg); |
}, |
|
"arg":lambda(string arg,string 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,string line) |
{ |
if (!lower_nowM()) |
return complain("note w/o method, class or module"); |
descM=nowM->note||(nowM->note=(["_line":line])); |
}, |
"added":lambda(string arg,string line) |
{ |
if (!lower_nowM()) |
return complain("added in: w/o method, class or module"); |
descM=nowM->added||(nowM->added=(["_line":line])); |
}, |
"bugs":lambda(string arg,string line) |
{ |
if (!lower_nowM()) |
return complain("bugs w/o method, class or module"); |
descM=nowM->bugs||(nowM->bugs=(["_line":line])); |
}, |
"see":lambda(string arg,string line) |
{ |
if (arg[0..3]!="also") |
return complain("see w/o 'also:'\n"); |
if (!lower_nowM()) |
return complain("see also w/o method, class or module"); |
sscanf(arg,"also%*[:]%s",arg); |
nowM["see also"]=map(arg/",",stripws)-({""}); |
if (!nowM["see also"]) |
return complain("empty see also\n"); |
}, |
"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=""; |
while (sscanf(s,"%s\t%s",string a,s)==2) |
{ |
res+=a; |
res+=" "[(strlen(res)%8)..7]; |
} |
return res+s; |
} |
|
|
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,mapping huh) |
{ |
string type,name,arg; |
s=replace(s,({"<",">"}),({"<",">"})); |
if (sscanf(s,"%s%*[ \t]%s(%s",type,name,arg)!=4) |
{ |
sscanf(s,"%s(%s",name,arg),type=""; |
werror(sprintf(huh->_line+": suspicios method %O\n",(s/"(")[0])); |
} |
if (arg[..1]==")(") name+="()",arg=arg[2..]; |
|
if (!arg) arg=""; |
|
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 stuff) |
{ |
string q; |
if (what==prefix[strlen(prefix)-strlen(what)-2..strlen(prefix)-3]) |
{ |
q=prefix[0..strlen(prefix)-3]; |
} |
else if (what==prefix[strlen(prefix)-strlen(what)-1..strlen(prefix)-2]) |
{ |
q=prefix[0..strlen(prefix)-2]; |
} |
else if (search(what,".")==-1 && |
search(what,"->")==-1 && |
!parse[what]) |
{ |
q=prefix+what; |
} |
else |
q=what; |
|
return "<ref to="+linkify(q)+">"+htmlify(stuff)+"</ref>"; |
} |
|
string fixdesc(string s,string prefix,string where) |
{ |
s=desc_stripws(s); |
|
string t,u,v,q; |
|
t=s; s=""; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
s+=htmlify(t); |
|
t=s; s=""; |
for (;;) |
{ |
string a,b,c; |
if (sscanf(t,"%s<%s>%s",a,b,c)<3) break; |
|
if (b[..11]=="illustration" && |
sscanf(t,"%s<illustration%s>%s</illustration>%s",t,q,u,v)==4) |
{ |
s+=replace(t,"\n\n","\n\n<p>")+ |
"<illustration __from__='"+where+"' src=image_ill.pnm"+q+">\n" |
+replace(u,"lena()","src")+"</illustration>"; |
t=v; |
} |
else if (b[..2]=="pre" && |
sscanf(t,"%s<pre%s>%s</pre>%s",t,q,u,v)==4) |
{ |
s+=replace(t,"\n\n","\n\n<p>")+ |
"<pre"+q+">\n"+u+"</pre>"; |
t=v; |
} |
else |
{ |
s+=replace(a,"\n\n","\n\n<p>")+"<"+b+">"; |
t=c; |
} |
} |
s+=replace(t,"\n\n","\n\n<p>"); |
|
if (where) |
return "<source-position " +where+ "/>\n"+s; |
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 *nice_order(string *arr) |
{ |
sort(map(arr,replace,({"_","`"}),({"ÿ","þ"})), |
arr); |
return arr; |
} |
|
string addprefix(string suffix,string prefix) |
{ |
return prefix+suffix; |
} |
|
array fix_dotstuff(array(string) in) |
{ |
if (!sizeof(in)) return ({}); |
array(string) last; |
in=Array.map(in,replace,({"->",">","<"}),({".","<",">"})); |
last=in[0]/"."; |
last=last[..sizeof(last)-2]; |
int i; |
array res=in[..0]; |
for (i=1; i<sizeof(in); i++) |
{ |
array(string) z=in[i]/"."; |
if (equal(z[..sizeof(z)-2],last)) |
res+=({"."+z[-1]}); |
else |
{ |
last=z[..sizeof(z)-2]; |
res+=in[i..i]; |
} |
} |
return res; |
} |
|
#define S(X) ("'"+(X)+"'") /* XML arg quote */ |
|
string doctype(string type,void|string indent) |
{ |
array(string) endparan(string in) |
{ |
int i; |
int q=1; |
for (i=0; i<strlen(in); i++) |
switch (in[i]) |
{ |
case '(': q++; break; |
case ')': q--; if (!q) return ({in[..i-1],in[i+1..]}); break; |
} |
return ({in,""}); |
}; |
string combine_or(string a,string b) |
{ |
if (b[..3]=="<or>") b=b[4..strlen(b)-6]; |
return "<or>"+a+b+"</or>"; |
}; |
array(string) paramlist(string in,string indent) |
{ |
int i; |
int q=0; |
array res=({}); |
for (i=0; i<strlen(in); i++) |
switch (in[i]) |
{ |
case '(': q++; break; |
case ')': q--; break; |
case ':': |
case ',': |
if (!q) return ({doctype(in[..i-1],indent+" ")})+ |
paramlist(in[i+1..],indent); |
} |
return ({in}); |
}; |
|
|
if (!indent) indent="\n "; |
string nindent=indent+" "; |
|
if (type[..2]=="...") |
return nindent+"<varargs>"+doctype(type[3..])+"</varargs>"; |
|
string a=type,b=0,c,o=0; |
sscanf(type,"%s(%s",a,b); |
if (b) [b,c]=endparan(b); |
|
if (sscanf(a,"%s|%s",string d,string e)==2) |
{ |
if (b) e+="("+b+")"+c; |
return nindent+combine_or(doctype(d,nindent), |
doctype(e,nindent)); |
} |
if (b && c!="" && sscanf(c,"%s|%s",string d,string e)==2) |
return nindent+combine_or(doctype(a+"("+b+")"+d,nindent), |
doctype(e,nindent)); |
|
switch (a) |
{ |
case "int": |
case "float": |
case "string": |
case "void": |
case "program": |
case "array": |
case "mapping": |
case "multiset": |
case "function": |
case "object": |
case "mixed": |
if (!b) return "<"+a+"/>"; |
break; |
} |
switch (a) |
{ |
case "array": |
return nindent+"<array><valuetype>"+ |
doctype(b,nindent)+"</valuetype></array>"; |
case "multiset": |
return nindent+"<multiset><indextype>"+ |
doctype(b,nindent)+"</indextype></multiset>"; |
case "mapping": |
array z=paramlist(b,nindent); |
if (sizeof(z)!=2) |
werror("warning: confused mapping type: %O\n",type), |
z+=({"mixed","mixed"}); |
return nindent+"<mapping><indextype>"+z[0]+"</indextype>"+ |
nindent+" <valuetype>"+z[1]+"</valuetype></mapping>"; |
case "object": |
return nindent+"<object>"+b+"</object>"; |
case "function": |
z=paramlist(b,nindent); |
if (sizeof(z)<1) |
werror("warning: confused function type: %O\n",type), |
z+=({"mixed"}); |
return |
nindent+ |
"<function>"+ |
map(z[..sizeof(z)-2], |
lambda(string s) |
{ |
return nindent+" <argtype>"+s+"<argtype>"; |
})*""+ |
nindent+" <returntype>"+z[-1]+"</returntype>"+ |
nindent+"</function>"; |
} |
if (b && a=="int") |
{ |
if (sscanf(b,"%d..%d",int min,int max)==2) |
return nindent+"<int><min>"+min+"</min><max>"+max+"</max></int>"; |
if (sscanf(b,"..%d",int max)==1) |
return nindent+"<int><max>"+max+"</max></int>"; |
if (sscanf(b,"%d..%",int min)==1) |
return nindent+"<int><min>"+min+"</min></int>"; |
} |
|
if (b) |
werror("warning: confused type: %O\n",type); |
|
return nindent+"<object>"+type+"</object>"; |
} |
|
constant convname= |
([ |
"`>":"`>", |
"`<":"`<", |
"`>=":"`>=", |
"`<=":"`<=", |
"`&":"`&", |
]); |
|
void docdecl(string enttype, |
string decl, |
object f) |
{ |
string rv,name,params=0; |
sscanf(decl,"%s %s(%s",rv,name,params); |
|
if (convname[name]) name=convname[name]; |
|
f->write("<"+enttype+" name="+S(name)+">"); |
|
if (params) |
{ |
string paramlist(string in) |
{ |
int i; |
int q=1; |
array res=({}); |
string t; |
if (in=="" || in[..0]==")") return ""; |
for (i=0; i<strlen(in); i++) |
switch (in[i]) |
{ |
case '(': q++; break; |
|
case ')': q--; if (q) break; |
case ':': |
case ',': |
array z=in[..i-1]/" "-({""}); |
if (sizeof(z)==1) |
return "\n <argument><type>"+doctype(z[0],"\n ")+ |
"</type></argument>"+ |
paramlist(in[i+1..]); |
else |
return "\n <argument name="+S(z[-1])+ |
"><type>"+doctype(z[0..sizeof(z)-2]*"","\n ")+ |
"</type></argument>"+ |
paramlist(in[i+1..]); |
} |
array z=in[..i-1]/" "-({""}); |
if (sizeof(z)==1) |
return "\n <argument><type>"+doctype(z[0])+ |
"</type></argument>"; |
else |
return "\n <argument name="+S(z[-1])+ |
"><type>"+doctype(z[0..sizeof(z)-2]*""); |
}; |
|
f->write("\n <returntype>"+doctype(rv,"\n ")+"</returntype>\n" |
" <arguments>"+paramlist(params)+"\n </arguments>\n"); |
} |
else |
{ |
f->write("<typevalue>"+doctype(rv)+"</typevalue>\n"); |
} |
|
f->write("</"+enttype+">"); |
} |
|
Parser.HTML html2xml; |
|
void document(string enttype, |
mapping huh,string name,string prefix, |
object f) |
{ |
string *names; |
|
if (huh->names) |
names=map(indices(huh->names),addprefix,name); |
else |
names=({name}); |
|
verbose("mkxml: "+name+" : "+names*","+"\n"); |
|
array v=name/"."; |
string canname=v[-1]; |
sscanf(canname,"%s->",canname); |
sscanf(canname,"%s()",canname); |
|
if (convname[canname]) canname=convname[canname]; |
|
switch (enttype) |
{ |
case "class": |
case "module": |
f->write("<"+enttype+" name="+S(canname)+">\n"); |
break; |
default: |
f->write("<docgroup homogen-type="+S(enttype)+ |
" homogen-name="+S(canname)+">\n"); |
|
if (huh->decl) |
{ |
foreach (arrayp(huh->decl)?huh->decl:({huh->decl}),string decl) |
{ |
docdecl(enttype,decl,f); |
} |
} |
else |
foreach (names,string name) |
{ |
if (convname[name]) name=convname[name]; |
f->write("<"+enttype+" name="+S(name)+">\n"); |
f->write("</"+enttype+">"); |
} |
break; |
} |
f->write("<source-position " + huh->_line + "/>\n"); |
|
|
|
string res=""; |
|
if (huh->desc) |
{ |
res+="<text>\n"; |
|
if (huh->inherits) |
{ |
string s=""; |
foreach (huh->inherits,string what) |
res+="inherits "+make_nice_reference(what,prefix,what)+ |
"<br/>\n"; |
res+="<br/>\n"; |
} |
|
res+=fixdesc(huh->desc,prefix,huh->_line)+"\n"; |
res+="</text>\n"; |
} |
|
|
|
#if 1 |
if (huh->args) |
{ |
string rarg=""; |
mapping arg; |
|
array v=({}); |
|
foreach (huh->args, arg) |
{ |
v+=arg->args; |
if (arg->desc) |
{ |
res+="<group>\n"; |
foreach (v,string arg) |
{ |
sscanf(arg,"%*s %s",arg); |
sscanf(arg,"%s(%*s",arg); |
res+=" <param name="+S(arg)+"/>\n"; |
} |
res+= |
"<text>"+ |
fixdesc(arg->desc,prefix,arg->_line)+ |
"</text></group>\n"; |
} |
} |
if (rarg!="") error("trailing args w/o desc on "+arg->_line+"\n"); |
} |
#endif |
|
|
|
if (huh->returns) |
{ |
res+="<group><returns/>\n"; |
res+=fixdesc(huh->returns,prefix,huh->_line)+"\n"; |
res+="</group>\n"; |
} |
|
|
|
|
if (huh->note && huh->note->desc) |
{ |
res+="<group><note/>\n"; |
res+=fixdesc(huh->note->desc,prefix,huh->_line)+"\n"; |
res+="</group>\n"; |
} |
|
|
|
if (huh->bugs && huh->bugs->desc) |
{ |
res+="<group><bugs/>\n"; |
res+=fixdesc(huh->bugs->desc,prefix,huh->_line)+"\n"; |
res+="</group>\n"; |
} |
|
|
|
if (huh->added && huh->added->desc) |
{ |
|
} |
|
|
|
if (huh["see also"]) |
{ |
res+="<group><seealso/>\n"; |
res+=fixdesc( |
map(huh["see also"], |
lambda(string s) |
{ |
return "<ref>"+htmlify(s)+"</ref>"; |
})*", ", |
prefix,0); |
res+="</group>\n"; |
} |
|
if (res!="") |
{ |
res=html2xml->finish(res)->read(); |
f->write("<doc>\n"+res+"\n</doc>\n"); |
} |
|
|
|
if (huh->constants) |
{ |
foreach(huh->constants,mapping m) |
{ |
sscanf(m->decl,"%s %s",string type,string name); |
sscanf(name,"%s=%s",name,string value); |
document("constant",m,prefix+name,prefix+name+".",f); |
} |
} |
|
if (huh->variables) |
{ |
foreach(huh->variables,mapping m) |
{ |
sscanf(m->decl,"%s %s",string type,string name); |
if (!name) name=m->decl,type="mixed"; |
sscanf(name,"%s=%s",name,string value); |
document("variable",m,prefix+name,prefix+name+".",f); |
} |
} |
|
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=nice_order(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",method,prefix,prefix,f); |
method_names-=method->names; |
} |
if (method_names[method_name]) |
stderr->write("failed to find "+method_name+" again, wierd...\n"); |
} |
} |
|
if (huh->classes) |
{ |
foreach(huh->classes->_order,string n) |
{ |
|
document("class",huh->classes[n], |
prefix+n,prefix+n+"->",f); |
|
} |
} |
|
if (huh->modules) |
{ |
foreach(huh->modules->_order,string n) |
{ |
document("module",huh->modules[n], |
prefix+n,prefix+n+".",f); |
} |
} |
|
|
switch (enttype) |
{ |
case "class": |
case "module": |
f->write("</"+enttype+">\n\n"); |
break; |
default: |
f->write("</docgroup>\n\n"); |
break; |
} |
} |
|
void make_doc_files() |
{ |
html2xml=Parser.HTML(); |
html2xml->add_tag("p",lambda(mixed...) { return ({"</p><p>"}); }); |
html2xml->add_tag("br",lambda(mixed...) { return ({"<br/>"}); }); |
html2xml->add_tag("wbr",lambda(mixed...) { return ({"<wbr/>"}); }); |
html2xml->add_container( |
"text", |
lambda(Parser.HTML p,mapping args,string cont) |
{ |
|
cont=p->clone()->finish(cont)->read(); |
|
|
string res="<text><p>"+cont+"</p></text>"; |
string t; |
do |
{ |
t=res; |
res=replace(res,"<p></p>",""); |
res=replace(res,"<br/></p>","</p>"); |
} |
while (t!=res); |
return ({res}); |
}); |
|
stderr->write("modules: "+sort(indices(parse))*", "+"\n"); |
|
stdout->write("<module name=''>\n"); |
|
foreach (sort(indices(parse)-({"_order"})),string module) |
document("module",parse[module],module,module+".",stdout); |
|
stdout->write("</module>\n"); |
} |
|
int inpre=0; |
|
void process_line(string s,string currentfile,int line) |
{ |
s=getridoftabs(s); |
|
int i; |
if ((i=search(s,"**!"))!=-1 || (i=search(s,"//!"))!=-1) |
{ |
string kw,arg; |
|
sscanf(s[i+3..],"%*[ \t]%[^: \t\n\r]%*[: \t]%s",kw,arg); |
if (keywords[kw]) |
{ |
string err; |
if ( (err=keywords[kw](arg,"file='"+currentfile+"' line='"+line+"'")) ) |
{ |
stderr->write("mkxml: "+ |
currentfile+"file='"+currentfile+"' line="+line); |
exit(1); |
} |
inpre=0; |
} |
else if (s[i+3..]!="") |
{ |
string d=s[i+3..]; |
|
|
if (!descM) descM=methodM; |
if (!descM) |
{ |
stderr->write("mkxml: "+ |
currentfile+" line "+line+ |
": illegal description position\n"); |
exit(1); |
} |
if (!descM->desc) descM->desc=""; |
else descM->desc+="\n"; |
d=getridoftabs(d); |
descM->desc+=d; |
} |
else if (descM) |
{ |
if (!descM->desc) descM->desc=""; |
else descM->desc+="\n"; |
} |
} |
} |
|
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..]; |
|
if (sizeof(files) && files[0]=="--nonverbose") |
files=files[1..],verbose=lambda(){}; |
|
stderr->write("mkxml: reading files...\n"); |
|
for (;;) |
{ |
int i; |
inpre=0; |
|
if (!f) |
{ |
if (!sizeof(files)) break; |
verbose("mkxml: 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); |
if (!t) |
{ |
werror("mkxml: failed to read %O\n",currentfile); |
f=0; |
continue; |
} |
s=ss[0]; |
ss=t/"\n"; |
ss[0]=s+ss[0]; |
} |
s=ss[0]; ss=ss[1..]; |
|
line++; |
process_line(s,currentfile,line); |
} |
|
|
|
stderr->write("mkxml: making docs...\n\n"); |
|
make_doc_files(); |
|
return 0; |
} |
|
|