/***** Autogenerated from runhistory.in; changes will be overwritten *****/

#line 1 "./runtimebase.in"
/*****
 * runtimebase.in
 * Andy Hammerlindl  2009/07/28
 *
 * Common declarations needed for all code-generating .in files.
 *
 *****/


#line 1 "./runhistory.in"
/*****
 * runhistory.in
 *
 * Runtime functions for history operations.
 *
 *****/

#line 23 "./runtimebase.in"
#include "stack.h"
#include "types.h"
#include "builtin.h"
#include "entry.h"
#include "errormsg.h"
#include "array.h"
#include "triple.h"
#include "callable.h"
#include "opsymbols.h"

using vm::stack;
using vm::error;
using vm::array;
using vm::read;
using vm::callable;
using types::formal;
using types::function;
using camp::triple;

#define PRIMITIVE(name,Name,asyName) using types::prim##Name;
#include <primitives.h>
#undef PRIMITIVE

void unused(void *);

namespace run {
typedef double real;

array *copyArray(array *a);
array *copyArray2(array *a);
array *copyArray3(array *a);

double *copyTripleArray2Components(array *a, size_t &N,
                                   GCPlacement placement=NoGC);
triple *copyTripleArray2C(array *a, size_t &N,
                          GCPlacement placement=NoGC);
}

function *realRealFunction();

#define CURRENTPEN processData().currentpen

#line 12 "runhistory.in"

#include "array.h"
#include "mathop.h"
#include "builtin.h"

#if defined(_WIN32)
#include <io.h>
#define isatty _isatty
#else
#include <unistd.h>
#endif

using namespace camp;
using namespace settings;
using namespace vm;
using namespace run;

typedef array stringarray;
using types::stringArray;

namespace camp {
bool allowRender=false;
}

#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
#include <readline/readline.h>
#include <readline/history.h>

struct historyState {
  bool store;
  HISTORY_STATE state;
  historyState() : store(false), state() {}
};

typedef mem::map<const string, historyState> historyMap_t;
historyMap_t historyMap;
static HISTORY_STATE history_save;

// Deep-copy entries so each saved state owns independent memory.
// This prevents use-after-free when readline frees the previous
// entries array during history_set_history_state.
static void deep_copy_entries(HISTORY_STATE *dest)
{
  if(dest->length == 0 || !dest->entries) { dest->entries = NULL; return; }
  HIST_ENTRY **ne = new HIST_ENTRY *[dest->length];
  for(int i = 0; i < dest->length; ++i) {
    HIST_ENTRY *e = dest->entries[i];
    if(e) {
      HIST_ENTRY *n = new HIST_ENTRY;
      n->line = e->line ? strdup(e->line) : NULL;
      n->data = e->data;
      ne[i] = n;
    } else
      ne[i] = NULL;
  }
  dest->entries = ne;
}

// Store a deep copy of the current readline history in dest.
void store_history(HISTORY_STATE *dest)
{
  HISTORY_STATE *src=history_get_history_state();
  if(src) {
    *dest=*src;
    deep_copy_entries(dest);
    free(src);
  }
}

// Set the global history to use entries from a saved state,
// without calling history_set_history_state (which would free
// our GC-allocated entries with readline's own free).
static void set_history(const HISTORY_STATE &state)
{
  clear_history();
  for(int i = 0; i < state.length; ++i) {
    HIST_ENTRY *e = state.entries[i];
    if(e && e->line) add_history(e->line);
  }
}

// Write the last nlines entries of a saved history state to filename.
static void write_history_from_state(const HISTORY_STATE &state,
                                     const string &filename, int nlines)
{
  if(state.entries == NULL || state.length == 0) return;
  int start = Max(0, (int)state.length - nlines);
  std::ofstream fout(filename.c_str(), std::ios::trunc);
  for(int i = start; i < (int)state.length; ++i) {
    if(state.entries[i] && state.entries[i]->line)
      fout << state.entries[i]->line << "\n";
  }
}

stringarray* get_history(Int n)
{
  int N=intcast(n);
  if(N <= 0) N=history_length;
  else N=Min(N,history_length);
  array *a=new array((size_t) N);
  int offset=history_length-N+1;
  for(int i=0; i < N; ++i) {
    HIST_ENTRY *last=history_get(offset+i);
    string s=last ? last->line : "";
    (*a)[i]=s;
  }
  return a;
}

string historyfilename(const string &name)
{
  return historyname+"_"+name;
}

#endif

namespace run {

extern string emptystring;

#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)

#endif

void cleanup()
{
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
  store_history(&history_save);
  int nlines=intcast(getSetting<Int>("historylines"));
  for(historyMap_t::iterator h=historyMap.begin(); h != historyMap.end();
      ++h) {
    if(h->second.store)
      write_history_from_state(h->second.state,
                               historyfilename(h->first), nlines);
  }
#endif
#ifdef HAVE_LIBGSL
  trans::GSLrngFree();
#endif
}
}

// Autogenerated routines:



#ifndef NOSYM
#include "runhistory.symbols.h"

