#line 2554 "/home/travis/build/felix-lang/felix/src/packages/flx_web.fdoc"
  include "./plugin_common";
  
  var C_PATH = Empty[string];
  var INSTALL_ROOT = "";
  
  
  module Cpp2Html {
  // C++ and C
  val cpp_big_keywords =
    "class",
    "struct",
    "union",
    "namespace",
    "typedef",
    "enum",
    "template"
  ;
  
  val cpp_small_keywords =
    "if", "while", "until","do","for","return","goto","std"
  ;
  
  val cpp_qualifiers =
    "virtual", "inline", "static", "extern", "public","private","protected",
    "int","long","unsigned","float","double","char","short","signed","void","size_t",
    "const","volatile","typename"
  ;
  
  val cpp_preproc =
    "define","if","endif","else","include","ifdef","ifndef"
  ;
  
  fun xlat_cpp(t:string, dir:string) : bool * string=
  {
    var out = "";
    proc write_string(t:string)
    {
      out += t;
    }
  
    union state_t =
      | sot // start of token
      | id // processing identifier
      | num // in a number
      | sq // processing single quote string
      | dq // processing double quote string
      | angle // processing <filename> string
      | ccomment // a C style comment
      | cppcomment // a C++ style comment
    ;
    fun str(s:state_t) => match s with
    | #sot => "sot"
    | #id => "id"
    | #num => "num"
    | #sq => "sq"
    | #dq => "dq"
    | #angle => "angle"
    | #ccomment=> "ccomment"
    | #cppcomment => "cppcomment"
    endmatch;
  
    var i = 0; var s:state_t;
    var ch = t.[i];
    proc next() { ch = t.[i]; ++i; }
    fun ahead (j:int)=> t.[i + j - 1];
  
    var b = "";
    var last_id = "";
    var last_op = "";
    proc cp() { b += ch; }
    proc ws() {
      if last_id == "include" do // hackery
        var n = b;
        while n.[0] == char '<' or n.[0] == char '"' do n = n.[1 to]; done
        while n.[-1] == char '>' or n.[-1] == char '"' do n = n.[to -1]; done
        var x = b;
        if x.[0] == char "<" do x = "&lt;" + x.[1 to]; done
        if x.[-1] == char ">" do x = x.[to -1] + "&gt;"; done
        match get_file(n,INSTALL_ROOT,Cons(dir,C_PATH)) with
        | Some f =>
            // the $ is so we know we have resolved the filename
            // we can't use just / because it means the server root
            // and we can't use // because firefox thinks it means
            // the website name is empty
            // the trailing cpp tells us the filetype is C/C++
            write_string('<a href="/$'+f+'" >' + x + '</a>');
        | #None => write_string('<span class="fstring">'+x+"</span>");
        endmatch;
      else
       write_string('<span class="fstring">'+b+"</span>");
      done
    }
    proc w() {
      //println$ "Token["+str s+"]="+b;
      match s with
      | #dq => ws;
      | #sq => ws;
      | #ccomment=> write_string('<span class="comment">'+b+"</span>");
      | #cppcomment=> write_string('<span class="comment">'+b+"</span>");
      | #id =>
          last_id = b;
          if b in cpp_big_keywords do write_string('<span class="big_keyword">'+b+"</span>");
          elif b in cpp_small_keywords do write_string('<span class="small_keyword">'+b+"</span>");
          elif b in cpp_qualifiers do write_string('<span class="qualifier">'+b+"</span>");
          elif last_op == "#" and b in cpp_preproc do write_string('<span class="preproc">'+b+"</span>"); last_op="";
          else write_string(b); done
      | #angle => ws;
      | _ =>
          last_op=b;
          if b == "<" do b = "&lt;";
          elif b == ">" do b = "&gt;";
          elif b == "&" do b = "&amp;";
          done;
          write_string(b);
      endmatch;
      b = "";
    }
  
  
    goto nextt;
  
  contin:> // copy char and continue
    cp();
    goto nextch;
  
  overrun:> // one past last char of token
    w();
    s = sot;
    goto thisch;
  
  lastch:> // last char of token
    cp();
    w();
  
  nextt:>  // new token on next char
    s = sot;
  
  nextch:> // next char
    next();
  
  thisch:> // same char, reconsider it
    //println$ "Considering char " + str(ord(ch));
    if isnull ch goto fin; // out of data
    match s with
    | #sot =>
        if isidstart ch do s = id; goto contin;
        elif isdigit ch do s = num; goto contin;
        elif issq ch do s = sq; goto contin;
        elif isdq ch do s = dq; goto contin;
        elif ch == char "/" do
          if ahead(1) == char "/" do cp; next; s = cppcomment; goto contin;
          elif ahead(1) == char "*" do cp; next; s = ccomment; goto contin;
          else goto lastch;
          done
        elif ch == char "<" and last_id == "include" do
          s = angle; goto contin;
        else cp; w; goto nextt;
        done
  
    | #id =>
        if isalphanum ch do goto contin;
        else goto overrun;
        done
    | #num =>
        if isnumeric ch do goto contin;
        else goto overrun;
        done
    // single quoted strings
    | #sq =>
        if issq ch do goto lastch;
        elif ch== char "<" do b+="&lt;"; goto nextch;
        elif ch== char ">" do b+="&gt;"; goto nextch;
        elif ch== char "&" do b+="&amp;"; goto nextch;
        else goto contin;
        done
    | #dq =>
        if isdq ch do goto lastch;
        elif ch== char "<" do b+="&lt;"; goto nextch;
        elif ch== char ">" do b+="&gt;"; goto nextch;
        elif ch== char "&" do b+="&amp;"; goto nextch;
        else goto contin;
        done
  
    // <bracket> form
    | #angle =>
        if ch == char ">" do goto lastch;
        else goto contin;
        done
  
    // comments
    | #cppcomment =>
        if iseol ch do goto lastch;
        else goto contin;
        done
    | #ccomment => // doesn't handle nested comments yet
        if ch == char "*" and ahead(1) == char "/" do
          cp;
          goto lastch;
        else goto contin;
        done
    endmatch
    ;
    println$ "Unexpected drop thru";
  
  fin:>
     w(); // whatever is left over gets written
     return false, out;
  }
  }
  eprintln$ Version::felix_version+ " cpp2html initialisation";
  
  fun setup(config_data:string) = {
    var config_lines = split(config_data, "\n");
    config_lines = map (strip of (string)) config_lines;
    var pathext = RE2("(.*)\\+=(.*)");
    var varset = RE2("(.*)=(.*)");
    var plugin_spec = RE2 " *extension (.*)->(.*)::(.*)";
  
    var result = varray[StringPiece] (4.size,StringPiece(""));
    for line in config_lines do
      var match_result = Match(pathext, StringPiece(line),0,ANCHOR_BOTH, result.stl_begin,3);
      if match_result do
        var lhs = result.1.str.strip;
        var rhs = result.2.str.strip;
        match lhs with
        | "C_PATH" => C_PATH += rhs;
        | _ => ;
        endmatch;
      else
      match_result = Match(varset, StringPiece(line),0,ANCHOR_BOTH, result.stl_begin,3);
      if match_result do
        lhs = result.1.str.strip;
        rhs = result.2.str.strip;
        match lhs with
        | "INSTALL_ROOT" => INSTALL_ROOT = rhs;
        | _ => ;
        endmatch;
      done done
    done
  
    return 0;
  }
  
  export fun setup of (string) as "cpp2html_setup";
  export fun Cpp2Html::xlat_cpp of (string * string) as "cpp2html";