Merge branch 'master' of github.com:vscosta/yap-6.3
This commit is contained in:
213
os/iopreds.c
213
os/iopreds.c
@@ -18,9 +18,16 @@
|
||||
static char SccsId[] = "%W% %G%";
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file iopreds.c
|
||||
* @author VITOR SANTOS COSTA <vsc@VITORs-MBP.lan>
|
||||
* @date Wed Jan 20 00:45:56 2016
|
||||
*
|
||||
* @brief main open and close predicates over generic streams.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* This file includes the definition of a miscellania of standard predicates
|
||||
* for yap refering to: Files and GLOBAL_Streams, Simple Input/Output,
|
||||
* This file includes the definition of a miscellania of standard predicates * for yap refering to: Files and GLOBAL_Streams, Simple Input/Output,
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -170,10 +177,10 @@ static void unix_upd_stream_info(StreamDesc *s) {
|
||||
Yap_socketStream(s);
|
||||
#if _MSC_VER || defined(__MINGW32__)
|
||||
{
|
||||
if (_isatty(_fileno(s->u.file.file))) {
|
||||
if (_isatty(_fileno(s->file))) {
|
||||
s->status |= Tty_Stream_f | Reset_Eof_Stream_f | Promptable_Stream_f;
|
||||
/* make all console descriptors unbuffered */
|
||||
setvbuf(s->u.file.file, NULL, _IONBF, 0);
|
||||
setvbuf(s->file, NULL, _IONBF, 0);
|
||||
return;
|
||||
}
|
||||
#if _MSC_VER
|
||||
@@ -1009,11 +1016,7 @@ Int GetStreamFd(int sno) {
|
||||
} else
|
||||
#endif
|
||||
if (GLOBAL_Stream[sno].status & Pipe_Stream_f) {
|
||||
#if _MSC_VER || defined(__MINGW32__)
|
||||
return ((Int)(GLOBAL_Stream[sno].u.pipe.hdl));
|
||||
#else
|
||||
return (GLOBAL_Stream[sno].u.pipe.fd);
|
||||
#endif
|
||||
} else if (GLOBAL_Stream[sno].status & InMemory_Stream_f) {
|
||||
return (-1);
|
||||
}
|
||||
@@ -1022,7 +1025,7 @@ Int GetStreamFd(int sno) {
|
||||
|
||||
Int Yap_GetStreamFd(int sno) { return GetStreamFd(sno); }
|
||||
|
||||
static int binary_file(char *file_name) {
|
||||
static int binary_file(const char *file_name) {
|
||||
#if HAVE_STAT
|
||||
#if _MSC_VER || defined(__MINGW32__)
|
||||
struct _stat ss;
|
||||
@@ -1229,20 +1232,52 @@ static void check_bom(int sno, StreamDesc *st) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
open_header( int sno, Atom open_mode)
|
||||
{
|
||||
if (open_mode == AtomWrite) {
|
||||
const char *ptr;
|
||||
const char s[] = "#!";
|
||||
int ch;
|
||||
|
||||
ptr = s;
|
||||
while ((ch = *ptr++))
|
||||
GLOBAL_Stream[sno].stream_wputc( sno, ch );
|
||||
const char *b = Yap_FindExecutable();
|
||||
ptr = b;
|
||||
while ((ch = *ptr++))
|
||||
GLOBAL_Stream[sno].stream_wputc( sno, ch );
|
||||
const char *l = " -L --\n\n YAP script\n#\n# .\n";
|
||||
ptr = l;
|
||||
while ((ch = *ptr++))
|
||||
GLOBAL_Stream[sno].stream_wputc( sno, ch );
|
||||
|
||||
} else if (open_mode == AtomRead) {
|
||||
// skip header
|
||||
int ch;
|
||||
while ((ch =Yap_peek(sno)) == '#' ) {
|
||||
while ((ch = GLOBAL_Stream[sno].stream_wgetc( sno )) != 10 && ch != -1 );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define OPEN_DEFS() \
|
||||
PAR("alias", isatom, OPEN_ALIAS), PAR("bom", boolean, OPEN_BOM), \
|
||||
PAR("alias", isatom, OPEN_ALIAS), PAR("bom", booleanFlag, OPEN_BOM), \
|
||||
PAR("buffer", isatom, OPEN_BUFFER), \
|
||||
PAR("close_on_abort", boolean, OPEN_CLOSE_ON_ABORT), \
|
||||
PAR("close_on_abort", booleanFlag, OPEN_CLOSE_ON_ABORT), \
|
||||
PAR("create", isatom, OPEN_CREATE), \
|
||||
PAR("encoding", isatom, OPEN_ENCODING), \
|
||||
PAR("eof_action", isatom, OPEN_EOF_ACTION), \
|
||||
PAR("expand_filename", boolean, OPEN_EXPAND_FILENAME), \
|
||||
PAR("expand_filename", booleanFlag, OPEN_EXPAND_FILENAME), \
|
||||
PAR("file_name", isatom, OPEN_FILE_NAME), PAR("input", ok, OPEN_INPUT), \
|
||||
PAR("locale", isatom, OPEN_LOCALE), PAR("lock", isatom, OPEN_LOCK), \
|
||||
PAR("mode", isatom, OPEN_MODE), PAR("output", ok, OPEN_OUTPUT), \
|
||||
PAR("representation_errors", boolean, OPEN_REPRESENTATION_ERRORS), \
|
||||
PAR("reposition", boolean, OPEN_REPOSITION), \
|
||||
PAR("type", isatom, OPEN_TYPE), PAR("wait", boolean, OPEN_WAIT), \
|
||||
PAR("representation_errors", booleanFlag, OPEN_REPRESENTATION_ERRORS), \
|
||||
PAR("reposition", booleanFlag, OPEN_REPOSITION), \
|
||||
PAR("script", booleanFlag, OPEN_SCRIPT), \
|
||||
PAR("type", isatom, OPEN_TYPE), PAR("wait", booleanFlag, OPEN_WAIT), \
|
||||
PAR(NULL, ok, OPEN_END)
|
||||
|
||||
#define PAR(x, y, z) z
|
||||
@@ -1267,7 +1302,7 @@ do_open(Term file_name, Term t2,
|
||||
char io_mode[8];
|
||||
StreamDesc *st;
|
||||
bool avoid_bom = false, needs_bom = false;
|
||||
char *fname;
|
||||
const char *fname;
|
||||
stream_flags_t flags;
|
||||
FILE *fd;
|
||||
encoding_t encoding;
|
||||
@@ -1352,6 +1387,10 @@ do_open(Term file_name, Term t2,
|
||||
fname = Yap_AbsoluteFile(fname, LOCAL_FileNameBuf, ok);
|
||||
st->name = Yap_LookupAtom(fname);
|
||||
|
||||
// Skip scripts that start with !#/.. or similar
|
||||
bool script = (args[OPEN_SCRIPT].used
|
||||
? args[OPEN_SCRIPT].tvalue == TermTrue
|
||||
: false);
|
||||
// binary type
|
||||
if (args[OPEN_TYPE].used) {
|
||||
Term t = args[OPEN_TYPE].tvalue;
|
||||
@@ -1395,7 +1434,7 @@ do_open(Term file_name, Term t2,
|
||||
(!(flags & Binary_Stream_f) && binary_file(fname))) {
|
||||
UNLOCK(st->streamlock);
|
||||
if (errno == ENOENT)
|
||||
return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, ARG6, "%s: %s", fname,
|
||||
return (PlIOError(EXISTENCE_ERROR_SOURCE_SINK, file_name, "%s: %s", fname,
|
||||
strerror(errno)));
|
||||
else {
|
||||
return (PlIOError(PERMISSION_ERROR_OPEN_SOURCE_SINK, file_name, "%s: %s",
|
||||
@@ -1416,6 +1455,10 @@ do_open(Term file_name, Term t2,
|
||||
} else if ( open_mode == AtomRead && !avoid_bom ) {
|
||||
check_bom(sno, st); // can change encoding
|
||||
}
|
||||
if (script)
|
||||
open_header(sno, open_mode);
|
||||
|
||||
|
||||
|
||||
UNLOCK(st->streamlock);
|
||||
{
|
||||
@@ -1423,10 +1466,109 @@ do_open(Term file_name, Term t2,
|
||||
return (Yap_unify(ARG3, t));
|
||||
}
|
||||
}
|
||||
|
||||
/** @pred open(+ _F_,+ _M_,- _S_) is iso
|
||||
|
||||
|
||||
Opens the file with name _F_ in mode _M_ (`read`, `write` or
|
||||
`append`), returning _S_ unified with the stream name.
|
||||
|
||||
Yap allows 64 streams opened at the same time. If you need more,
|
||||
redefine the MaxStreams constant. Each stream is either an input or
|
||||
an output stream but not both. There are always 3 open streams:
|
||||
user_input for reading, user_output for writing and user_error for
|
||||
writing. If there is no ambiguity, the atoms user_input and
|
||||
user_output may be referred to as `user`.
|
||||
|
||||
The `file_errors` flag controls whether errors are reported when in
|
||||
mode `read` or `append` the file _F_ does not exist or is not
|
||||
readable, and whether in mode `write` or `append` the file is not
|
||||
writable.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
static Int open3(USES_REGS1) { /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
|
||||
return do_open(Deref(ARG1), Deref(ARG2), TermNil PASS_REGS);
|
||||
}
|
||||
|
||||
/** @pred open(+ _F_,+ _M_,- _S_,+ _Opts_) is iso
|
||||
|
||||
Opens the file with name _F_ in mode _M_ (`read`, `write` or
|
||||
`append`), returning _S_ unified with the stream name, and following
|
||||
these options:
|
||||
|
||||
|
||||
|
||||
+ `type(+ _T_)` is iso
|
||||
|
||||
Specify whether the stream is a `text` stream (default), or a
|
||||
`binary` stream.
|
||||
|
||||
+ `reposition(+ _Bool_)` is iso
|
||||
Specify whether it is possible to reposition the stream (`true`), or
|
||||
not (`false`). By default, YAP enables repositioning for all
|
||||
files, except terminal files and sockets.
|
||||
|
||||
+ `eof(+ _Action_)` is iso
|
||||
|
||||
Specify the action to take if attempting to input characters from a
|
||||
stream where we have previously found an `end_of_file`. The possible
|
||||
actions are `error`, that raises an error, `reset`, that tries to
|
||||
reset the stream and is used for `tty` type files, and `eof_code`,
|
||||
which generates a new `end_of_file` (default for non-tty files).
|
||||
|
||||
+ `alias(+ _Name_)` is iso
|
||||
|
||||
Specify an alias to the stream. The alias <tt>Name</tt> must be an atom. The
|
||||
alias can be used instead of the stream descriptor for every operation
|
||||
concerning the stream.
|
||||
|
||||
The operation will fail and give an error if the alias name is already
|
||||
in use. YAP allows several aliases for the same file, but only
|
||||
one is returned by stream_property/2
|
||||
|
||||
+ `bom(+ _Bool_)`
|
||||
|
||||
If present and `true`, a BOM (<em>Byte Order Mark</em>) was
|
||||
detected while opening the file for reading or a BOM was written while
|
||||
opening the stream. See BOM for details.
|
||||
|
||||
+ `encoding(+ _Encoding_)`
|
||||
|
||||
Set the encoding used for text. See Encoding for an overview of
|
||||
wide character and encoding issues.
|
||||
|
||||
+ `representation_errors(+ _Mode_)`
|
||||
|
||||
Change the behaviour when writing characters to the stream that cannot
|
||||
be represented by the encoding. The behaviour is one of `error`
|
||||
(throw and Input/Output error exception), `prolog` (write `\u...\`
|
||||
escape code or `xml` (write `\&#...;` XML character entity).
|
||||
The initial mode is `prolog` for the user streams and
|
||||
`error` for all other streams. See also Encoding.
|
||||
|
||||
+ `expand_filename(+ _Mode_)`
|
||||
|
||||
If _Mode_ is `true` then do filename expansion, then ask Prolog
|
||||
to do file name expansion before actually trying to opening the file:
|
||||
this includes processing `~` characters and processing `$`
|
||||
environment variables at the beginning of the file. Otherwise, just try
|
||||
to open the file using the given name.
|
||||
|
||||
The default behavior is given by the Prolog flag
|
||||
open_expands_filename.
|
||||
|
||||
+ `script( + _Boolean_ )` YAP extension.
|
||||
|
||||
The file may be a Prolog script. In `read` mode just check for
|
||||
initial lines if they start with the hash symbol, and skip them. In
|
||||
`write` mode output an header that can be used to launch the file by
|
||||
calling `yap -l file -- $*`. Note that YAP will not set file
|
||||
permissions as executable. In `append` mode ignore the flag.
|
||||
|
||||
|
||||
*/
|
||||
static Int open4(USES_REGS1) { /* '$open'(+File,+Mode,?Stream,-ReturnCode) */
|
||||
return do_open(Deref(ARG1), Deref(ARG2), Deref(ARG4) PASS_REGS);
|
||||
}
|
||||
@@ -1605,6 +1747,12 @@ int Yap_GetFreeStreamDForReading(void) {
|
||||
return sno;
|
||||
}
|
||||
|
||||
/**
|
||||
* @pred always_prompt_user
|
||||
*
|
||||
* Ensure that the stream always prompts before asking the standard input stream for data.
|
||||
|
||||
*/
|
||||
static Int always_prompt_user(USES_REGS1) {
|
||||
StreamDesc *s = GLOBAL_Stream + StdInStream;
|
||||
|
||||
@@ -1621,7 +1769,17 @@ static Int always_prompt_user(USES_REGS1) {
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
static Int close1(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
|
||||
static Int close1/** @pred close(+ _S_) is iso
|
||||
|
||||
|
||||
Closes the stream _S_. If _S_ does not stand for a stream
|
||||
currently opened an error is reported. The streams user_input,
|
||||
user_output, and user_error can never be closed.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
|
||||
Int sno = CheckStream(
|
||||
ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f), "close/2");
|
||||
if (sno < 0)
|
||||
@@ -1636,7 +1794,7 @@ static Int close1(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
|
||||
}
|
||||
|
||||
#define CLOSE_DEFS() \
|
||||
PAR("force", boolean, CLOSE_FORCE), PAR(NULL, ok, CLOSE_END)
|
||||
PAR("force", booleanFlag, CLOSE_FORCE), PAR(NULL, ok, CLOSE_END)
|
||||
|
||||
#define PAR(x, y, z) z
|
||||
|
||||
@@ -1650,6 +1808,15 @@ typedef enum close_enum_choices { CLOSE_DEFS() } close_choices_t;
|
||||
static const param_t close_defs[] = {CLOSE_DEFS()};
|
||||
#undef PAR
|
||||
|
||||
/** @pred close(+ _S_,+ _O_) is iso
|
||||
|
||||
Closes the stream _S_, following options _O_.
|
||||
|
||||
The only valid options are `force(true)` and `force(false)`.
|
||||
YAP currently ignores these options.
|
||||
|
||||
|
||||
*/
|
||||
static Int close2(USES_REGS1) { /* '$close'(+GLOBAL_Stream) */
|
||||
Int sno = CheckStream(
|
||||
ARG1, (Input_Stream_f | Output_Stream_f | Socket_Stream_f), "close/2");
|
||||
@@ -1685,14 +1852,14 @@ Term read_line(int sno) {
|
||||
|
||||
#define ABSOLUTE_FILE_NAME_DEFS() \
|
||||
PAR("access", isatom, ABSOLUTE_FILE_NAME_ACCESS), \
|
||||
PAR("expand", boolean, ABSOLUTE_FILE_NAME_EXPAND), \
|
||||
PAR("expand", booleanFlag, ABSOLUTE_FILE_NAME_EXPAND), \
|
||||
PAR("extensions", ok, ABSOLUTE_FILE_NAME_EXTENSIONS), \
|
||||
PAR("file_type", is_file_type, ABSOLUTE_FILE_NAME_FILE_TYPE), \
|
||||
PAR("file_errors", is_file_errors, ABSOLUTE_FILE_NAME_FILE_ERRORS), \
|
||||
PAR("glob", ok, ABSOLUTE_FILE_NAME_GLOB), \
|
||||
PAR("relative_to", isatom, ABSOLUTE_FILE_NAME_RELATIVE_TO), \
|
||||
PAR("solutions", issolutions, ABSOLUTE_FILE_NAME_SOLUTIONS), \
|
||||
PAR("verbose_file_search", boolean, \
|
||||
PAR("verbose_file_search", booleanFlag, \
|
||||
ABSOLUTE_FILE_NAME_VERBOSE_FILE_SEARCH), \
|
||||
PAR(NULL, ok, ABSOLUTE_FILE_NAME_END)
|
||||
|
||||
@@ -1838,7 +2005,9 @@ void Yap_InitIOPreds(void) {
|
||||
Yap_InitReadTPreds();
|
||||
Yap_InitFormat();
|
||||
Yap_InitRandomPreds();
|
||||
Yap_InitReadline();
|
||||
#if USE_READLINE
|
||||
Yap_InitReadlinePreds();
|
||||
#endif
|
||||
Yap_InitSockets();
|
||||
Yap_InitSignalPreds();
|
||||
Yap_InitSysPreds();
|
||||
|
||||
Reference in New Issue
Block a user