#endif
namespace run {
// Return the last n lines of the history named name.
#line 158 "./runhistory.in"
// stringarray* history(string name, Int n=1);
void gen_runhistory0(stack *Stack)
{
  Int n=vm::pop<Int>(Stack,1);
  string name=vm::pop<string>(Stack);
#line 159 "./runhistory.in"
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
  bool newhistory=historyMap.find(name) == historyMap.end();

  string filename;

  if(newhistory) {
    filename=historyfilename(name);
    std::ifstream exists(filename.c_str());
    if(!exists) {Stack->push<stringarray*>(new array(0)); return;}
  }

  store_history(&history_save);
  HISTORY_STATE& history=historyMap[name].state;
  set_history(history);

  if(newhistory)
    read_history(filename.c_str());

  array *a=get_history(n);

  store_history(&history);
  set_history(history_save);

  {Stack->push<stringarray*>(a); return;}
#else
  unused(&n);
  {Stack->push<stringarray*>(new array(0)); return;}
#endif
}

// Return the last n lines of the interactive history.
#line 191 "./runhistory.in"
// stringarray* history(Int n=0);
void gen_runhistory1(stack *Stack)
{
  Int n=vm::pop<Int>(Stack,0);
#line 192 "./runhistory.in"
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
  {Stack->push<stringarray*>(get_history(n)); return;}
#else
  unused(&n);
  {Stack->push<stringarray*>(new array(0)); return;}
#endif
}

// Prompt for a string using prompt, the GNU readline library, and a
// local history named name.
#line 203 "./runhistory.in"
// string readline(string prompt=emptystring, string name=emptystring,                bool tabcompletion=false);
void gen_runhistory2(stack *Stack)
{
  bool tabcompletion=vm::pop<bool>(Stack,false);
  string name=vm::pop<string>(Stack,emptystring);
  string prompt=vm::pop<string>(Stack,emptystring);
#line 205 "./runhistory.in"
  bool stdinIsTty=isatty(STDIN_FILENO);
  bool hasInpipe=getSetting<Int>("inpipe") >= 0;
  if(!(stdinIsTty || hasInpipe))
  {
    {Stack->push<string>(emptystring); return;}
  }
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
  interact::init_readline(tabcompletion);

  store_history(&history_save);
  bool newhistory=historyMap.find(name) == historyMap.end();
  historyState& h=historyMap[name];
  HISTORY_STATE& history=h.state;
  set_history(history);

  if(newhistory)
    read_history(historyfilename(name).c_str());

  static char *line=NULL;
  /* Return the memory to the free pool
     if the buffer has already been allocated. */
  if(line) {
    free(line);
    line=NULL;
  }

  /* Get a line from the user. */
  bool allowRenderSave=allowRender;
  allowRender=false;
  line=readline(prompt.c_str());
  allowRender=allowRenderSave;

  if(!line) cout << endl;

  set_history(history_save);

  {Stack->push<string>(line ? string(line) : emptystring); return;}
#else
  cout << prompt;
  string s;
  getline(cin,s);
  unused(&tabcompletion); // Avoid unused variable warning message.
  {Stack->push<string>(s); return;}
#endif
}

// Save a string in a local history named name.
// If store=true, store the local history in the file historyfilename(name).
#line 254 "./runhistory.in"
// void saveline(string name, string value, bool store=true);
void gen_runhistory3(stack *Stack)
{
  bool store=vm::pop<bool>(Stack,true);
  string value=vm::pop<string>(Stack);
  string name=vm::pop<string>(Stack);
#line 255 "./runhistory.in"
#if defined(HAVE_LIBREADLINE) && defined(HAVE_LIBCURSES)
  store_history(&history_save);
  bool newhistory=historyMap.find(name) == historyMap.end();
  historyState& h=historyMap[name];
  h.store=store;
  HISTORY_STATE& history=h.state;
  set_history(history);

  if(newhistory)
    read_history(historyfilename(name).c_str());

  if(value != "") {
    add_history(value.c_str());
    if(store) {
      std::ofstream hout(historyfilename(name).c_str(),std::ios::app);
      hout << value << endl;
    }
  }

  store_history(&history);
  set_history(history_save);
#else
  unused(&store);
#endif
}

} // namespace run

namespace trans {

void gen_runhistory_venv(venv &ve)
{
#line 157 "./runhistory.in"
  addFunc(ve, run::gen_runhistory0, stringArray(), SYM(history), formal(primString(), SYM(name), false, false), formal(primInt(), SYM(n), true, false));
#line 190 "./runhistory.in"
  addFunc(ve, run::gen_runhistory1, stringArray(), SYM(history), formal(primInt(), SYM(n), true, false));
#line 201 "./runhistory.in"
  addFunc(ve, run::gen_runhistory2, primString(), SYM(readline), formal(primString(), SYM(prompt), true, false), formal(primString(), SYM(name), true, false), formal(primBoolean(), SYM(tabcompletion), true, false));
#line 252 "./runhistory.in"
  addFunc(ve, run::gen_runhistory3, primVoid(), SYM(saveline), formal(primString(), SYM(name), false, false), formal(primString(), SYM(value), false, false), formal(primBoolean(), SYM(store), true, false));
}

} // namespace trans
