
/******************************************************************************
* MODULE     : input.gen.cc
* DESCRIPTION: Generic TeXmacs input
* COPYRIGHT  : (C) 2000  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#include <path.gen.h>
#include <convert.gen.h>
#include <hashmap.gen.h>

#module code_input
#import path
#import convert
#import hashmap (string, tree)

extern bool guile_eval (string s);

#define DATA_BEGIN   ((char) 2)
#define DATA_END     ((char) 5)
#define DATA_ESCAPE  ((char) 27)

#define STATUS_NORMAL 0
#define STATUS_ESCAPE 1
#define STATUS_BEGIN  2

#define MODE_VERBATIM 0
#define MODE_SCHEME   1
#define MODE_LATEX    2
#define MODE_HTML     3
#define MODE_PS       4
#define MODE_ISPELL   5
#define MODE_CHANNEL  6
#define MODE_COMMAND  7

/******************************************************************************
* Universal data input
******************************************************************************/

struct texmacs_input_rep: concrete_struct {
  bool   status;
  path   mode;
  string buf;
  bool   generic_flag;

  tree   channels;
  hashmap<string,tree> docs;

  texmacs_input_rep (string the_mode);
  int  get_mode (string s);
  bool put (char c);
  void bof ();
  void eof ();
  void flush (bool force= FALSE);
  void write (tree t);
  tree get (string channel= "output");

  void verbatim_flush (bool force= FALSE);
  void scheme_flush (bool force= FALSE);
  void latex_flush (bool force= FALSE);
  void html_flush (bool force= FALSE);
  void ps_flush (bool force= FALSE);
  void ispell_flush (bool force= FALSE);
  void channel_flush (bool force= FALSE);
  void command_flush (bool force= FALSE);
};

texmacs_input_rep::texmacs_input_rep (string the_mode):
  status (STATUS_NORMAL), mode (get_mode (the_mode)), buf (""),
  generic_flag (the_mode == "generic"),
  channels (tuple ("output", "")),
  docs (tree (DOCUMENT, "")) { bof (); }

class texmacs_input {
#import concrete (texmacs_input, texmacs_input_rep)
  texmacs_input (string the_mode);
};
#import code_concrete (texmacs_input, texmacs_input_rep)

texmacs_input::texmacs_input (string the_mode):
  rep (new texmacs_input_rep (the_mode)) {}

/******************************************************************************
* Main routines
******************************************************************************/

int
texmacs_input_rep::get_mode (string s) {
  if (s == "latex") return MODE_LATEX;
  if (s == "scheme") return MODE_SCHEME;
  if (s == "html")  return MODE_HTML;
  if (s == "ps")  return MODE_PS;
  if (s == "ispell")  return MODE_ISPELL;
  if (s == "channel")  return MODE_CHANNEL;
  if (s == "command")  return MODE_COMMAND;
  return MODE_VERBATIM;
}

bool
texmacs_input_rep::put (char c) { // returns TRUE when expecting input
  // cout << c;
  if (generic_flag) {
    bool block_done= FALSE;
    switch (status) {
    case STATUS_NORMAL:
      if (c == DATA_ESCAPE) status= STATUS_ESCAPE;
      else if (c == DATA_BEGIN) {
	flush (TRUE);
	status= STATUS_BEGIN;
      }
      else if (c == DATA_END) {
	flush (TRUE);
	if (!atom (mode)) {
	  mode    = mode->next;
	  channels= channels[1];
	}
	block_done= atom (mode);
      }
      else buf << c;
      break;
    case STATUS_ESCAPE:
    buf << c;
    status= STATUS_NORMAL;
    break;
    case STATUS_BEGIN:
      if (c == ':') {
	mode    = path (get_mode (buf), mode);
	channels= tuple (channels[0], channels);
	buf     = "";
	status  = STATUS_NORMAL;
      }
    else buf << c;
      break;
    }
    if (status == STATUS_NORMAL) flush ();
    return block_done;
  }
  else {
    if (c == DATA_END) return TRUE;
    buf << c;
    flush ();
    if (buf == "") return TRUE;
  }
  return FALSE;
}

