/* "unix.c" functions only in Unix (unix).
   Copyright (C) 1994 Aubrey Jaffer.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

The author can be reached at jaffer@ai.mit.edu or
Aubrey Jaffer, 84 Pleasant St., Wakefield MA 01880
*/

#include "scm.h"

#include <pwd.h>
#include <sys/types.h>
/* #include <sys/wait.h> */
#include <sys/stat.h>

SCM	scm_stat2scm P((struct stat *stat_temp));

#ifndef STDC_HEADERS
	void sync P((void));
	int symlink P((const char *oldpath, const char *newpath));
	int readlink P((const char *path, char *buf, sizet bufsiz));
	int acct P((const char *filename));
	int nice P((int inc));
#endif /* STDC_HEADERS */

/* Only the superuser can successfully execute mknod and acct */

static char s_mknod[] = "%mknod";
SCM scm_mknod(path, mode, dev)
     SCM path, mode, dev;
{
  int val;
  ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_mknod);
  ASSERT(INUMP(mode), mode, ARG2, s_mknod);
  ASSERT(INUMP(dev), dev, ARG3, s_mknod);
  SYSCALL(val = mknod(CHARS(path), INUM(mode), INUM(dev)));
  return val ? BOOL_F : BOOL_T;
}
static char s_acct[] = "%acct";
SCM scm_acct(path)
     SCM path;
{
  int val;
  if FALSEP(path) {
    SYSCALL(val = acct(0););
    return val ? BOOL_F : BOOL_T;
  }
  ASSERT(NIMP(path) && STRINGP(path), path, ARG1, s_acct);
  SYSCALL(val = acct(CHARS(path)));
  return val ? BOOL_F : BOOL_T;
}

static char s_nice[] = "%nice";
SCM scm_nice(incr)
     SCM incr;
{
  ASSERT(INUMP(incr), incr, ARG1, s_nice);
  return nice(INUM(incr)) ? BOOL_F : BOOL_T;
}

static char s_sync[] = "sync";
SCM scm_sync()
{
  sync();
  return UNSPECIFIED;
}

static char s_symlink[] = "%symlink";
SCM scm_symlink(oldpath, newpath)
     SCM oldpath, newpath;
{
  int val;
  ASSERT(NIMP(oldpath) && STRINGP(oldpath), oldpath, ARG1, s_symlink);
  ASSERT(NIMP(newpath) && STRINGP(newpath), newpath, ARG2, s_symlink);
  SYSCALL(val = symlink(CHARS(oldpath), CHARS(newpath)));
  return val ? BOOL_F : BOOL_T;
}
static char s_readlink[] = "%readlink";
SCM scm_readlink(path)
  SCM path;
{
  sizet rv;
  sizet size = 100;
  char *buf;
  SCM result = BOOL_F;
  ASSERT (NIMP (path) && STRINGP (path),  path, (char *) ARG1, s_readlink);
  DEFER_INTS;
  buf = scm_must_malloc (size, s_readlink);
  while ((rv = readlink (CHARS (path), buf, (sizet) size)) == size)
    {
      scm_must_free (buf);
      size *= 2;
      buf = scm_must_malloc (size, s_readlink);
    }
  if (rv != -1)
    result = scm_makfromstr (buf, rv, 0);
  scm_must_free (buf);
  ALLOW_INTS;
  return result;
}

static char s_lstat[] = "%lstat";
SCM scm_lstat(str)
  SCM str;
{
  int i;
  struct stat stat_temp;
  ASSERT(NIMP(str) && STRINGP(str), str, (char *)ARG1, s_lstat);
  SYSCALL(i = lstat(CHARS(str), &stat_temp));
  return i ? BOOL_F :  scm_stat2scm(&stat_temp);
}

static scm_iproc subr0s[] = {
	{s_sync, scm_sync},
	{0,0}};

static scm_iproc subr1s[] = {
	{s_nice,  scm_nice},
	{s_acct,  scm_acct},
	{s_lstat, scm_lstat},
	{s_readlink, scm_readlink},
	{0,0}};

static scm_iproc subr2s[] = {
	{s_symlink, scm_symlink},
	{0,0}};

static scm_iproc subr3s[] = {
	{s_mknod, scm_mknod},
	{0,0}};

void scm_init_unix ()
{
	scm_init_iprocs (subr0s, tc7_subr_0);
	scm_init_iprocs (subr1s, tc7_subr_1);
	scm_init_iprocs (subr2s, tc7_subr_2);
	scm_init_iprocs (subr3s, tc7_subr_3);
	scm_add_feature ("unix");
}
