#!/home/x97davka/arch/sparc-sun-solaris5.5.1/bin/pike
// -*- pike -*-

object comstart = Regexp("^[ \t]*(\\(|)\\*\\*(.*)$");
object procinst = Regexp("^[ \t]*\\(\\*!([a-z]*)");

string untabify(string s)
{
  string s1, s2;
  while(sscanf(s,"%[^\t]\t%s", s1, s2) == 2)
    s = s1 + String.strmult(" ", 8 - sizeof(s1)%8) + s2;
  return s;
}

string tex_escape(string s)
{
  array a;
  string ss = "";
  s = replace(s,
	      ({ "_"  , "{"  , "}"  , "\\" }),
	      ({ "\\_", "\\{", "\\}", "\\\\" }));
  while(a=Regexp("([^`]*)`([^']*)'(.*)")->split(s))
  {
    ss += a[0]+"\\code{"+a[1]+"}";
    s = a[2];
  }
  return ss + s;
}

#define OUT(x) outbuf += (x)

void convert(string f)
{
  array(string) lines = Stdio.read_file(f) / "\n";
  string state = "start", buf = "", desc = "";
  string fn = (f/"/")[-1];
  string module = fn - ".rml";
  array a;
  int ignorecode = 0, lno = 0;
  string outbuf = "";

  foreach(lines, string line)
  {
    int empty = Regexp("^[ \t]*$")->match(line);
    lno++;
    // write(sprintf("+%s\n",line));
    if(a = procinst->split(line))
    {
      switch(a[0]) {
      case "ignorecode":
	ignorecode = 1; break;
      case "includecode":
	ignorecode = 0; break;
      default:
	werror(sprintf("%s:%d: unknown processing instruction: %s\n",
		       f, lno, a[0]));
      }
    }
    else if(a = comstart->split(line))
    {
      // write("-com\n");
      string s, newstate;
      switch(state) {
      case "start":
      case "comment":
      case "itemize":
	break;
      case "code2":
	OUT("\\end{boxedverbatim}\n\n");
	break;
      case "code1":
	OUT("\n");
	break;
      }
      newstate = "comment";
      // Remove extra stuff at the end of the line
      s = a[1];
      if(s[sizeof(s)-2..] == "*)")
	s = s[..sizeof(s)-3];
      while(sizeof(s) && s[-1] == ' ') s = s[..sizeof(s)-2];
      // Escape TeX special characters
      s = tex_escape(s);

      if(s==")")
	;
      else if(s[..2] == " - ")
      {
	OUT("\n\\subsection{"+s[3..]+"}\n\n");
      }
      else if(s[..3] == "  o ")
      {
	newstate = "itemize";
	if(state != "itemize")
	  OUT("\\begin{itemize}\n");
	OUT("\\item "+s[4..]+"\n");
      }
      else if(s[..3] == "    " && state == "itemize")
      {
	newstate = "itemize";
	OUT("      "+s[4..]+"\n");
      }
      else if(s[..1] == "  ")
	OUT("\\subsubsection{"+s[2..]+"}\n");
      else if(a = Regexp("^ *([a-zA-Z]*):[ \t]*(.*)")->split(s))
      {
	switch(lower_case(a[0])) {
	case "file":
	  if(a[1] != fn)
	  {
	    werror("Filename mismatch in file "+f+
		   ": claims to be '"+a[1]+"'\n");
	    fn = (a[1]/"/")[-1];
	    module = fn - ".rml";
	  }
	  break;
	case "module":
	  module = a[1];
	  break;
	case "description":
	  desc = a[1];
	  break;
	case "relation":
	  OUT("\\subsubsection{Relation \\code{"+a[1]+"}}\n"
	      "\\label{src:"+module+":"+lower_case(a[1]-"\\_")+"}\n");
	  break;
	case "purpose":
	  OUT("\\textbf{Purpose:} "+a[1]+"\n\\vspace{1ex}\n");
	  break;
	case "fixme":
	  OUT("\\fixme{"+a[1]+"}\n");
	  break;
	case "rcs":
	  OUT("% "+a[1]+"\n");
	  break;
	default:
	  werror(sprintf("%s:%d: Warning: ignored header %s\n",
			 f,lno,a[0]));
	}
      }
      else
	OUT(s+"\n");
      if(state == "itemize" && newstate != "itemize")
	OUT("\\end{itemize}\n");
      state = newstate;
    }
    else if(!ignorecode)
    {
      // write("-code: "+state+"\n");
      switch (state) {
      case "code1":
      case "code2":
	break;
      case "start":
      case "comment":
	// OUT("{\\small\\begin{verbatim}\n");
	buf = "";
	break;
      }
      line = untabify(line);
      if(!empty)
      {
	if(state!="code2")
	  OUT("\\begin{boxedverbatim}\n");
	state = "code2";
      }
      else if (state != "code2")
	state = "code1";
      
      if(state == "code2")
	if(empty)
	  buf += "\n";
	else
	{
	  OUT(buf+line+"\n");
	  buf = "";
	}
    }
  }

  if(state == "code2")
    // OUT("\\end{verbatim}}\n");
    OUT("\\end{boxedverbatim}\n\n");

  write("\\sourcefile{"+module+"}{"+desc+"}\n"+outbuf);
}

int main(int argc, array argv)
{
  foreach(argv[1..], string f)
    convert(f);
}
