#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#include <signal.h>
#include <limits.h>
#include "myc_str.h"
#include "sys_util.h"

void F_FUN(sys_realpath)(F_CHAR(rpath), int *reslen, F_CHAR(path) F_CLEN(rpath) F_CLEN(path)) {
  char p[PATH_MAX], rp[PATH_MAX], *pt;

  STR_TO_C(p, path);
  pt=realpath(p, rp);
  if (pt==NULL) str_copy(rp, p);
  *reslen=strlen(rp);
  STR_TO_F(rpath, rp);
}

static char *last_line = NULL;

char *readline (char *prompt);
void add_history(const char *line);

void F_FUN(sys_rd_line)(F_CHAR(cmd), int *retlen, F_CHAR(prompt) F_CLEN(cmd) F_CLEN(prompt))
{
  char *line_read;
  char p0[64], p[64];

  STR_TO_C(p0, prompt);
  str_copy(p, "\n");
  str_append(p, p0);
  if (last_line == NULL) { last_line =malloc(1); last_line[0] = '\0';};

  line_read = readline(p);

  if (line_read)
  {  
    if (*line_read && strcmp(last_line, line_read)!=0)
      add_history (line_read);
    free (last_line);
    STR_TO_F(cmd, line_read);
    *retlen=strlen(line_read);
    last_line = line_read;
    if (*retlen>F_LEN(cmd)) *retlen=F_LEN(cmd);
  } else {
    *retlen=-1;
  }
}


void intcatch(int sig)
{ printf("\nuse quit (normally ctrl-\\) to interrupt\n");
}

int called=0; /* env is valid only if called==1 */
jmp_buf env;

void (*inthdl)(int sig)=intcatch;
void (*errhdl)(void);

void sighdl(int sig)
{ if (called) longjmp(env,sig);
}

void F_FUN(sys_err_hdl)(void errhdl0(void))
{ errhdl=errhdl0; }

void F_FUN(sys_int_hdl)(void inthdl0(int sig))
{ inthdl=inthdl0; }

void F_FUN(sys_try)(void proc(void))
{ int status;
  void (*sgh[32]) (int);

  assert(!called); /* nested calls not allowed */
  called=1;
  sgh[SIGFPE] =signal(SIGFPE, sighdl);
  sgh[SIGINT] =signal(SIGINT, *inthdl);
  status=setjmp(env);
  if (status==0) /* first return of setjmp */
  { proc(); }
  else
  { (*errhdl)(); };
  signal(SIGFPE, sgh[SIGFPE]);
  signal(SIGINT, intcatch);
  called=0;
}

void F_FUN(sys_abort)(void)
{ if (called) longjmp(env,-2);
}


void F_FUN(sys_exit_hdl)(void hdl(void))
{ int res;
  res=atexit(hdl);
}