void
texmacs_input_rep::bof () {
  channels[0]= "output";
  docs= hashmap<string,tree> (tree (DOCUMENT, ""));
  docs (channels[0]->label)= tree (DOCUMENT, "");
}

void
texmacs_input_rep::eof () {
  flush (TRUE);
}

void
texmacs_input_rep::flush (bool force) {
  switch (mode->item) {
  case MODE_SCHEME:
    scheme_flush (force);
    break;
  case MODE_LATEX:
    latex_flush (force);
    break;
  case MODE_HTML:
    html_flush (force);
    break;
  case MODE_PS:
    ps_flush (force);
    break;
  case MODE_ISPELL:
    ispell_flush (force);
    break;
  case MODE_CHANNEL:
    channel_flush (force);
    break;
  case MODE_COMMAND:
    command_flush (force);
    break;
  default:
    verbatim_flush (force);
    break;
  }
}

void
texmacs_input_rep::write (tree u) {
  tree& t (docs (channels[0]->label));
  if (!is_document (u)) u= tree (DOCUMENT, u);
  if (t[N(t)-1] == "") t[N(t)-1]= u[0];
  else {
    if (!is_concat (t[N(t)-1])) t[N(t)-1]= tree (CONCAT, t[N(t)-1]);
    if (!is_concat (u[0])) u[0]= tree (CONCAT, u[0]);
    t[N(t)-1] << A(u[0]);
  }
  t << A (u (1, N(u)));
}

tree
texmacs_input_rep::get (string channel) {
  tree& doc (docs (channel));
  if (doc == tree (DOCUMENT, "")) return "";
  tree t= doc;
  doc= tree (DOCUMENT, "");
  return t;
}

/******************************************************************************
* Flushing
******************************************************************************/

void
texmacs_input_rep::verbatim_flush (bool force) {
  if (force || ends (buf, "\n")) {
    write (verbatim_to_tree (buf));
    buf= "";
  }
}

void
texmacs_input_rep::scheme_flush (bool force) {
  if (force) {
    write (scheme_to_tree (buf));
    buf= "";
  }
}

void
texmacs_input_rep::latex_flush (bool force) {
  if (force || ends (buf, "\n\n")) {
    write (latex_to_tree (buf, "text"));
    buf= "";
  }
}

void
texmacs_input_rep::html_flush (bool force) {
  if (force || ends (buf, "</P>")) {
    write (html_to_tree (buf, "text"));
    buf= "";
  }
}

void
texmacs_input_rep::ps_flush (bool force) {
  if (force) {
    tree t (POSTSCRIPT, tuple (tree (RAW_DATA, copy (buf)), "ps"));
    t << "" << "" << "" << "" << "" << "";
    write (t);
    buf= "";
  }
}

void
texmacs_input_rep::ispell_flush (bool force) {
  if (force || ends (buf, "\n\n") || (buf == "\n") ||
      (ends (buf, "\n") && starts (buf, "@(#)")))
    {
      write (verbatim_to_tree (buf));
      buf= "";
    }
}

void
texmacs_input_rep::channel_flush (bool force) {
  if (force) {
    channels[1][0]= buf;
    if (!docs->contains (buf)) docs (buf)= tree (DOCUMENT, "");
    buf= "";
  }
}

void
texmacs_input_rep::command_flush (bool force) {
  if (force) {
    guile_eval ("(begin " * buf * ")");
    buf= "";
  }
}

/******************************************************************************
* User interface
******************************************************************************/

tree
get_texmacs_input (string in, string fm) {
  int i;
  texmacs_input tm_in (fm);
  for (i=0; i<N(in); i++)
    (void) tm_in->put (in[i]);
  tm_in->eof ();
  return tm_in->get ();
}

#endmodule // code_input
