pike.git / src / modules / Image / mkdoc.pike

version» Context lines:

pike.git/src/modules/Image/mkdoc.pike:1: - #include <stdio.h> + import Stdio; + import Array;      mapping parse=([]);      /*      module : mapping <- moduleM    "desc" : text -  "classes" : mapping <- classM -  class : mapping +  "see also" : array of references +  "note" : mapping of "desc": text +  "classes" : mapping +  class : mapping <- classM +  "see also" : array of references    "desc" : text -  +  "note" : mapping of "desc": text    "methods" : array of mappings <- methodM -  "methods" : list of method names +     "decl" : array of textlines of declarations    "desc" : text    "returns" : textline    "see also" : array of references -  "note" : text -  "args" : mapping -  arg : mapping <- argM -  "type" : textline -  "desc" : text +  "note" : mapping of "desc": text +  "args" : array of mappings <- argM +  "args" : array of args names and types +  "desc" : description +  "names" : multiset of method name(s)      */    - mapping moduleM, classM, methodM, argM; + 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; + } +  + #define complain(X) (X) +  + mapping keywords= + (["module":lambda(string arg,int line) +  { nowM=moduleM=focM(parse,stripws(arg),line); classM=methodM=0; +  if (!nowM->classes) nowM->classes=([]); }, +  "class":lambda(string arg,int line) +  { if (!moduleM) return complain("class w/o module"); +  nowM=classM=focM(moduleM->classes,stripws(arg),line); +  methodM=0; }, +  "method":lambda(string arg,int line) +  { if (!classM) return complain("method w/o class"); +  if (!nowM || methodM!=nowM || methodM->desc || methodM->args) +  { if (!classM->methods) classM->methods=({}); +  classM->methods+=({methodM=nowM=(["decl":({}),"_line":line])}); } +  methodM->decl+=({stripws(arg)}); }, +  "arg":lambda(string arg,int line) +  { +  if (!methodM) return complain("arg w/o method"); +  if (nowM!=argM || !argM) +  { if (!methodM->args) methodM->args=({}); +  methodM->args+=({argM=nowM=(["args":({}),"_line":line])}); } +  argM->args+=({arg}); +  }, +  "note":lambda(string arg,int line) +  { +  if (!lower_nowM()) +  return complain("note w/o method, class or module"); +  nowM=nowM->note||(nowM->note=(["_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); +  } + ]); +  + 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]; +  } + } +  + string addprefix(string suffix,string prefix) + { +  return prefix+suffix; + } +  + string make_nice_reference(string refto,string my_prefix) + { +  return "<tt><a href=#>"+refto+"</a></tt>"; + } +  + object(File) make_file(string filename) + { +  stdout->write("creating "+filename+"...\n"); +  if (file_size(filename)>0) +  { +  rm(filename+"~"); +  mv(filename,filename+"~"); +  } +  object f=File(); +  if (!f->open(filename,"wtc")) +  { +  stdout->write("failed."); +  exit(1); +  } +  return f; + } +  + string fixdesc(string s,string prefix) + { +  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; +  return replace(s,"\n\n","\n\n<p>"); + } +  + string standard_doc(mapping info,string myprefix) + { +  string res=""; +  +  if (info->desc && stripws(info->desc)!="") +  res+="\n\n<blockquote>\n"+info->desc+"\n</blockquote>\n"; +  +  if (info->note) +  res+="\n\n<h4>NOTE</h4>\n<blockquote>\n"+ +  fixdesc(info->desc,myprefix)+"\n</blockquote>\n"; +  +  if (info["see also"]) +  { +  res+= +  "\n\n<h4>SEE ALSO</h4>\n<blockquote> " + +  map(info["see also"],make_nice_reference,myprefix)*",\n " + +  "\n</blockquote>\n"; +  } +  +  return res; + } +  + void make_an_index(string title, +  string file, +  mapping info, +  string prefix, +  string *refs) + { +  object f=make_file(file); +  f->write("<title>Pike documentation: "+title+"</title>\n"+ +  "<h2>"+title+"</h2>\n"+ +  standard_doc(info,prefix)); +  if (sizeof(refs)) +  { +  f->write("<h3>More documentation:</h3>\n <i><tt>" + +  map(map(refs,addprefix,prefix), +  make_nice_reference,prefix)*"</tt></i><br>\n <i><tt>" + +  "</tt></i>\n\n"); +  } +  f->close(); + } +  + 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 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,({","," "}),({", ","&nbsp"})); + } +  + void document_method(object(File) f, +  mapping method, +  string prefix) + { +  stdout->write("documenting "+prefix+" methods "+ +  sort(indices(method->names))*", "+"...\n"); +  +  f->write("\n<hr>\n" +  // anchors goes here +  "<h4>SYNOPSIS</h4>\n" +  "<blockquote>\n" +  "<tt>"+map(method->decl,synopsis_to_html)* +  "<br>\n"+ +  "</tt>\n</blockquote>\n\n"); +  +  if (method->desc && stripws(method->desc)!="") +  { +  f->write("<h4>DESCRIPTION</h4>\n" +  "\n\n<blockquote>\n"+ +  fixdesc(method->desc,prefix)+ +  "\n</blockquote>\n"); +  } +  +  if (method->args) +  { +  mapping arg; +  f->write("<h4>ARGUMENTS</h4>\n<blockquote><dl>\n"); +  foreach (method->args,arg) +  { +  f->write("<dt><tt>"+arg->args*"</tt>\n<dt><tt>"+ +  "</tt>\n <dd>"+ +  fixdesc(arg->desc,prefix)+"\n"); +  } +  f->write("</dl></blockquote>\n"); +  } +  +  if (method->returns) +  { +  f->write("<h4>RETURNS</h4>\n" +  "\n\n<blockquote>\n"+method->returns+"\n</blockquote>\n"); +  } +  +  if (method->note) +  { +  f->write("\n\n<h4>NOTE</h4>\n<blockquote>\n"+ +  method->desc+"\n</blockquote>\n"); +  } +  +  if (method["see also"]) +  { +  f->write("\n\n<h4>SEE ALSO</h4>\n<blockquote> " + +  map(method["see also"], +  make_nice_reference,prefix)*",\n " + +  "\n</blockquote>\n"); +  } + } +  + void document_class(string title, +  string file, +  mapping info, +  string prefix) + { +  stdout->write("documenting "+title+"...\n"); +  +  object(File) f=make_file(file); +  +  f->write("<title>Pike documentation: "+title+"</title>\n"+ +  "<h2>"+title+"</h2>\n"+ +  standard_doc(info,prefix)); +  +  // postprocess methods to get names +  +  multiset(string) method_names=(<>); +  string *method_names_arr,method_name; +  mapping method; +  +  foreach (info->methods,method) +  method_names|=(method->names=get_method_names(method->decl)); +  +  method_names_arr=sort(indices(method_names)); +  +  f->write("\n<hr>\n <i><tt>"+ +  map(method_names_arr,make_nice_reference,prefix)* +  "</tt></i><br>\n <i><tt>"+"</tt></i><br>\n\n"); +  // alphabetically +  +  foreach (method_names_arr,method_name) +  if (method_names[method_name]) +  { +  // find it +  foreach (info->methods,method) +  if ( method->names[method_name] ) +  { +  document_method(f,method,prefix); +  method_names-=method->names; +  } +  } +  +  f->close(); +  + } +  + void make_doc_files(string dir) + { +  stdout->write("modules: "+sort(indices(parse))*", "+"\n"); +  +  string module,clas; +  +  foreach (sort(indices(parse)),module) +  { +  make_an_index("module "+module, +  dir+module+".html", parse[module], +  module+".", sort(indices(parse[module]->classes))); +  +  stdout->write("module "+module+" class(es): "+ +  sort(indices(parse[module]->classes))*", "+"\n"); +  +  foreach (sort(indices(parse[module]->classes)),clas) +  document_class(module+"."+clas, +  dir+module+"."+clas+".html", +  parse[module]->classes[clas], +  module+"."+clas); +  } + } +    int main()   { -  +  stdout->write("reading data...\n"); +     string doc=stdin->read(10000000); -  +  string s; +  int line;    -  +  nowM=parse; +  +  stdout->write("parsing data...\n"); +  +  foreach (doc/"\n",s) +  { +  int i; +  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,line)) ) +  { +  stderr->write("Error on line "+line+": "+err+"\n"); +  return 1;    } -  +  } +  else +  { +  if (!nowM && !(nowM=descM) ) +  { +  stderr->write("Error on line "+line+": illegal description position\n"); +  return 1; +  } +  if (!nowM->desc) nowM->desc=""; +  else nowM->desc+="\n"; +  s=getridoftabs(s); +  nowM->desc+=s[search(s,"**!")+3..]; +  descM=nowM; nowM=0; +  } +  } +  } +  + // stderr->write(sprintf("%O",parse)); +  +  stdout->write("making docs...\n\n"); +  +  make_doc_files("doc/"); +  return 0; + }