
#pragma once

#include "ptytty.h"
#include <sys/errno.h>

typedef int bool;

/*
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
*/

//
// class TtyForkExec  is a way to fork/exec processes which require a tty.
//
// ForkExecxx forks off a child which then execs the requested program.
//
// A TtyForkExec object should only be asked to ForkExec once.
//

class TtyForkExec
{
  bool  have_forked =0;

  PtyTty the_ptytty;

  void  err(char* msg, bool am_child =0);

  void  child(char*name,char*argv[],char*envp[]);

 public:
  ~TtyForkExec () { Close(); };
  Close() { the_ptytty.Close(); };

  int ForkExecv (char*,char*[]);  // returns child_pid, or -1 on failure.
  char *ErrorMessage;             // After a ForkExec failure, describes error.

  bool got_tty();
  int  our_filedescriptor();
  int  tty_filedescriptor();

  int read  (char* buf, int nchars);
  int write (char* buf, int nchars);
};


inline bool TtyForkExec::got_tty()
{
  return the_ptytty.Has_pair();
}

inline int  TtyForkExec::our_filedescriptor()
{
  return the_ptytty.master_pty();
}
inline int  TtyForkExec::tty_filedescriptor()
{
  return the_ptytty.slave_tty();
}

inline int TtyForkExec::read  (char* buf, int nchars)
{
  if(have_forked) return ::read(our_filedescriptor(),buf,nchars);
  else {
    errno = ECHILD;
    return -1;
  }
}
inline int TtyForkExec::write (char* buf, int nchars)
{
  if(have_forked) return ::write(our_filedescriptor(),buf,nchars);
  else {
    errno = ECHILD;
    return -1;
  }
}
