#include "mmix.h"

int select_wait(int fd, int t) {
 struct timeval tv;
 fd_set se;

 FD_ZERO(&se);
 FD_SET(fd,&se);
 tv.tv_sec = 0;
 tv.tv_usec = t;
 return select(fd+1,&se,NULL,NULL,&tv);
}

void mesg(int fd, unsigned char *msg) {
 write(fd,msg,str_len(msg));
}

ssize_t open_trunc(const char *filename) {
 return (ssize_t)open(filename,O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT,0600);
}

ssize_t open_read(const char *filename) {
 return (ssize_t)open(filename,O_RDONLY|O_NDELAY);
}

ssize_t open_append(const char *filename) {
 return (ssize_t)open(filename,O_WRONLY|O_NDELAY|O_APPEND|O_CREAT,0600);
}

size_t open_appendclose(const char *fn, const unsigned char *what) {
 size_t len=0,fd=open_append(fn);
 if (fd<0) return 0;
 len=write(fd, what, str_len(what));
 close(fd);
 return len;
}

off_t get_filesize(int fd) {
 off_t l, c=lseek(fd,0,SEEK_CUR);
 l=lseek(fd,0,SEEK_END);
 lseek(fd,c,SEEK_SET);
 return l;
}

unsigned char *open_readclose(const char *fn, size_t *len, size_t max) {
 ssize_t fd=open_read(fn);
 unsigned char *buf=NULL;
 if (fd<0) goto end; /* mostly ENOENT */
 *len=get_filesize(fd);
 if (*len>max) goto end; /* file to big */
 buf=mallocn(unsigned char, *len+1);
 *len=read(fd, buf, *len);
 if (*len != (size_t)-1) buf[*len]=0;
 else { if (buf) xfree(buf); *buf=0; }
 end:
 close(fd);
 return buf;
}

char *get_user_home(void) {
 struct passwd *pw=getpwuid(getuid());
 return pw->pw_dir?pw->pw_dir:getenv("HOME");
}

bool is_digit(unsigned char ch) {
 return (ch - '0') < 10u;
}

int my_system(const char *line) {
 int pid, ret;
 if (!line) return -1;

 sig_set(SIGINT,  SIG_IGN);
 sig_set(SIGQUIT, SIG_IGN);
 sig_set(SIGTERM, SIG_IGN);
 switch(pid=fork()) {
  case 0:   /* child*/
  {
   const char *nargs[4];
   nargs[0] = "/bin/sh";
   nargs[1] = "-c";
   nargs[2] = line;
   nargs[3] = 0;
   execve("/bin/sh",(char *const *)nargs, environ);
   _exit(127);
  }

  default:  /* parent */
  {
   int n;
   do n=waitpid(pid, &ret, 0);
   while ((n==-1) && (errno==EINTR));
   if (n!=pid) return -1;
  }
 }
 sig_set(SIGINT,  mmix_quit);
 sig_set(SIGQUIT, mmix_quit);
 sig_set(SIGTERM, mmix_quit);
 return ret;
}

bool is_devfs() {
 struct stat st;
 if (stat("/dev/.devfsd", &st)<0) return 0; /* really no devfs */

 /* should be devfsd */
 return 1;
}
