diff --git a/library/system.yap b/library/system.yap new file mode 100644 index 000000000..22f9acc10 --- /dev/null +++ b/library/system.yap @@ -0,0 +1,346 @@ +/************************************************************************* +* * +* YAP Prolog * +* * +* Yap Prolog was developed at NCCUP - Universidade do Porto * +* * +* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * +* * +************************************************************************** +* * +* File: system.yap * +* Last rev: * +* mods: * +* comments: Operating System Access built-ins * +* * +*************************************************************************/ + +:- module(system, [ + chmod/2, + datime/1, + delete_file/1, + delete_file/2, + directory_files/2, + environ/2, + exec/3, + file_exists/1, + file_exists/2, + file_property/2, + fmode/2, + host_id/1, + host_name/1, + pid/1, + kill/2, + mktemp/2, + make_directory/1, + popen/3, + rename_file/2, + shell/1, + shell/2, + sleep/1, + system/1, + system/2, + time/1, + tmpnam/1, + wait/2, + working_directory/2 + ]). + +:- load_foreign_files([sys], [], init_sys). + +% time builtins + +datime(X) :- + datime(X, Error), + handle_system_error(Error, off, datime(X)). + +% file operations + +delete_file(File) :- + delete_file(File, off, on, off). + +delete_file(File, Opts) :- + process_delete_file_opts(Opts, Dir, Recurse, Ignore, delete_file(File,Opts)), + delete_file(File, Dir, Recurse, Ignore). + +process_delete_file_opts(V, _, _, _, T) :- var(V), !, + throw(error(instantiation_error,T)). +process_delete_file_opts([], off, off, off, _) :- !. +process_delete_file_opts([V|_], _, _, _, T) :- var(V), !, + throw(error(instantiation_error,T)). +process_delete_file_opts([directory|Opts], on, Recurse, Ignore, T) :- !, + process_delete_file_opts(Opts, _, Recurse, Ignore, T). +process_delete_file_opts([recursive|Opts], Dir, on, Ignore, T) :- !, + process_delete_file_opts(Opts, Dir, _, Ignore, T). +process_delete_file_opts([ignore|Opts], Dir, Recurse, on, T) :- !, + process_delete_file_opts(Opts, Dir, Recurse, _, T). +process_delete_file_opts(Opts, _, _, _, T) :- + throw(error(domain_error(delete_file_option,Opts),T)). + +delete_file(File, Dir, Recurse, Ignore) :- + file_property(File, Type, _, _, _Permissions, Ignore), + delete_file(Type, File, Dir, Recurse, Ignore). + +delete_file(N, File, Dir, Recurse, Ignore) :- number(N), !, % error. + handle_system_error(N, Ignore, delete_file(File)). +delete_file(directory, File, Dir, Recurse, Ignore) :- + delete_directory(Dir, File, Recurse, Ignore). +delete_file(_, File, Dir, Recurse, Ignore) :- + unlink_file(File, Ignore). + +unlink_file(File, Ignore) :- + unlink(File, N), + handle_system_error(N, Ignore, delete_file(File)). + +delete_directory(on, File, Recurse, Ignore) :- + rm_directory(File, Ignore). +delete_directory(off, File, Recurse, Ignore) :- + delete_directory(Recurse, File, Ignore). + +rm_directory(File, Ignore) :- + rmdir(File, Error), + handle_system_error(Error, Ignore, delete_file(File)). + +delete_directory(on, File, Ignore) :- + directory_files(File, FileList, Ignore), + dir_separator(D), + atom_concat(File, D, FileP), + delete_dirfiles(FileList, FileP, Ignore), + rmdir(File, Ignore). + +delete_dirfiles([], _, _). +delete_dirfiles(['.'|Fs], File, Ignore) :- !. +delete_dirfiles(['..'|Fs], File, Ignore) :- !. +delete_dirfiles([F|Fs], File, Ignore) :- + atom_concat(File,F,TrueF), + delete_file(TrueF, off, on, Ignore), + delete_dirfiles(Fs, File, Ignore). + +directory_files(File, FileList) :- + directory_files(File, FileList, off). + +directory_files(File, FileList, Ignore) :- + list_directory(File, FileList, Error), + handle_system_error(Error, Ignore, directory_files(File, FileList)). + +handle_system_error(Error, Ignore, G) :- var(Error), !. +handle_system_error(Error, off, G) :- + error_message(Error, Message), + throw(error(system_error(Message),G)). + +file_property(File, type(Type)) :- + file_property(File, Type, _Size, _Date). +file_property(File, size(Size)) :- + file_property(File, _Type, Size, _Date). +file_property(File, mod_time(Date)) :- + file_property(File, _Type, _Size, Date). + +file_property(File, Type, Size, Date) :- + file_property(File, Type, Size, Date, Permissions, Error), + handle_system_error(Error, off, file_property(File)). + +file_exists(File) :- + file_property(File, _Type, _Size, _Date, _Permissions, Error), + var(Error). + +file_exists(File, Permissions) :- + file_property(File, _Type, _Size, _Date, FPermissions, Error), + var(Error), + process_permissions(Permissions, Perms), + FPermissions /\ Perms =:= Perms. + +process_permissions(Number, Number) :- integer(Number). + +make_directory(Dir) :- + var(Dir), !, + throw(error(instantiation_error,mkdir(Dir))). +make_directory(Dir) :- + atom(Dir), !, + mkdir(Dir,Err), + handle_system_error(Error, off, mkdir(Dir)). +make_directory(Dir) :- + throw(error(type_error(atom,X),make_directory(Dir))). + +rename_file(Old, New) :- + atom(Old), atom(New), !, + rename_file(Old, New, Error), + handle_system_error(Error, off, rename_file(Old, New)). +rename_file(X,Y) :- (var(X) ; var(Y)), !, + throw(error(instantiation_error,rename_file(X,Y))). +rename_file(X,Y) :- atom(X), !, + throw(error(type_error(atom,Y),rename_file(X,Y))). +rename_file(X,Y) :- + throw(error(type_error(atom,X),rename_file(X,Y))). + +% +% environment manipulation. +% + +environ(Na,Val) :- var(Na), !, + environ_enum(0,I), + ( p_environ(I,S) -> environ_split(S,SNa,SVal) ; !, fail ), + atom_codes(Na, SNa), + atom_codes(Val, SVal). +environ(Na,Val) :- atom(Na), !, + bound_environ(Na, Val). +environ(Na,Val) :- + throw(type_error(atom,Na),environ(Na,Val)). + +bound_environ(Na, Val) :- var(Val), !, + getenv(Na,Val). +bound_environ(Na, Val) :- atom(Val), !, + putenv(Na,Val). +bound_environ(Na, Val) :- + throw(type_error(atom,Val),environ(Na,Val)). + +environ_enum(X,X). +environ_enum(X,X1) :- + Xi is X+1, + environ_enum(Xi,X1). + +environ_split([61|SVal], [], SVal) :- !. +environ_split([C|S],[C|SNa],SVal) :- + environ_split(S,SNa,SVal). + +working_directory(OLD, NEW) :- + getcwd(OLD), + cd(NEW). + +% +% process execution +% +exec(Command, [StdIn, StdOut, StdErr], PID) :- + G = exec(Command, [StdIn, StdOut, StdErr], PID), + check_command(Command, G), + process_inp_stream_for_exec(StdIn, In, G), + process_out_stream_for_exec(StdOut, Out, G), + process_err_stream_for_exec(StdErr, Err, G), + ( exec_command(Command, In, Out, Err, PID, Error) -> true ; true ), + close_temp_streams(StdIn, In, StdOut, Out, StdErr, Err), + handle_system_error(Error, off, G). + +process_inp_stream_for_exec(Error, _, G) :- var(Error), !, + throw(error(instantiation_error,G)). +process_inp_stream_for_exec(null, 0, _) :- !. +process_inp_stream_for_exec(std, '$stream'(0), _) :- !. +process_inp_stream_for_exec(pipe(SOut), SInp, _) :- !, + open_pipe_streams(SInp, SOut). +process_inp_stream_for_exec(Stream, Stream, _) :- + stream_property(Stream, input). + + +process_out_stream_for_exec(Error, _, G) :- var(Error), !, + throw(error(instantiation_error,G)). +process_out_stream_for_exec(null, 0, _) :- !. +process_out_stream_for_exec(std, '$stream'(1), _) :- !. +process_out_stream_for_exec(pipe(SInp), SOut, _) :- !, + open_pipe_streams(SInp, SOut). +process_out_stream_for_exec(Stream, Stream, _) :- + stream_property(Stream, output). + +process_err_stream_for_exec(Error, _, G) :- var(Error), !, + throw(error(instantiation_error,G)). +process_err_stream_for_exec(null, 0, _) :- !. +process_err_stream_for_exec(std, '$stream'(2), _) :- !. +process_err_stream_for_exec(pipe(SInp), SOut, _) :- !, + open_pipe_streams(SInp, SOut). +process_err_stream_for_exec(Stream, Stream, _) :- + stream_property(Stream, output). + +close_temp_streams(pipe(_), S, _, _, _, _) :- close(S), fail. +close_temp_streams(_, _, pipe(_), S, _, _) :- close(S), fail. +close_temp_streams(_, _, _, _, pipe(_), S) :- close(S), fail. +close_temp_streams(_, _, _, _, _, _). + + +popen(Command, Mode, Stream) :- + G = popen(Command, Mode, Stream), + check_command(Command, G), + check_mode(Mode, M, G), + popen(Command, M, Stream, Result), + handle_system_error(Error, off, G). + +check_command(Com, G) :- var(Com), !, + throw(error(instantiation_error,G)). +check_command(Com, G) :- atom(Com), !. +check_command(Com, G) :- + throw(type_error(atom,Com),G). + +check_mode(Mode, _, G) :- var(G), !, + throw(error(instantiation_error,G)). +check_mode(read, 0, _) :- !. +check_mode(write,1, _) :- !. +check_mode(Mode, G) :- + throw(domain_error(io_mode,Mode),G). + +shell(Command, Status) :- + G = shell(Command, Status), + check_command(Command, G), + do_shell(Status, Error), + ( var(Error) -> Status = 0 ; Status = Error). + +system(Command, Status) :- + G = system(Command, Status), + check_command(Command, G), + do_system(Status, Status). + +sleep(Interval) :- var(Interval), !, + throw(error(instantiation_error,sleep(Interval))). +sleep(Interval) :- number(Interval), !, + ( Interval =< 0 -> + throw(error(domain_error(not_less_than_zero,Interval), + sleep(Interval))) + ; + sleep(Interval, _Remainder) + ). +sleep(Interval) :- + throw(error(type_error(number,Interval),sleep(Interval))). + +wait(PID,STATUS) :- var(PID), !, + throw(error(instantiation_error,wait(PID,STATUS))). +wait(PID,STATUS) :- integer(PID), !, + wait(PID, STATUS, Error), + handle_system_error(Error, off, wait(PID,STATUS)). +wait(PID,STATUS) :- + throw(error(type_error(integer,PID),wait(PID,STATUS))). + +% +% host info +% +host_name(X) :- + host_name(X, Error), + handle_system_error(Error, off, host_name(X)). + +host_id(X) :- + host_id(X0, Error), + handle_system_error(Error, off, host_id(X)), + number_codes(X0, S), + atom_codes(X, S). + +pid(X) :- + pid(X, Error), + handle_system_error(Error, off, pid(X)). + +kill(X,Y) :- + integer(X), integer(Y), !, + kill(X, Y, Error), + handle_system_error(Error, off, kill(X,Y)). +kill(X,Y) :- (var(X) ; var(Y)), !, + throw(error(instantiation_error,kill(X,Y))). +kill(X,Y) :- integer(X), !, + throw(error(type_error(integer,Y),kill(X,Y))). +kill(X,Y) :- + throw(error(type_error(integer,X),kill(X,Y))). + +mktemp(X,Y) :- var(X), !, + throw(error(instantiation_error,mktemp(X,Y))). +mktemp(X,Y) :- + atom(X), !, + mktemp(X, Y, Error), + handle_system_error(Error, off, mktemp(X,Y)). +mktemp(X,Y) :- + throw(error(type_error(atom,X),mktemp(X,Y))). + +tmpnam(X) :- + tmpnam(X, Error), + handle_system_error(Error, off, tmpnam(X)). diff --git a/library/system/Makefile.in b/library/system/Makefile.in new file mode 100644 index 000000000..7d310e3b4 --- /dev/null +++ b/library/system/Makefile.in @@ -0,0 +1,88 @@ +# +# default base directory for YAP installation +# +ROOTDIR = @prefix@ +# +# where the binary should be +# +BINDIR = $(ROOTDIR)/bin +# +# where YAP should look for libraries +# +LIBDIR=$(ROOTDIR)/lib/Yap +# +# +CC=@CC@ +CFLAGS= @CFLAGS@ $(YAP_EXTRAS) $(DEFS) -I$(srcdir) -I../.. -I$(srcdir)/../../include +# +# +# You shouldn't need to change what follows. +# +INSTALL=@INSTALL@ +INSTALL_DATA=@INSTALL_DATA@ +INSTALL_PROGRAM=@INSTALL_PROGRAM@ +SHELL=/bin/sh +RANLIB=@RANLIB@ +srcdir=@srcdir@ +SHLIB_CFLAGS=@SHLIB_CFLAGS@ +SHLIB_SUFFIX=@SHLIB_SUFFIX@ +#4.1VPATH=@srcdir@:@srcdir@/OPTYap +CWD=$(PWD) +# + +OBJS=sys.o +SOBJS=sys@SHLIB_SUFFIX@ + +#in some systems we just create a single object, in others we need to +# create a libray + +all: @NEWSHOBJ@ + +sobjs: $(SOBJS) + +dll: sys@SHLIB_SUFFIX@ + +sys.o: $(srcdir)/sys.c + $(CC) -c $(CFLAGS) $(SHLIB_CFLAGS) $(srcdir)/sys.c -o sys.o + +%.so: %.o + @SHLIB_LD@ -o $@ $< + +sys.so: sys.o + @SHLIB_LD@ -o sys.so sys.o + +# +# create a new DLL library on cygwin environments +# +# DLLNAME: name of the new dll +# OBJS: list of object files I want to put in +# LIBS: list of libraries to link with +# DEFFILE is the name of the definitions file. +# BASEFILE temporary +# EXPFILE temporary +# ENTRY is the entry point int WINAPI startup (HINSTANCE, DWORD, LPVOID) +# +DLLTOOL=dlltool +DLLNAME=sys.dll +DLL_LIBS=-lcrtdll -L../.. -lWYap +BASE_FILE=sys.base +EXP_FILE=sys.exp +DEF_FILE=$(srcdir)/sys.def +ENTRY_FUNCTION=_win_sys@12 +# +sys.dll: $(OBJS) + $(LD) -s --base-file $(BASE_FILE) --dll -o $(DLLNAME) $(OBJS) $(DLL_LIBS) -e $(ENTRY_FUNCTION) + $(DLLTOOL) --as=$(AS) --dllname $(DLLNAME) --def $(DEF_FILE) --base-file $(BASE_FILE) --output-exp $(EXP_FILE) + $(LD) -s --base-file $(BASE_FILE) $(EXP_FILE) -dll -o $(DLLNAME) $(OBJS) $(DLL_LIBS) -e $(ENTRY_FUNCTION) + $(DLLTOOL) --as=$(AS) --dllname $(DLLNAME) --def $(DEF_FILE) --base-file $(BASE_FILE) --output-exp $(EXP_FILE) + $(LD) $(EXP_FILE) --dll -o $(DLLNAME) $(OBJS) $(DLL_LIBS) -e $(ENTRY_FUNCTION) + +install: all + $(INSTALL_PROGRAM) $(SOBJS) $(DESTDIR)$(LIBDIR) + +install_mingw32: dll + $(INSTALL_PROGRAM) -m 755 sys.dll $(LIBDIR)/sys.dll + +clean: + rm -f *.o *.so *~ $(OBJS) *.BAK + diff --git a/library/system/sys.c b/library/system/sys.c new file mode 100644 index 000000000..8854048ec --- /dev/null +++ b/library/system/sys.c @@ -0,0 +1,581 @@ +/************************************************************************* +* * +* YAP Prolog * +* * +* Yap Prolog was developed at NCCUP - Universidade do Porto * +* * +* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 * +* * +************************************************************************** +* * +* File: regexp.c * +* Last rev: * +* mods: * +* comments: regular expression interpreter * +* * +*************************************************************************/ + +#include "config.h" +#include "c_interface.h" +#if STDC_HEADERS +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#if HAVE_TIME_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_STRING_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif +#if HAVE_SYS_WAIT_H +#include +#endif +#if HAVE_DIRENT_H +#include +#endif + +#ifdef __MINGW32__ +#ifdef HAVE_ENVIRON +#undef HAVE_ENVIRON +#endif +#endif + +void PROTO(init_sys, (void)); + +/* Return time in a structure */ +static int +datime(void) +{ + Term tf, out[6]; +#ifdef HAVE_TIME + time_t tp; + + if ((tp = time(NULL)) == -1) { + return(unify(ARG2, MkIntTerm(errno))); + } +#ifdef HAVE_LOCALTIME + { + struct tm *loc = localtime(&tp); + if (loc == NULL) { + return(unify(ARG2, MkIntTerm(errno))); + } + out[0] = MkIntTerm(loc->tm_year); + out[1] = MkIntTerm(loc->tm_mon); + out[2] = MkIntTerm(loc->tm_mday); + out[3] = MkIntTerm(loc->tm_hour); + out[4] = MkIntTerm(loc->tm_min); + out[5] = MkIntTerm(loc->tm_sec); + } +#else + oops +#endif /* HAVE_LOCALTIME */ +#else + oops +#endif /* HAVE_TIME */ + tf = MkApplTerm(MkFunctor(LookupAtom("datime"),6), 6, out); + return(unify(ARG1, tf)); +} + +#define BUF_SIZE 1024 + +/* Return a list of files for a directory */ +static int +list_directory(void) +{ + Term tf = MkAtomTerm(LookupAtom("[]")); + + char *buf = AtomName(AtomOfTerm(ARG1)); +#if HAVE_OPENDIR + { + DIR *de; + struct dirent *dp; + + if ((de = opendir(buf)) == NULL) { + return(unify(ARG3, MkIntTerm(errno))); + } + while ((dp = readdir(de))) { + Term ti = MkAtomTerm(LookupAtom(dp->d_name)); + tf = MkPairTerm(ti, tf); + } + closedir(de); + } +#endif /* HAVE_OPENDIR */ + return(unify(ARG2, tf)); +} + +static int +p_unlink(void) +{ + char *fd = AtomName(AtomOfTerm(ARG1)); + if (unlink(fd) == -1) { + /* return an error number */ + return(unify(ARG2, MkIntTerm(errno))); + } + return(TRUE); +} + +static int +p_mkdir(void) +{ + char *fd = AtomName(AtomOfTerm(ARG1)); + if (mkdir(fd, 0777) == -1) { + /* return an error number */ + return(unify(ARG2, MkIntTerm(errno))); + } + return(TRUE); +} + +static int +p_rmdir(void) +{ + char *fd = AtomName(AtomOfTerm(ARG1)); + if (rmdir(fd) == -1) { + /* return an error number */ + return(unify(ARG2, MkIntTerm(errno))); + } + return(TRUE); +} + +static int +rename_file(void) +{ + char *s1 = AtomName(AtomOfTerm(ARG1)); + char *s2 = AtomName(AtomOfTerm(ARG2)); +#if HAVE_RENAME + if (rename(s1, s2) == -1) { + /* return an error number */ + return(unify(ARG3, MkIntTerm(errno))); + } +#endif + return(TRUE); +} + +static int +dir_separator(void) +{ + return(unify(ARG1,MkAtomTerm(LookupAtom("/")))); +} + +static int +file_property(void) +{ + char *fd; +#if HAVE_LSTAT + struct stat buf; + + fd = AtomName(AtomOfTerm(ARG1)); + if (lstat(fd, &buf) == -1) { + /* return an error number */ + return(unify(ARG6, MkIntTerm(errno))); + } + if (S_ISREG(buf.st_mode)) + unify(ARG2, MkAtomTerm(LookupAtom("regular"))); + else if (S_ISDIR(buf.st_mode)) + unify(ARG2, MkAtomTerm(LookupAtom("directory"))); + else if (S_ISFIFO(buf.st_mode)) + unify(ARG2, MkAtomTerm(LookupAtom("fifo"))); + else if (S_ISLNK(buf.st_mode)) + unify(ARG2, MkAtomTerm(LookupAtom("symlink"))); + else if (S_ISSOCK(buf.st_mode)) + unify(ARG2, MkAtomTerm(LookupAtom("socket"))); + else + unify(ARG2, MkAtomTerm(LookupAtom("unknown"))); + unify(ARG3, MkIntTerm(buf.st_size)); + unify(ARG4, MkIntTerm(buf.st_mtime)); + unify(ARG5, MkIntTerm(buf.st_mode)); +#endif + return(TRUE); +} + +/* temporary files */ + +static int +p_mktemp(void) +{ +#if HAVE_MKTEMP + char *s, tmp[1024]; + s = AtomName(AtomOfTerm(ARG1)); +#if HAVE_STRNCPY + strncpy(tmp, s, 1024); +#else + strcpy(tmp, s); +#endif + if ((s = mktemp(tmp)) == NULL) { + /* return an error number */ + return(unify(ARG3, MkIntTerm(errno))); + } + return(unify(ARG2,MkAtomTerm(LookupAtom(s)))); +#else + oops +#endif + return(TRUE); +} + +static int +p_tpmnam(void) +{ +#if HAVE_TMPNAM + return(unify(ARG1,MkAtomTerm(LookupAtom(tmpnam(NULL))))); +#else +oops +#endif +} + +/* return YAP's environment */ +static int +p_environ(void) +{ +#if HAVE_ENVIRON + extern char **environ; + Term t1 = ARG1; + Int i; + + i = IntOfTerm(t1); + if (environ[i] == NULL) + return(FALSE); + else { + Term t = BufferToString(environ[i]); + return(unify(t, ARG2)); + } +#else + YapError("environ not available in this configuration"); + return(FALSE); +#endif +} + +/* execute a command as a detached process */ +static int +execute_command(void) +{ + Term ti = ARG2, to = ARG3, te = ARG4; + Term tzero = MkIntTerm(0); + int res; + int inpf, outf, errf; + /* process input first */ + if (ti == tzero) { + inpf = open("/dev/null", O_RDONLY); + } else { + int sd = YapStreamToFileNo(ti); + inpf = dup(sd); + } + if (inpf < 0) { + /* return an error number */ + return(unify(ARG6, MkIntTerm(errno))); + } + /* then output stream */ + if (to == tzero) { + outf = open("/dev/zero", O_WRONLY); + } else { + int sd = YapStreamToFileNo(to); + outf = dup(sd); + } + if (outf < 0) { + /* return an error number */ + return(unify(ARG6, MkIntTerm(errno))); + } + /* then error stream */ + if (te == tzero) { + errf = open("/dev/zero", O_WRONLY); + } else { + int sd = YapStreamToFileNo(te); + errf = dup(sd); + } + if (errf < 0) { + /* return an error number */ + return(unify(ARG6, MkIntTerm(errno))); + } + /* we are now ready to fork */ + if ((res = fork()) < 0) { + /* close streams we don't need */ + close(inpf); + close(outf); + close(errf); + /* return an error number */ + return(unify(ARG6, MkIntTerm(errno))); + } else if (res == 0) { + char *argv[4]; + + /* child */ + /* close current streams, but not std streams */ + YapCloseAllOpenStreams(); + close(0); + dup(inpf); + close(1); + dup(outf); + close(2); + dup(outf); + close(inpf); + close(outf); + close(errf); + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = AtomName(AtomOfTerm(ARG1)); + argv[3] = NULL; + execv("/bin/sh", argv); + exit(127); + /* we have the streams where we want them, just want to execute now */ + } else { + close(inpf); + close(outf); + close(errf); + return(unify(ARG5,MkIntTerm(res))); + } +} + +/* execute a command as a detached process */ +static int +shell(void) +{ + char *command = AtomName(AtomOfTerm(ARG1)); + int pid; + /* we are now ready to fork */ + if ((pid = fork()) < 0) { + /* return an error number */ + return(unify(ARG2, MkIntTerm(errno))); + } else if (pid == 0) { + char *argv[4]; + char *shell; + + /* child */ + /* close current streams, but not std streams */ + YapCloseAllOpenStreams(); +#if HAVE_GETENV + shell = getenv ("SHELL"); + if (shell == NULL) + shell = "/bin/sh"; +#endif + argv[0] = shell; + argv[1] = "-c"; + argv[2] = command; + argv[3] = NULL; + execv("/bin/sh", argv); + exit(127); + /* we have the streams where we want them, just want to execute now */ + } else { + do { + int status; + + /* check for interruptions */ + if (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) + return -1; + return(unify(ARG2, MkIntTerm(errno))); + } else + return(TRUE); + } while(TRUE); + } +} + +/* execute a command as a detached process */ +static int +p_system(void) +{ + char *command = AtomName(AtomOfTerm(ARG1)); + int sys = system(command); +#if HAVE_SYSTEM + return(unify(ARG2, MkIntTerm(sys))); +#endif +} + +/* execute a command as a detached process */ +static int +p_wait(void) +{ + Int pid = IntOfTerm(ARG1); + do { + int status; + + /* check for interruptions */ + if (waitpid(pid, &status, 0) == -1) { + if (errno != EINTR) + return -1; + return(unify(ARG3, MkIntTerm(errno))); + } else { + return(unify(ARG2, MkIntTerm(status))); + } + } while(TRUE); +} + +/* execute a command as a detached process */ +static int +p_popen(void) +{ + char *command = AtomName(AtomOfTerm(ARG1)); + Int mode = IntOfTerm(ARG2); + FILE *pfd; + Term tsno; + int flags; + +#if HAVE_POPEN + if (mode == 0) + pfd = popen(command, "r"); + else + pfd = popen(command, "w"); + if (pfd == NULL) { + return(unify(ARG4, MkIntTerm(errno))); + } + if (mode == 0) + flags = YAP_INPUT_STREAM | YAP_POPEN_STREAM; + else + flags = YAP_OUTPUT_STREAM | YAP_POPEN_STREAM; + tsno = YapOpenStream((void *)pfd, + "pipe", + MkAtomTerm(LookupAtom("pipe")), + flags); +#endif + return(unify(ARG3, tsno)); +} + +static int +p_sleep(void) +{ + Term ts = ARG1; + Int secs = 0, usecs = 0, out; + if (IsIntTerm(ts)) { + secs = IntOfTerm(ts); + } else if (IsFloatTerm(ts)) { + flt tfl = FloatOfTerm(ts); + if (tfl > 1.0) + secs = tfl; + else + usecs = tfl*1000; + } +#if HAVE_USLEEP + if (usecs > 0) { + usleep(usecs); + out = 0; + } else +#endif +#if HAVE_SLEEP + { + out = sleep(secs); + } +#endif + return(unify(ARG2, MkIntTerm(out))); +} + +/* host info */ + +static int +host_name(void) +{ + char name[256]; +#if HAVE_GETHOSTNAME + if (gethostname(name, 256) == -1) { + /* return an error number */ + return(unify(ARG2, MkIntTerm(errno))); + } +#endif + return(unify(ARG1, MkAtomTerm(LookupAtom(name)))); +} + +static int +host_id(void) +{ +#if HAVE_GETHOSTID + return(unify(ARG1, MkIntTerm(gethostid()))); +#endif +} + +static int +pid(void) +{ + return(unify(ARG1, MkIntTerm(getpid()))); +} + +static int +p_kill(void) +{ +#if HAVE_KILL + if (kill(IntOfTerm(ARG1), IntOfTerm(ARG2)) < 0) { + /* return an error number */ + return(unify(ARG2, MkIntTerm(errno))); + } +#else + oops +#endif + return(TRUE); +} + +static int +error_message(void) +{ +#if HAVE_STRERROR + return(unify(ARG2,MkAtomTerm(LookupAtom(strerror(IntOfTerm(ARG1)))))); +#else +#if HAVE_STRERROR + return(unify(ARG2,ARG1)); +#endif +#endif +} + +void +init_sys(void) +{ + UserCPredicate("datime", datime, 2); + UserCPredicate("list_directory", list_directory, 3); + UserCPredicate("file_property", file_property, 6); + UserCPredicate("unlink", p_unlink, 2); + UserCPredicate("mkdir", p_mkdir, 2); + UserCPredicate("rmdir", p_rmdir, 2); + UserCPredicate("dir_separator", dir_separator, 1); + UserCPredicate("p_environ", p_environ, 2); + UserCPredicate("exec_command", execute_command, 6); + UserCPredicate("do_shell", shell, 2); + UserCPredicate("do_system", p_system, 2); + UserCPredicate("popen", p_popen, 4); + UserCPredicate("wait", p_wait, 3); + UserCPredicate("host_name", host_name, 2); + UserCPredicate("host_id", host_id, 2); + UserCPredicate("pid", pid, 2); + UserCPredicate("kill", p_kill, 3); + UserCPredicate("mktemp", p_mktemp, 3); + UserCPredicate("tmpnam", p_tpmnam, 2); + UserCPredicate("rename_file", rename_file, 3); + UserCPredicate("sleep", p_sleep, 2); + UserCPredicate("error_message", error_message, 2); +} + +#ifdef _WIN32 + +#include + +int WINAPI PROTO(win_system, (HANDLE, DWORD, LPVOID)); + +int WINAPI win_system(HANDLE hinst, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + break; + case DLL_PROCESS_DETACH: + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + } +p return 1; +} +#endif