Merge branch 'master' of ssh://git.dcc.fc.up.pt/yap-6.3

This commit is contained in:
Vitor Santos Costa 2013-01-16 11:29:38 +00:00
commit 298fb62f0c
21 changed files with 1168 additions and 793 deletions

View File

@ -2109,14 +2109,14 @@ c_head(Term t, compiler_struct *cglobs)
if (IsAtomTerm(t)) { if (IsAtomTerm(t)) {
Yap_emit(name_op, (CELL) AtomOfTerm(t), Zero, &cglobs->cint); Yap_emit(name_op, (CELL) AtomOfTerm(t), Zero, &cglobs->cint);
#ifdef BEAM #ifdef BEAM
if (EAM) { if (EAM) {
Yap_emit(run_op,Zero,(UInt) cglobs->cint.CurrentPred,&cglobs->cint); Yap_emit(run_op,Zero,(UInt) cglobs->cint.CurrentPred,&cglobs->cint);
} }
#endif #endif
Yap_emit(ensure_space_op, Zero , Zero, &cglobs->cint);
cglobs->space_op = cglobs->cint.cpc;
return; return;
} }
Yap_emit(ensure_space_op, Zero , Zero, &cglobs->cint);
cglobs->space_op = cglobs->cint.cpc;
f = FunctorOfTerm(t); f = FunctorOfTerm(t);
Yap_emit(name_op, (CELL) NameOfFunctor(f), ArityOfFunctor(f), &cglobs->cint); Yap_emit(name_op, (CELL) NameOfFunctor(f), ArityOfFunctor(f), &cglobs->cint);
#ifdef BEAM #ifdef BEAM
@ -2124,8 +2124,10 @@ c_head(Term t, compiler_struct *cglobs)
Yap_emit(run_op,Zero,(UInt) cglobs->cint.CurrentPred,&cglobs->cint); Yap_emit(run_op,Zero,(UInt) cglobs->cint.CurrentPred,&cglobs->cint);
} }
#endif #endif
if (Yap_ExecutionMode == MIXED_MODE_USER) if (Yap_ExecutionMode == MIXED_MODE_USER)
Yap_emit(native_op, 0, 0, &cglobs->cint); Yap_emit(native_op, 0, 0, &cglobs->cint);
Yap_emit(ensure_space_op, Zero , Zero, &cglobs->cint);
cglobs->space_op = cglobs->cint.cpc;
c_args(t, 0, cglobs); c_args(t, 0, cglobs);
} }
@ -3537,6 +3539,10 @@ Yap_cclause(volatile Term inp_clause, Int NOfArgs, Term mod, volatile Term src)
} }
if (LOCAL_ErrorMessage) if (LOCAL_ErrorMessage)
return (0); return (0);
/* make sure we give enough space for the fact */
if (cglobs.space_op)
cglobs.space_op->rnd1 = cglobs.space_used;
#ifdef DEBUG #ifdef DEBUG
if (GLOBAL_Option['g' - 96]) if (GLOBAL_Option['g' - 96])
Yap_ShowCode(&cglobs.cint); Yap_ShowCode(&cglobs.cint);

View File

@ -476,14 +476,11 @@ int raiseStackOverflow(int overflow)
* FEATURES * * FEATURES *
*******************************/ *******************************/
int
PL_set_prolog_flag(const char *name, int type, ...) PL_set_prolog_flag(const char *name, int type, ...)
{ va_list args; { va_list args;
int rval = TRUE; int rval = TRUE;
int flags = (type & FF_MASK); int flags = (type & FF_MASK);
initPrologFlagTable();
va_start(args, type); va_start(args, type);
switch(type & ~FF_MASK) switch(type & ~FF_MASK)
{ case PL_BOOL: { case PL_BOOL:
@ -494,10 +491,8 @@ PL_set_prolog_flag(const char *name, int type, ...)
} }
case PL_ATOM: case PL_ATOM:
{ const char *v = va_arg(args, const char *); { const char *v = va_arg(args, const char *);
#ifndef __YAP_PROLOG__ // VSC if ( !GD->initialised )
if ( !GD->initialised ) // VSC initAtoms();
initAtoms();
#endif
setPrologFlag(name, FT_ATOM|flags, v); setPrologFlag(name, FT_ATOM|flags, v);
break; break;
} }
@ -509,13 +504,12 @@ PL_set_prolog_flag(const char *name, int type, ...)
default: default:
rval = FALSE; rval = FALSE;
} }
va_end(args); va_end(args);
return rval; return rval;
} }
int int
PL_unify_chars(term_t t, int flags, size_t len, const char *s) PL_unify_chars(term_t t, int flags, size_t len, const char *s)
{ PL_chars_t text; { PL_chars_t text;
@ -761,6 +755,12 @@ PL_get_list_nchars(term_t l, size_t *length, char **s, unsigned int flags)
fail; fail;
} }
void *
PL_malloc_uncollectable(size_t sz)
{
return malloc(sz);
}
int int
PL_get_list_chars(term_t l, char **s, unsigned flags) PL_get_list_chars(term_t l, char **s, unsigned flags)
{ return PL_get_list_nchars(l, NULL, s, flags); { return PL_get_list_nchars(l, NULL, s, flags);
@ -1213,6 +1213,16 @@ nameOfWideAtom(atom_t atom)
return RepAtom(a)->WStrOfAE; return RepAtom(a)->WStrOfAE;
} }
access_level_t
setAccessLevel(access_level_t accept)
{ GET_LD
bool old;
old = LD->prolog_flag.access_level;
LD->prolog_flag.access_level = accept;
return old;
}
#if THREADS #if THREADS

View File

@ -81,6 +81,15 @@ typedef struct {
int optimise; /* -O: optimised compilation */ int optimise; /* -O: optimised compilation */
} cmdline; } cmdline;
struct
{ char * CWDdir;
size_t CWDlen;
char * executable; /* Running executable */
#ifdef __WINDOWS__
char * module; /* argv[0] module passed */
#endif
} paths;
struct struct
{ ExtensionCell _ext_head; /* head of registered extensions */ { ExtensionCell _ext_head; /* head of registered extensions */
ExtensionCell _ext_tail; /* tail of this chain */ ExtensionCell _ext_tail; /* tail of this chain */
@ -193,6 +202,7 @@ typedef struct PL_local_data {
pl_features_t mask; /* Masked access to booleans */ pl_features_t mask; /* Masked access to booleans */
int write_attributes; /* how to write attvars? */ int write_attributes; /* how to write attvars? */
occurs_check_t occurs_check; /* Unify and occurs check */ occurs_check_t occurs_check; /* Unify and occurs check */
access_level_t access_level; /* Current access level */
} prolog_flag; } prolog_flag;
void * glob_info; /* pl-glob.c */ void * glob_info; /* pl-glob.c */

View File

@ -240,6 +240,7 @@ users foreign language code.
#define PRED_LD #define PRED_LD
#define PASS_LD #define PASS_LD
#define PASS_LD1 #define PASS_LD1
#define IGNORE_LD
#else #else
@ -253,6 +254,7 @@ users foreign language code.
#define PASS_LD1 LD #define PASS_LD1 LD
#define PASS_LD , LD #define PASS_LD , LD
#define PRED_LD GET_LD #define PRED_LD GET_LD
#define IGNORE_LD (void)__PL_ld;
#endif #endif
@ -466,9 +468,6 @@ typedef struct
#define FT_FROM_VALUE 0x0f /* Determine type from value */ #define FT_FROM_VALUE 0x0f /* Determine type from value */
#define FT_MASK 0x0f /* mask to get type */ #define FT_MASK 0x0f /* mask to get type */
#define FF_READONLY 0x10 /* feature is read-only */
#define FF_KEEP 0x20 /* keep value it already set */
#define PLFLAG_CHARESCAPE 0x000001 /* handle \ in atoms */ #define PLFLAG_CHARESCAPE 0x000001 /* handle \ in atoms */
#define PLFLAG_GC 0x000002 /* do GC */ #define PLFLAG_GC 0x000002 /* do GC */
#define PLFLAG_TRACE_GC 0x000004 /* verbose gc */ #define PLFLAG_TRACE_GC 0x000004 /* verbose gc */
@ -531,6 +530,15 @@ typedef struct redir_context
#include "pl-file.h" #include "pl-file.h"
typedef enum
{ ACCESS_LEVEL_USER = 0, /* Default user view */
ACCESS_LEVEL_SYSTEM /* Allow low-level access */
} access_level_t;
#define SYSTEM_MODE (LD->prolog_flag.access_level == ACCESS_LEVEL_SYSTEM)
#define PL_malloc_atomic malloc
/* vsc: global variables */ /* vsc: global variables */
#include "pl-global.h" #include "pl-global.h"
@ -682,6 +690,7 @@ typedef double real;
#endif #endif
#define PL_unify_time(A,B) PL_unify_int64(A,B)
extern int PL_unify_char(term_t chr, int c, int how); extern int PL_unify_char(term_t chr, int c, int how);
extern int PL_get_char(term_t chr, int *c, int eof); extern int PL_get_char(term_t chr, int *c, int eof);
extern void PL_cleanup_fork(void); extern void PL_cleanup_fork(void);
@ -691,6 +700,7 @@ extern int PL_unify_atomic(term_t t, PL_atomic_t a);
extern int _PL_unify_atomic(term_t t, PL_atomic_t a); extern int _PL_unify_atomic(term_t t, PL_atomic_t a);
extern int _PL_unify_string(term_t t, word w); extern int _PL_unify_string(term_t t, word w);
#define _PL_get_arg(X,Y,Z) PL_get_arg(X,Y,Z) #define _PL_get_arg(X,Y,Z) PL_get_arg(X,Y,Z)
extern IOSTREAM ** /* provide access to Suser_input, */ extern IOSTREAM ** /* provide access to Suser_input, */
@ -797,6 +807,7 @@ COMMON(int) unicode_separator(pl_wchar_t c);
COMMON(word) pl_raw_read(term_t term); COMMON(word) pl_raw_read(term_t term);
COMMON(word) pl_raw_read2(term_t stream, term_t term); COMMON(word) pl_raw_read2(term_t stream, term_t term);
COMMON(access_level_t) setAccessLevel(access_level_t new_level);
/**** stuff from pl-error.c ****/ /**** stuff from pl-error.c ****/
extern void outOfCore(void); extern void outOfCore(void);
@ -838,7 +849,7 @@ extern size_t getenv3(const char *name, char *buf, size_t len);
extern int Setenv(char *name, char *value); extern int Setenv(char *name, char *value);
extern int Unsetenv(char *name); extern int Unsetenv(char *name);
extern int System(char *cmd); extern int System(char *cmd);
extern bool expandVars(const char *pattern, char *expanded, int maxlen); extern char *expandVars(const char *pattern, char *expanded, int maxlen);
/**** SWI stuff (emulated in pl-yap.c) ****/ /**** SWI stuff (emulated in pl-yap.c) ****/
extern int writeAtomToStream(IOSTREAM *so, atom_t at); extern int writeAtomToStream(IOSTREAM *so, atom_t at);
@ -899,7 +910,7 @@ COMMON(Buffer) codes_or_chars_to_buffer(term_t l, unsigned int flags,
COMMON(bool) systemMode(bool accept); COMMON(bool) systemMode(bool accept);
COMMON(void) initPrologFlagTable(void); COMMON(void) cleanupPrologFlags(void);
COMMON(void) initPrologFlags(void); COMMON(void) initPrologFlags(void);
COMMON(int) raiseStackOverflow(int overflow); COMMON(int) raiseStackOverflow(int overflow);

View File

@ -622,7 +622,7 @@ extern char *PL_prompt_string(int fd);
PL_EXPORT(int) PL_get_file_name(term_t n, char **name, int flags); PL_EXPORT(int) PL_get_file_name(term_t n, char **name, int flags);
PL_EXPORT(int) PL_get_file_nameW(term_t n, wchar_t **name, int flags); PL_EXPORT(int) PL_get_file_nameW(term_t n, wchar_t **name, int flags);
PL_EXPORT(void) PL_changed_cwd(void); /* foreign code changed CWD */ PL_EXPORT(void) PL_changed_cwd(void); /* foreign code changed CWD */
PL_EXPORT(const char *) PL_cwd(void); PL_EXPORT(char *) PL_cwd(char *buf, size_t buflen);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: the functions in this section are not documented, as as yet not NOTE: the functions in this section are not documented, as as yet not
@ -788,8 +788,6 @@ PL_EXPORT(int) PL_unify_mpq(term_t t, mpq_t mpz);
#endif #endif
extern X_API const char *PL_cwd(void);
void swi_install(void); void swi_install(void);
X_API int PL_warning(const char *msg, ...); X_API int PL_warning(const char *msg, ...);

View File

@ -65,6 +65,10 @@ typedef intptr_t ssize_t; /* signed version of size_t */
extern "C" { extern "C" {
#endif #endif
#ifndef PL_HAVE_TERM_T
#define PL_HAVE_TERM_T
typedef uintptr_t term_t;
#endif
/******************************* /*******************************
* CONSTANTS * * CONSTANTS *
*******************************/ *******************************/
@ -335,14 +339,10 @@ PL_EXPORT(int) Sfpasteof(IOSTREAM *s);
PL_EXPORT(int) Sferror(IOSTREAM *s); PL_EXPORT(int) Sferror(IOSTREAM *s);
PL_EXPORT(void) Sclearerr(IOSTREAM *s); PL_EXPORT(void) Sclearerr(IOSTREAM *s);
PL_EXPORT(void) Sseterr(IOSTREAM *s, int which, const char *message); PL_EXPORT(void) Sseterr(IOSTREAM *s, int which, const char *message);
#ifdef _FLI_H_INCLUDED
PL_EXPORT(void) Sset_exception(IOSTREAM *s, term_t ex); PL_EXPORT(void) Sset_exception(IOSTREAM *s, term_t ex);
#else
PL_EXPORT(void) Sset_exception(IOSTREAM *s, intptr_t ex);
#endif
PL_EXPORT(int) Ssetenc(IOSTREAM *s, IOENC new_enc, IOENC *old_enc); PL_EXPORT(int) Ssetenc(IOSTREAM *s, IOENC new_enc, IOENC *old_enc);
PL_EXPORT(int) Sflush(IOSTREAM *s); PL_EXPORT(int) Sflush(IOSTREAM *s);
PL_EXPORT(long) Ssize(IOSTREAM *s); PL_EXPORT(int64_t) Ssize(IOSTREAM *s);
PL_EXPORT(int) Sseek(IOSTREAM *s, long pos, int whence); PL_EXPORT(int) Sseek(IOSTREAM *s, long pos, int whence);
PL_EXPORT(long) Stell(IOSTREAM *s); PL_EXPORT(long) Stell(IOSTREAM *s);
PL_EXPORT(int) Sclose(IOSTREAM *s); PL_EXPORT(int) Sclose(IOSTREAM *s);

View File

@ -471,7 +471,7 @@ init_tout(PL_chars_t *t, size_t len)
{ t->text.t = t->buf; { t->text.t = t->buf;
t->storage = PL_CHARS_LOCAL; t->storage = PL_CHARS_LOCAL;
} else } else
{ t->text.t = PL_malloc(len+1); { t->text.t = PL_malloc(len);
t->storage = PL_CHARS_MALLOC; t->storage = PL_CHARS_MALLOC;
} }
succeed; succeed;
@ -480,7 +480,7 @@ init_tout(PL_chars_t *t, size_t len)
{ t->text.w = (pl_wchar_t*)t->buf; { t->text.w = (pl_wchar_t*)t->buf;
t->storage = PL_CHARS_LOCAL; t->storage = PL_CHARS_LOCAL;
} else } else
{ t->text.w = PL_malloc((len+1)*sizeof(pl_wchar_t)); { t->text.w = PL_malloc(len*sizeof(pl_wchar_t));
t->storage = PL_CHARS_MALLOC; t->storage = PL_CHARS_MALLOC;
} }
succeed; succeed;

View File

@ -1154,6 +1154,7 @@ protocol(const char *str, size_t n)
* TEMPORARY I/O * * TEMPORARY I/O *
*******************************/ *******************************/
int int
push_input_context(atom_t type) push_input_context(atom_t type)
{ GET_LD { GET_LD
@ -1953,7 +1954,7 @@ error:
return FALSE; return FALSE;
} }
#if defined(__WINDOWS__) && !defined(__MINGW32__) /* defined in pl-nt.c */ #ifdef _MSC_VER /* defined in pl-nt.c */
extern int ftruncate(int fileno, int64_t length); extern int ftruncate(int fileno, int64_t length);
#define HAVE_FTRUNCATE #define HAVE_FTRUNCATE
#endif #endif
@ -3586,8 +3587,10 @@ static int
stream_file_name_propery(IOSTREAM *s, term_t prop ARG_LD) stream_file_name_propery(IOSTREAM *s, term_t prop ARG_LD)
{ atom_t name; { atom_t name;
if ( (name = getStreamContext(s)->filename) ) for(; s; s=s->downstream)
{ return PL_unify_atom(prop, name); { if ( (name = getStreamContext(s)->filename) )
{ return PL_unify_atom(prop, name);
}
} }
return FALSE; return FALSE;
@ -3617,13 +3620,17 @@ stream_mode_property(IOSTREAM *s, term_t prop ARG_LD)
static int static int
stream_input_prop(IOSTREAM *s ARG_LD) stream_input_prop(IOSTREAM *s ARG_LD)
{ return (s->flags & SIO_INPUT) ? TRUE : FALSE; { IGNORE_LD
return (s->flags & SIO_INPUT) ? TRUE : FALSE;
} }
static int static int
stream_output_prop(IOSTREAM *s ARG_LD) stream_output_prop(IOSTREAM *s ARG_LD)
{ return (s->flags & SIO_OUTPUT) ? TRUE : FALSE; { IGNORE_LD
return (s->flags & SIO_OUTPUT) ? TRUE : FALSE;
} }
@ -3664,7 +3671,9 @@ stream_alias_prop(IOSTREAM *s, term_t prop ARG_LD)
static int static int
stream_position_prop(IOSTREAM *s, term_t prop ARG_LD) stream_position_prop(IOSTREAM *s, term_t prop ARG_LD)
{ if ( s->position ) { IGNORE_LD
if ( s->position )
{ return PL_unify_term(prop, { return PL_unify_term(prop,
PL_FUNCTOR, FUNCTOR_stream_position4, PL_FUNCTOR, FUNCTOR_stream_position4,
PL_INT64, s->position->charno, PL_INT64, s->position->charno,
@ -3680,8 +3689,7 @@ stream_position_prop(IOSTREAM *s, term_t prop ARG_LD)
static int static int
stream_end_of_stream_prop(IOSTREAM *s, term_t prop ARG_LD) stream_end_of_stream_prop(IOSTREAM *s, term_t prop ARG_LD)
{ if ( s->flags & SIO_INPUT ) { if ( s->flags & SIO_INPUT )
{ GET_LD { atom_t val;
atom_t val;
if ( s->flags & SIO_FEOF2 ) if ( s->flags & SIO_FEOF2 )
val = ATOM_past; val = ATOM_past;
@ -3730,7 +3738,7 @@ stream_reposition_prop(IOSTREAM *s, term_t prop ARG_LD)
int fd = Sfileno(s); int fd = Sfileno(s);
struct stat buf; struct stat buf;
if ( fstat(fd, &buf) == 0 && S_ISREG(buf.st_mode) ) if ( fd != -1 && fstat(fd, &buf) == 0 && S_ISREG(buf.st_mode) )
val = ATOM_true; val = ATOM_true;
else else
val = ATOM_false; val = ATOM_false;
@ -3746,7 +3754,9 @@ stream_reposition_prop(IOSTREAM *s, term_t prop ARG_LD)
static int static int
stream_close_on_abort_prop(IOSTREAM *s, term_t prop ARG_LD) stream_close_on_abort_prop(IOSTREAM *s, term_t prop ARG_LD)
{ return PL_unify_bool_ex(prop, !(s->flags & SIO_NOCLOSE)); { IGNORE_LD
return PL_unify_bool_ex(prop, !(s->flags & SIO_NOCLOSE));
} }
@ -3769,7 +3779,9 @@ stream_file_no_prop(IOSTREAM *s, term_t prop ARG_LD)
static int static int
stream_tty_prop(IOSTREAM *s, term_t prop ARG_LD) stream_tty_prop(IOSTREAM *s, term_t prop ARG_LD)
{ if ( (s->flags & SIO_ISATTY) ) { IGNORE_LD
if ( (s->flags & SIO_ISATTY) )
return PL_unify_bool_ex(prop, TRUE); return PL_unify_bool_ex(prop, TRUE);
return FALSE; return FALSE;
@ -3778,7 +3790,9 @@ stream_tty_prop(IOSTREAM *s, term_t prop ARG_LD)
static int static int
stream_bom_prop(IOSTREAM *s, term_t prop ARG_LD) stream_bom_prop(IOSTREAM *s, term_t prop ARG_LD)
{ if ( (s->flags & SIO_BOM) ) { IGNORE_LD
if ( (s->flags & SIO_BOM) )
return PL_unify_bool_ex(prop, TRUE); return PL_unify_bool_ex(prop, TRUE);
return FALSE; return FALSE;
@ -3876,6 +3890,7 @@ stream_close_on_exec_prop(IOSTREAM *s, term_t prop ARG_LD)
#else #else
int fd_flags; int fd_flags;
#endif #endif
IGNORE_LD
if ( (fd = Sfileno(s)) < 0) if ( (fd = Sfileno(s)) < 0)
return FALSE; return FALSE;
@ -3915,7 +3930,7 @@ static const sprop sprop_list [] =
{ FUNCTOR_end_of_stream1, stream_end_of_stream_prop }, { FUNCTOR_end_of_stream1, stream_end_of_stream_prop },
{ FUNCTOR_eof_action1, stream_eof_action_prop }, { FUNCTOR_eof_action1, stream_eof_action_prop },
{ FUNCTOR_reposition1, stream_reposition_prop }, { FUNCTOR_reposition1, stream_reposition_prop },
{ FUNCTOR_type1, stream_type_prop }, { FUNCTOR_type1, stream_type_prop },
{ FUNCTOR_file_no1, stream_file_no_prop }, { FUNCTOR_file_no1, stream_file_no_prop },
{ FUNCTOR_buffer1, stream_buffer_prop }, { FUNCTOR_buffer1, stream_buffer_prop },
{ FUNCTOR_buffer_size1, stream_buffer_size_prop }, { FUNCTOR_buffer_size1, stream_buffer_size_prop },
@ -3974,7 +3989,7 @@ PRED_IMPL("stream_property", 2, stream_property,
ATOM_stream_property, property); ATOM_stream_property, property);
} }
pe = allocHeap(sizeof(*pe)); pe = allocForeignState(sizeof(*pe));
pe->e = newTableEnum(streamContext); pe->e = newTableEnum(streamContext);
pe->s = NULL; pe->s = NULL;
@ -3992,7 +4007,7 @@ PRED_IMPL("stream_property", 2, stream_property,
{ functor_t f; { functor_t f;
if ( PL_is_variable(property) ) /* generate properties */ if ( PL_is_variable(property) ) /* generate properties */
{ pe = allocHeap(sizeof(*pe)); { pe = allocForeignState(sizeof(*pe));
pe->e = NULL; pe->e = NULL;
pe->s = s; pe->s = s;
@ -4050,7 +4065,7 @@ PRED_IMPL("stream_property", 2, stream_property,
{ if ( pe->e ) { if ( pe->e )
freeTableEnum(pe->e); freeTableEnum(pe->e);
freeHeap(pe, sizeof(*pe)); freeForeignState(pe, sizeof(*pe));
} }
return TRUE; return TRUE;
} }
@ -4066,7 +4081,7 @@ PRED_IMPL("stream_property", 2, stream_property,
if ( pe->e ) if ( pe->e )
freeTableEnum(pe->e); freeTableEnum(pe->e);
freeHeap(pe, sizeof(*pe)); freeForeignState(pe, sizeof(*pe));
return FALSE; return FALSE;
} }
@ -4140,7 +4155,7 @@ PRED_IMPL("stream_property", 2, stream_property,
{ if ( pe->e ) { if ( pe->e )
freeTableEnum(pe->e); freeTableEnum(pe->e);
freeHeap(pe, sizeof(*pe)); freeForeignState(pe, sizeof(*pe));
return FALSE; return FALSE;
} }
} }
@ -4385,7 +4400,8 @@ PRED_IMPL("current_output", 1, current_output, PL_FA_ISO)
static static
PRED_IMPL("byte_count", 2, byte_count, 0) PRED_IMPL("byte_count", 2, byte_count, 0)
{ IOSTREAM *s; { PRED_LD
IOSTREAM *s;
if ( getStreamWithPosition(A1, &s) ) if ( getStreamWithPosition(A1, &s) )
{ int64_t n = s->position->byteno; { int64_t n = s->position->byteno;
@ -4400,7 +4416,8 @@ PRED_IMPL("byte_count", 2, byte_count, 0)
static static
PRED_IMPL("character_count", 2, character_count, 0) PRED_IMPL("character_count", 2, character_count, 0)
{ IOSTREAM *s; { PRED_LD
IOSTREAM *s;
if ( getStreamWithPosition(A1, &s) ) if ( getStreamWithPosition(A1, &s) )
{ int64_t n = s->position->charno; { int64_t n = s->position->charno;
@ -4501,7 +4518,7 @@ peek(term_t stream, term_t chr, int how ARG_LD)
if ( !getInputStream(stream, how == PL_BYTE ? S_BINARY : S_TEXT, &s) ) if ( !getInputStream(stream, how == PL_BYTE ? S_BINARY : S_TEXT, &s) )
return FALSE; return FALSE;
if ( true(s, SIO_NBUF) || (s->bufsize && s->bufsize < MB_LEN_MAX) ) if ( true(s, SIO_NBUF) || (s->bufsize && s->bufsize < PL_MB_LEN_MAX) )
{ releaseStream(s); { releaseStream(s);
return PL_error(NULL, 0, "stream is unbuffered", ERR_PERMISSION, return PL_error(NULL, 0, "stream is unbuffered", ERR_PERMISSION,
ATOM_peek, ATOM_stream, stream); ATOM_peek, ATOM_stream, stream);
@ -4588,20 +4605,23 @@ ssize_t
Sread_user(void *handle, char *buf, size_t size) Sread_user(void *handle, char *buf, size_t size)
{ GET_LD { GET_LD
wrappedIO *wio = handle; wrappedIO *wio = handle;
ssize_t rc;
if ( LD->prompt.next && ttymode != TTY_RAW ) if ( LD->prompt.next && ttymode != TTY_RAW )
PL_write_prompt(TRUE); PL_write_prompt(TRUE);
else else
Sflush(Suser_output); Sflush(Suser_output);
size = (*wio->wrapped_functions->read)(wio->wrapped_handle, buf, size); rc = (*wio->wrapped_functions->read)(wio->wrapped_handle, buf, size);
if ( size == 0 ) /* end-of-file */ if ( rc == 0 ) /* end-of-file */
{ Sclearerr(Suser_input); { Sclearerr(Suser_input);
LD->prompt.next = TRUE; LD->prompt.next = TRUE;
} else if ( size > 0 && buf[size-1] == '\n' ) } else if ( rc == 1 && buf[0] == 04 )
{ rc = 0; /* Map ^D to end-of-file */
} else if ( rc > 0 && buf[rc-1] == '\n' )
LD->prompt.next = TRUE; LD->prompt.next = TRUE;
return size; return rc;
} }
@ -4649,9 +4669,9 @@ PRED_IMPL("set_prolog_IO", 3, set_prolog_IO, 0)
IOSTREAM *in = NULL, *out = NULL, *error = NULL; IOSTREAM *in = NULL, *out = NULL, *error = NULL;
int rval = FALSE; int rval = FALSE;
int wrapin = FALSE; int wrapin = FALSE;
int i;
if ( !term_stream_handle(A1, &in, SH_ERRORS|SH_ALIAS|SH_UNLOCKED PASS_LD) || if ( !term_stream_handle(A1, &in, SH_ERRORS|SH_ALIAS|SH_UNLOCKED PASS_LD) )
!term_stream_handle(A2, &out, SH_ERRORS|SH_ALIAS PASS_LD) )
goto out; goto out;
wrapin = (LD->IO.streams[0] != in); wrapin = (LD->IO.streams[0] != in);
@ -4660,6 +4680,9 @@ PRED_IMPL("set_prolog_IO", 3, set_prolog_IO, 0)
goto out; goto out;
} }
if ( !term_stream_handle(A2, &out, SH_ERRORS|SH_ALIAS PASS_LD) )
goto out;
if ( PL_compare(A2, A3) == 0 ) /* == */ if ( PL_compare(A2, A3) == 0 ) /* == */
{ error = getStream(Snew(out->handle, out->flags, out->functions)); { error = getStream(Snew(out->handle, out->flags, out->functions));
if ( !error ) if ( !error )
@ -4686,6 +4709,11 @@ PRED_IMPL("set_prolog_IO", 3, set_prolog_IO, 0)
LD->prompt.next = TRUE; LD->prompt.next = TRUE;
} }
for(i=0; i<3; i++)
{ LD->IO.streams[i]->position = &LD->IO.streams[0]->posbuf;
LD->IO.streams[i]->flags |= SIO_RECORDPOS;
}
UNLOCK(); UNLOCK();
rval = TRUE; rval = TRUE;
@ -4710,7 +4738,7 @@ PRED_IMPL("$size_stream", 2, size_stream, 0)
if ( !PL_get_stream_handle(A1, &s) ) if ( !PL_get_stream_handle(A1, &s) )
return FALSE; return FALSE;
rval = PL_unify_integer(A2, Ssize(s)); rval = PL_unify_int64(A2, Ssize(s));
PL_release_stream(s); PL_release_stream(s);
return rval; return rval;
@ -4855,15 +4883,12 @@ BeginPredDefs(file)
PRED_DEF("is_stream", 1, is_stream, 0) PRED_DEF("is_stream", 1, is_stream, 0)
PRED_DEF("set_stream", 2, set_stream, 0) PRED_DEF("set_stream", 2, set_stream, 0)
PRED_DEF("with_output_to", 2, with_output_to, PL_FA_TRANSPARENT) PRED_DEF("with_output_to", 2, with_output_to, PL_FA_TRANSPARENT)
//vsc
PRED_DEF("set_prolog_IO", 3, set_prolog_IO, 0) PRED_DEF("set_prolog_IO", 3, set_prolog_IO, 0)
PRED_DEF("protocol", 1, protocol, 0) PRED_DEF("protocol", 1, protocol, 0)
PRED_DEF("protocola", 1, protocola, 0) PRED_DEF("protocola", 1, protocola, 0)
PRED_DEF("noprotocol", 0, noprotocol, 0) PRED_DEF("noprotocol", 0, noprotocol, 0)
PRED_DEF("protocolling", 1, protocolling, 0) PRED_DEF("protocolling", 1, protocolling, 0)
//vsc
PRED_DEF("prompt1", 1, prompt1, 0) PRED_DEF("prompt1", 1, prompt1, 0)
//vsc
PRED_DEF("seek", 4, seek, 0) PRED_DEF("seek", 4, seek, 0)
PRED_DEF("wait_for_input", 3, wait_for_input, 0) PRED_DEF("wait_for_input", 3, wait_for_input, 0)
PRED_DEF("get_single_char", 1, get_single_char, 0) PRED_DEF("get_single_char", 1, get_single_char, 0)
@ -4875,11 +4900,10 @@ BeginPredDefs(file)
PRED_DEF("set_end_of_stream", 1, set_end_of_stream, 0) PRED_DEF("set_end_of_stream", 1, set_end_of_stream, 0)
/* SWI internal */ /* SWI internal */
PRED_DEF("$push_input_context", 0, push_input_context, 0) PRED_DEF("$push_input_context", 1, push_input_context, 0)
PRED_DEF("$pop_input_context", 0, pop_input_context, 0) PRED_DEF("$pop_input_context", 0, pop_input_context, 0)
PRED_DEF("$input_context", 1, input_context, 0) PRED_DEF("$input_context", 1, input_context, 0)
PRED_DEF("$size_stream", 2, size_stream, 0) PRED_DEF("$size_stream", 2, size_stream, 0)
//vsc
EndPredDefs EndPredDefs
#if __YAP_PROLOG__ #if __YAP_PROLOG__

View File

@ -3,9 +3,10 @@
Part of SWI-Prolog Part of SWI-Prolog
Author: Jan Wielemaker Author: Jan Wielemaker
E-mail: J.Wielemaker@uva.nl E-mail: J.Wielemaker@cs.vu.nl
WWW: http://www.swi-prolog.org WWW: http://www.swi-prolog.org
Copyright (C): 1985-2008, University of Amsterdam Copyright (C): 1985-2011, University of Amsterdam
VU University Amsterdam
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -19,7 +20,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "pl-incl.h" #include "pl-incl.h"
@ -44,26 +45,89 @@
General file operations and binding to Prolog General file operations and binding to Prolog
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef __WINDOWS__
static void
set_posix_error(int win_error)
{ int error = 0;
switch(win_error)
{ case ERROR_ACCESS_DENIED: error = EACCES; break;
case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
case ERROR_SHARING_VIOLATION: error = EAGAIN; break;
case ERROR_ALREADY_EXISTS: error = EEXIST; break;
}
errno = error;
}
#endif /*__WINDOWS__*/
/******************************* /*******************************
* OS STUFF * * OS STUFF *
*******************************/ *******************************/
/** time_t LastModifiedFile(const char *file) /** int LastModifiedFile(const char *file, double *t)
Return the last modification time of file as a POSIX timestamp. Returns Return the last modification time of file as a POSIX timestamp. Returns
(time_t)-1 on failure. (time_t)-1 on failure.
Contains a 64-bit value representing the number of 100-nanosecond
intervals since January 1, 1601 (UTC).
*/ */
int
LastModifiedFile(const char *name, double *tp)
{
#ifdef __WINDOWS__
HANDLE hFile;
wchar_t wfile[MAXPATHLEN];
time_t #define nano * 0.000000001
LastModifiedFile(const char *file) #define ntick 100.0
{ char tmp[MAXPATHLEN]; #define SEC_TO_UNIX_EPOCH 11644473600.0
if ( !_xos_os_filenameW(name, wfile, MAXPATHLEN) )
return FALSE;
if ( (hFile=CreateFileW(wfile,
0,
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL)) != INVALID_HANDLE_VALUE )
{ FILETIME wt;
int rc;
rc = GetFileTime(hFile, NULL, NULL, &wt);
CloseHandle(hFile);
if ( rc )
{ double t;
t = (double)wt.dwHighDateTime * (4294967296.0 * ntick nano);
t += (double)wt.dwLowDateTime * (ntick nano);
t -= SEC_TO_UNIX_EPOCH;
*tp = t;
return TRUE;
}
}
set_posix_error(GetLastError());
return FALSE;
#else
char tmp[MAXPATHLEN];
statstruct buf; statstruct buf;
if ( statfunc(OsPath(file, tmp), &buf) < 0 ) if ( statfunc(OsPath(name, tmp), &buf) < 0 )
return (time_t)-1; return FALSE;
return buf.st_mtime; *tp = (double)buf.st_mtime;
return TRUE;
#endif
} }
@ -349,13 +413,7 @@ MarkExecutable(const char *name)
int int
unifyTime(term_t t, time_t time) unifyTime(term_t t, time_t time)
{ { return PL_unify_time(t, time);
#if __YAP_PROLOG__
/* maintain compatibility with old Prolog systems, and avoid losing precision unnecessarily */
return PL_unify_int64(t, (int64_t)time);
#else
return PL_unify_float(t, (double)time);
#endif
} }
@ -433,9 +491,12 @@ get_file_name(term_t n, char **namep, char *tmp, int flags)
return PL_error(NULL, 0, "file name contains a 0-code", return PL_error(NULL, 0, "file name contains a 0-code",
ERR_DOMAIN, ATOM_file_name, n); ERR_DOMAIN, ATOM_file_name, n);
} }
if ( len+1 >= MAXPATHLEN )
return PL_error(NULL, 0, NULL, ERR_REPRESENTATION,
ATOM_max_path_length);
if ( truePrologFlag(PLFLAG_FILEVARS) ) if ( truePrologFlag(PLFLAG_FILEVARS) )
{ if ( !(name = ExpandOneFile(name, tmp)) ) { if ( !(name = expandVars(name, tmp, MAXPATHLEN)) )
return FALSE; return FALSE;
} }
@ -529,13 +590,13 @@ PRED_IMPL("time_file", 2, time_file, 0)
{ char *fn; { char *fn;
if ( PL_get_file_name(A1, &fn, 0) ) if ( PL_get_file_name(A1, &fn, 0) )
{ time_t time; { double time;
if ( (time = LastModifiedFile(fn)) == (time_t)-1 ) if ( LastModifiedFile(fn, &time) )
return PL_error(NULL, 0, NULL, ERR_FILE_OPERATION, return PL_unify_float(A2, time);
ATOM_time, ATOM_file, A1);
return unifyTime(A2, time); return PL_error(NULL, 0, NULL, ERR_FILE_OPERATION,
ATOM_time, ATOM_file, A1);
} }
return FALSE; return FALSE;
@ -544,7 +605,8 @@ PRED_IMPL("time_file", 2, time_file, 0)
static static
PRED_IMPL("size_file", 2, size_file, 0) PRED_IMPL("size_file", 2, size_file, 0)
{ char *n; { PRED_LD
char *n;
if ( PL_get_file_name(A1, &n, 0) ) if ( PL_get_file_name(A1, &n, 0) )
{ int64_t size; { int64_t size;
@ -680,7 +742,7 @@ static
PRED_IMPL("file_base_name", 2, file_base_name, 0) PRED_IMPL("file_base_name", 2, file_base_name, 0)
{ char *n; { char *n;
if ( !PL_get_chars_ex(A1, &n, CVT_ALL|REP_FN) ) if ( !PL_get_chars(A1, &n, CVT_ALL|REP_FN|CVT_EXCEPTION) )
return FALSE; return FALSE;
return PL_unify_chars(A2, PL_ATOM|REP_FN, -1, BaseName(n)); return PL_unify_chars(A2, PL_ATOM|REP_FN, -1, BaseName(n));
@ -692,7 +754,7 @@ PRED_IMPL("file_directory_name", 2, file_directory_name, 0)
{ char *n; { char *n;
char tmp[MAXPATHLEN]; char tmp[MAXPATHLEN];
if ( !PL_get_chars_ex(A1, &n, CVT_ALL|REP_FN) ) if ( !PL_get_chars(A1, &n, CVT_ALL|REP_FN|CVT_EXCEPTION) )
return FALSE; return FALSE;
return PL_unify_chars(A2, PL_ATOM|REP_FN, -1, DirName(n, tmp)); return PL_unify_chars(A2, PL_ATOM|REP_FN, -1, DirName(n, tmp));
@ -868,12 +930,13 @@ PRED_IMPL("$absolute_file_name", 2, absolute_file_name, 0)
static static
PRED_IMPL("working_directory", 2, working_directory, 0) PRED_IMPL("working_directory", 2, working_directory, 0)
{ PRED_LD { PRED_LD
char buf[MAXPATHLEN];
const char *wd; const char *wd;
term_t old = A1; term_t old = A1;
term_t new = A2; term_t new = A2;
if ( !(wd = PL_cwd()) ) if ( !(wd = PL_cwd(buf, sizeof(buf))) )
return FALSE; return FALSE;
if ( PL_unify_chars(old, PL_ATOM|REP_FN, -1, wd) ) if ( PL_unify_chars(old, PL_ATOM|REP_FN, -1, wd) )
@ -966,8 +1029,8 @@ PRED_IMPL("file_name_extension", 3, file_name_extension, 0)
PL_fail; PL_fail;
} }
if ( PL_get_chars_ex(base, &b, CVT_ALL|BUF_RING|REP_FN) && if ( PL_get_chars(base, &b, CVT_ALL|BUF_RING|REP_FN|CVT_EXCEPTION) &&
PL_get_chars_ex(ext, &e, CVT_ALL|REP_FN) ) PL_get_chars(ext, &e, CVT_ALL|REP_FN|CVT_EXCEPTION) )
{ char *s; { char *s;
if ( e[0] == '.' ) /* +Base, +Extension, -full */ if ( e[0] == '.' ) /* +Base, +Extension, -full */
@ -989,20 +1052,19 @@ PRED_IMPL("file_name_extension", 3, file_name_extension, 0)
static static
PRED_IMPL("prolog_to_os_filename", 2, prolog_to_os_filename, 0) PRED_IMPL("prolog_to_os_filename", 2, prolog_to_os_filename, 0)
{ { PRED_LD
term_t pl = A1; term_t pl = A1;
term_t os = A2; term_t os = A2;
#ifdef O_XOS #ifdef O_XOS
PRED_LD
wchar_t *wn; wchar_t *wn;
if ( !PL_is_variable(pl) ) if ( !PL_is_variable(pl) )
{ char *n; { char *n;
wchar_t buf[MAXPATHLEN]; wchar_t buf[MAXPATHLEN];
if ( PL_get_chars_ex(pl, &n, CVT_ALL|REP_UTF8) ) if ( PL_get_chars(pl, &n, CVT_ALL|REP_UTF8|CVT_EXCEPTION) )
{ if ( !_xos_os_filenameW(n, buf, MAXPATHLEN) ) { if ( !_xos_os_filenameW(n, buf, MAXPATHLEN) )
return name_too_long(); return name_too_long();

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef PL_FILES_H_INCLUDED #ifndef PL_FILES_H_INCLUDED
@ -31,11 +31,11 @@
#define ACCESS_WRITE 4 #define ACCESS_WRITE 4
COMMON(void) initFiles(void); COMMON(void) initFiles(void);
COMMON(time_t) LastModifiedFile(const char *f); COMMON(int) LastModifiedFile(const char *f, double *t);
COMMON(int) RemoveFile(const char *path); COMMON(int) RemoveFile(const char *path);
COMMON(int) AccessFile(const char *path, int mode); COMMON(int) AccessFile(const char *path, int mode);
COMMON(char *) DeRefLink(const char *link, char *buf); COMMON(char *) DeRefLink(const char *link, char *buf);
COMMON(int) ExistsFile(const char *path); COMMON(int) ExistsFile(const char *path);
COMMON(int) ExistsDirectory(const char *path); COMMON(int) ExistsDirectory(const char *path);
#endif /*PL_FILES_H_INCLUDED*/ #endif /*PL_FILES_H_INCLUDED*/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -53,9 +53,9 @@ typedef struct
struct rubber rub[MAXRUBBER]; struct rubber rub[MAXRUBBER];
} format_state; } format_state;
#define BUFSIZE 1024 #define BUFSIZE 1024
#define DEFAULT (-1) #define DEFAULT (-1)
#define SHIFT { argc--; argv++; } #define SHIFT { argc--; argv++; }
#define NEED_ARG { if ( argc <= 0 ) \ #define NEED_ARG { if ( argc <= 0 ) \
{ FMT_ERROR("not enough arguments"); \ { FMT_ERROR("not enough arguments"); \
} \ } \
@ -189,7 +189,8 @@ outtext(format_state *state, PL_chars_t *txt)
#define format_predicates (GD->format.predicates) #define format_predicates (GD->format.predicates)
static int update_column(int, Char); static int update_column(int, Char);
static bool do_format(IOSTREAM *fd, PL_chars_t *fmt, int ac, term_t av); static bool do_format(IOSTREAM *fd, PL_chars_t *fmt,
int ac, term_t av, Module m);
static void distribute_rubber(struct rubber *, int, int); static void distribute_rubber(struct rubber *, int, int);
static int emit_rubber(format_state *state); static int emit_rubber(format_state *state);
@ -272,7 +273,7 @@ pl_current_format_predicate(term_t chr, term_t descr, control_t h)
static word static word
format_impl(IOSTREAM *out, term_t format, term_t Args) format_impl(IOSTREAM *out, term_t format, term_t Args, Module m)
{ GET_LD { GET_LD
term_t argv; term_t argv;
int argc = 0; int argc = 0;
@ -307,7 +308,7 @@ format_impl(IOSTREAM *out, term_t format, term_t Args)
break; break;
} }
rval = do_format(out, &fmt, argc, argv); rval = do_format(out, &fmt, argc, argv, m);
PL_free_text(&fmt); PL_free_text(&fmt);
if ( !endCritical ) if ( !endCritical )
return FALSE; return FALSE;
@ -318,31 +319,20 @@ format_impl(IOSTREAM *out, term_t format, term_t Args)
word word
pl_format3(term_t out, term_t format, term_t args) pl_format3(term_t out, term_t format, term_t args)
{ redir_context ctx; { GET_LD
redir_context ctx;
word rc; word rc;
#if __YAP_PROLOG__ Module m = NULL;
/* term_t list = PL_new_term_ref();
YAP allows the last argument to format to be of the form
module:[]
*/
YAP_Term mod;
#endif
if ( (rc=setupOutputRedirect(out, &ctx, FALSE)) ) { if ( !PL_strip_module(args, &m, list) )
#if __YAP_PROLOG__ return FALSE;
/* module processing */
{ if ( (rc=setupOutputRedirect(out, &ctx, FALSE)) )
args = Yap_fetch_module_for_format(args, &mod); { if ( (rc = format_impl(ctx.stream, format, list, m)) )
} rc = closeOutputRedirect(&ctx);
#endif else
{ if ( (rc = format_impl(ctx.stream, format, args)) )
rc = closeOutputRedirect(&ctx);
else
discardOutputRedirect(&ctx); discardOutputRedirect(&ctx);
}
#if __YAP_PROLOG__
YAP_SetCurrentModule(mod);
#endif
} }
return rc; return rc;
@ -374,7 +364,7 @@ get_chr_from_text(const PL_chars_t *t, int index)
********************************/ ********************************/
static bool static bool
do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv) do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv, Module m)
{ GET_LD { GET_LD
format_state state; /* complete state */ format_state state; /* complete state */
int tab_stop = 0; /* padded tab stop */ int tab_stop = 0; /* padded tab stop */
@ -443,7 +433,7 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
char buf[BUFSIZE]; char buf[BUFSIZE];
char *str = buf; char *str = buf;
size_t bufsize = BUFSIZE; size_t bufsize = BUFSIZE;
unsigned int i; int i;
PL_predicate_info(proc, NULL, &arity, NULL); PL_predicate_info(proc, NULL, &arity, NULL);
av = PL_new_term_refs(arity); av = PL_new_term_refs(arity);
@ -481,7 +471,9 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
if ( !PL_get_text(argv, &txt, CVT_ATOMIC) ) if ( !PL_get_text(argv, &txt, CVT_ATOMIC) )
FMT_ARG("a", argv); FMT_ARG("a", argv);
SHIFT; SHIFT;
outtext(&state, &txt); rc = outtext(&state, &txt);
if ( !rc )
goto out;
here++; here++;
break; break;
} }
@ -494,7 +486,9 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
SHIFT; SHIFT;
while(times-- > 0) while(times-- > 0)
{ outchr(&state, chr); { rc = outchr(&state, chr);
if ( !rc )
goto out;
} }
} else } else
FMT_ARG("c", argv); FMT_ARG("c", argv);
@ -508,7 +502,7 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
case 'G': /* shortest of 'f' and 'E' */ case 'G': /* shortest of 'f' and 'E' */
{ number n; { number n;
union { union {
tmp_buffer b; tmp_buffer b;
buffer b1; buffer b1;
} u; } u;
@ -525,8 +519,10 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
initBuffer(&u.b); initBuffer(&u.b);
formatFloat(c, arg, &n, &u.b1); formatFloat(c, arg, &n, &u.b1);
clearNumber(&n); clearNumber(&n);
outstring0(&state, baseBuffer(&u.b, char)); rc = outstring0(&state, baseBuffer(&u.b, char));
discardBuffer(&u.b); discardBuffer(&u.b);
if ( !rc )
goto out;
here++; here++;
break; break;
} }
@ -564,8 +560,10 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
formatNumber(FALSE, 0, arg, c == 'r', &i, (Buffer)&b); formatNumber(FALSE, 0, arg, c == 'r', &i, (Buffer)&b);
} }
clearNumber(&i); clearNumber(&i);
outstring0(&state, baseBuffer(&b, char)); rc = outstring0(&state, baseBuffer(&b, char));
discardBuffer(&b); discardBuffer(&b);
if ( !rc )
goto out;
here++; here++;
break; break;
} }
@ -576,8 +574,10 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
if ( !PL_get_text(argv, &txt, CVT_LIST|CVT_STRING) && if ( !PL_get_text(argv, &txt, CVT_LIST|CVT_STRING) &&
!PL_get_text(argv, &txt, CVT_ATOM) ) /* SICStus compat */ !PL_get_text(argv, &txt, CVT_ATOM) ) /* SICStus compat */
FMT_ARG("s", argv); FMT_ARG("s", argv);
outtext(&state, &txt); rc = outtext(&state, &txt);
SHIFT; SHIFT;
if ( !rc )
goto out;
here++; here++;
break; break;
} }
@ -610,8 +610,10 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
str = buf; str = buf;
tellString(&str, &bufsize, ENC_UTF8); tellString(&str, &bufsize, ENC_UTF8);
(*f)(argv); rc = (*f)(argv);
toldString(); toldString();
if ( !rc )
goto out;
oututf8(&state, str, bufsize); oututf8(&state, str, bufsize);
if ( str != buf ) if ( str != buf )
free(str); free(str);
@ -632,8 +634,10 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
str = buf; str = buf;
tellString(&str, &bufsize, ENC_UTF8); tellString(&str, &bufsize, ENC_UTF8);
(*f)(argv); rc = (*f)(argv);
toldString(); toldString();
if ( !rc )
goto out;
oututf8(&state, str, bufsize); oututf8(&state, str, bufsize);
if ( str != buf ) if ( str != buf )
free(str); free(str);
@ -704,7 +708,7 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
{ FMT_ERROR("not enough arguments"); { FMT_ERROR("not enough arguments");
} }
tellString(&str, &bufsize, ENC_UTF8); tellString(&str, &bufsize, ENC_UTF8);
rval = callProlog(NULL, argv, PL_Q_CATCH_EXCEPTION, &ex); rval = callProlog(m, argv, PL_Q_CATCH_EXCEPTION, &ex);
toldString(); toldString();
oututf8(&state, str, bufsize); oututf8(&state, str, bufsize);
if ( str != buf ) if ( str != buf )
@ -724,7 +728,9 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
break; break;
} }
case '~': /* ~ */ case '~': /* ~ */
{ outchr(&state, '~'); { rc = outchr(&state, '~');
if ( !rc )
goto out;
here++; here++;
break; break;
} }
@ -735,7 +741,10 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
if ( c == 'N' && state.column == 0 ) if ( c == 'N' && state.column == 0 )
arg--; arg--;
while( arg-- > 0 ) while( arg-- > 0 )
outchr(&state, '\n'); { rc = outchr(&state, '\n');
if ( !rc )
goto out;
}
here++; here++;
break; break;
} }
@ -790,7 +799,9 @@ do_format(IOSTREAM *fd, PL_chars_t *fmt, int argc, term_t argv)
break; /* the '~' switch */ break; /* the '~' switch */
} }
default: default:
{ outchr(&state, c); { rc = outchr(&state, c);
if ( !rc )
goto out;
here++; here++;
break; break;
} }
@ -1032,7 +1043,8 @@ formatFloat(int how, int arg, Number f, Buffer out)
while(written >= size) while(written >= size)
{ size = written+1; { size = written+1;
growBuffer(out, size); /* reserve for -.e<null> */ if ( !growBuffer(out, size) ) /* reserve for -.e<null> */
outOfCore();
written = gmp_snprintf(baseBuffer(out, char), size, tmp, mpf); written = gmp_snprintf(baseBuffer(out, char), size, tmp, mpf);
} }
mpf_clear(mpf); mpf_clear(mpf);
@ -1053,7 +1065,8 @@ formatFloat(int how, int arg, Number f, Buffer out)
while(written >= size) while(written >= size)
{ size = written+1; { size = written+1;
growBuffer(out, size); if ( !growBuffer(out, size) )
outOfCore();
written = snprintf(baseBuffer(out, char), size, tmp, f->value.f); written = snprintf(baseBuffer(out, char), size, tmp, f->value.f);
} }
out->top = out->base + written; out->top = out->base + written;

View File

@ -3,9 +3,10 @@
Part of SWI-Prolog Part of SWI-Prolog
Author: Jan Wielemaker Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl E-mail: J.Wielemaker@cs.vu.nl
WWW: http://www.swi-prolog.org WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam Copyright (C): 1985-2011, University of Amsterdam
VU University Amsterdam
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -19,7 +20,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "pl-incl.h" #include "pl-incl.h"
@ -29,9 +30,9 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef __WATCOMC__ #ifdef O_XOS
#include <direct.h> # include "windows/dirent.h"
#else /*__WATCOMC__*/ #else
#if HAVE_DIRENT_H #if HAVE_DIRENT_H
# include <dirent.h> # include <dirent.h>
#else #else
@ -46,7 +47,7 @@
# include <ndir.h> # include <ndir.h>
# endif # endif
#endif #endif
#endif /*__WATCOMC__*/ #endif /*O_XOS*/
#ifdef HAVE_SYS_STAT_H #ifdef HAVE_SYS_STAT_H
#include <sys/stat.h> #include <sys/stat.h>
@ -326,8 +327,8 @@ PRED_IMPL("wildcard_match", 2, wildcard_match, 0)
{ char *p, *s; { char *p, *s;
compiled_pattern buf; compiled_pattern buf;
if ( !PL_get_chars_ex(A1, &p, CVT_ALL) || if ( !PL_get_chars(A1, &p, CVT_ALL|CVT_EXCEPTION) ||
!PL_get_chars_ex(A2, &s, CVT_ALL) ) !PL_get_chars(A2, &s, CVT_ALL|CVT_EXCEPTION) )
fail; fail;
if ( compilePattern(p, &buf) ) if ( compilePattern(p, &buf) )
@ -423,6 +424,7 @@ expand(const char *pattern, GlobInfo info)
compiled_pattern cbuf; compiled_pattern cbuf;
char prefix[MAXPATHLEN]; /* before first pattern */ char prefix[MAXPATHLEN]; /* before first pattern */
char patbuf[MAXPATHLEN]; /* pattern buffer */ char patbuf[MAXPATHLEN]; /* pattern buffer */
size_t prefix_len;
int end, dot; int end, dot;
initBuffer(&info->files); initBuffer(&info->files);
@ -441,20 +443,25 @@ expand(const char *pattern, GlobInfo info)
switch( (c=*s++) ) switch( (c=*s++) )
{ case EOS: { case EOS:
if ( s > pat ) /* something left and expanded */ if ( s > pat ) /* something left and expanded */
{ un_escape(prefix, pat, s); { size_t prefix_len;
un_escape(prefix, pat, s);
prefix_len = strlen(prefix);
end = info->end; end = info->end;
for( ; info->start < end; info->start++ ) for( ; info->start < end; info->start++ )
{ char path[MAXPATHLEN]; { char path[MAXPATHLEN];
size_t plen; const char *entry = expand_entry(info, info->start);
size_t plen = strlen(entry);
strcpy(path, expand_entry(info, info->start)); if ( plen+prefix_len+2 <= MAXPATHLEN )
plen = strlen(path); { strcpy(path, entry);
if ( prefix[0] && plen > 0 && path[plen-1] != '/' ) if ( prefix[0] && plen > 0 && path[plen-1] != '/' )
path[plen++] = '/'; path[plen++] = '/';
strcpy(&path[plen], prefix); strcpy(&path[plen], prefix);
if ( end == 1 || AccessFile(path, ACCESS_EXIST) ) if ( end == 1 || AccessFile(path, ACCESS_EXIST) )
add_path(path, info); add_path(path, info);
}
} }
} }
succeed; succeed;
@ -489,8 +496,9 @@ expand(const char *pattern, GlobInfo info)
*/ */
un_escape(prefix, pat, head); un_escape(prefix, pat, head);
un_escape(patbuf, head, tail); un_escape(patbuf, head, tail);
prefix_len = strlen(prefix);
if ( !compilePattern(patbuf, &cbuf) ) /* syntax error */ if ( !compilePattern(patbuf, &cbuf) ) /* syntax error */
fail; fail;
dot = (patbuf[0] == '.'); /* do dots as well */ dot = (patbuf[0] == '.'); /* do dots as well */
@ -502,6 +510,10 @@ expand(const char *pattern, GlobInfo info)
char path[MAXPATHLEN]; char path[MAXPATHLEN];
char tmp[MAXPATHLEN]; char tmp[MAXPATHLEN];
const char *current = expand_entry(info, info->start); const char *current = expand_entry(info, info->start);
size_t clen = strlen(current);
if ( clen+prefix_len+1 > sizeof(path) )
continue;
strcpy(path, current); strcpy(path, current);
strcat(path, prefix); strcat(path, prefix);
@ -521,12 +533,11 @@ expand(const char *pattern, GlobInfo info)
matchPattern(e->d_name, &cbuf) ) matchPattern(e->d_name, &cbuf) )
{ char newp[MAXPATHLEN]; { char newp[MAXPATHLEN];
strcpy(newp, path); if ( plen+strlen(e->d_name)+1 < sizeof(newp) )
strcpy(&newp[plen], e->d_name); { strcpy(newp, path);
/* if ( !tail[0] || ExistsDirectory(newp) ) strcpy(&newp[plen], e->d_name);
Saves memory, but involves one more file-access
*/
add_path(newp, info); add_path(newp, info);
}
} }
} }
closedir(d); closedir(d);
@ -579,11 +590,11 @@ PRED_IMPL("expand_file_name", 2, expand_file_name, 0)
term_t head = PL_new_term_ref(); term_t head = PL_new_term_ref();
int i; int i;
if ( !PL_get_chars_ex(A1, &s, CVT_ALL|REP_FN) ) if ( !PL_get_chars(A1, &s, CVT_ALL|REP_FN|CVT_EXCEPTION) )
fail; fail;
if ( strlen(s) > sizeof(spec)-1 ) if ( strlen(s) > sizeof(spec)-1 )
return PL_error(NULL, 0, "File name too intptr_t", return PL_error(NULL, 0, NULL, ERR_REPRESENTATION,
ERR_DOMAIN, ATOM_pattern, A1); ATOM_max_path_length);
if ( !expandVars(s, spec, sizeof(spec)) ) if ( !expandVars(s, spec, sizeof(spec)) )
fail; fail;

View File

@ -1,11 +1,10 @@
/* $Id$ /* Part of SWI-Prolog
Part of SWI-Prolog
Author: Jan Wielemaker Author: Jan Wielemaker
E-mail: wielemak@science.uva.nl E-mail: J.Wielemaker@vu.nl
WWW: http://www.swi-prolog.org WWW: http://www.swi-prolog.org
Copyright (C): 1985-2007, University of Amsterdam Copyright (C): 1985-2013, University of Amsterdam
VU University Amsterdam
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -19,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/* Modified (M) 1993 Dave Sherratt */ /* Modified (M) 1993 Dave Sherratt */
@ -30,6 +29,17 @@
#include <os2.h> /* this has to appear before pl-incl.h */ #include <os2.h> /* this has to appear before pl-incl.h */
#endif #endif
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Solaris has asctime_r() with 3 arguments. Using _POSIX_PTHREAD_SEMANTICS
is supposed to give the POSIX standard one.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(__sun__) || defined(__sun)
#define _POSIX_PTHREAD_SEMANTICS 1
#endif
#define __MINGW_USE_VC2005_COMPAT /* Get Windows time_t as 64-bit */
#include "pl-incl.h" #include "pl-incl.h"
#include "pl-ctype.h" #include "pl-ctype.h"
#include "pl-utf8.h" #include "pl-utf8.h"
@ -96,27 +106,11 @@ static double initial_time;
static void initExpand(void); static void initExpand(void);
static void cleanupExpand(void); static void cleanupExpand(void);
static void initEnviron(void); static void initEnviron(void);
static char * Which(const char *program, char *fullname);
#ifndef DEFAULT_PATH #ifndef DEFAULT_PATH
#define DEFAULT_PATH "/bin:/usr/bin" #define DEFAULT_PATH "/bin:/usr/bin"
#endif #endif
/*******************************
* GLOBALS *
*******************************/
#ifdef HAVE_CLOCK
long clock_wait_ticks;
#endif
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This module is a contraction of functions that used to be all over the
place. together with pl-os.h (included by pl-incl.h) this file
should define a basic layer around the OS, on which the rest of
SWI-Prolog is based.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/******************************** /********************************
* INITIALISATION * * INITIALISATION *
*********************************/ *********************************/
@ -145,20 +139,6 @@ initOs(void)
setPrologFlagMask(PLFLAG_FILE_CASE_PRESERVING); setPrologFlagMask(PLFLAG_FILE_CASE_PRESERVING);
#endif #endif
#ifdef HAVE_CLOCK
clock_wait_ticks = 0L;
#endif
#if OS2
{ DATETIME i;
DosGetDateTime((PDATETIME)&i);
initial_time = (i.hours * 3600.0)
+ (i.minutes * 60.0)
+ i.seconds
+ (i.hundredths / 100.0);
}
#endif /* OS2 */
DEBUG(1, Sdprintf("OS:done\n")); DEBUG(1, Sdprintf("OS:done\n"));
succeed; succeed;
@ -239,11 +219,26 @@ static char errmsg[64];
#endif /*_SC_CLK_TCK*/ #endif /*_SC_CLK_TCK*/
#endif /*HAVE_TIMES*/ #endif /*HAVE_TIMES*/
#ifdef HAVE_CLOCK_GETTIME
#define timespec_to_double(ts) \
((double)(ts).tv_sec + (double)(ts).tv_nsec/(double)1000000000.0)
#endif
double double
CpuTime(cputime_kind which) CpuTime(cputime_kind which)
{ {
#ifdef HAVE_TIMES #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
#define CPU_TIME_DONE
struct timespec ts;
(void)which;
if ( clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0 )
return timespec_to_double(ts);
return 0.0;
#endif
#if !defined(CPU_TIME_DONE) && defined(HAVE_TIMES)
#define CPU_TIME_DONE
struct tms t; struct tms t;
double used; double used;
static int MTOK_got_hz = FALSE; static int MTOK_got_hz = FALSE;
@ -268,39 +263,17 @@ CpuTime(cputime_kind which)
used = 0.0; /* happens when running under GDB */ used = 0.0; /* happens when running under GDB */
return used; return used;
#else #endif
#if OS2 && EMX #if !defined(CPU_TIME_DONE)
DATETIME i; (void)which;
DosGetDateTime((PDATETIME)&i);
return (((i.hours * 3600)
+ (i.minutes * 60)
+ i.seconds
+ (i.hundredths / 100.0)) - initial_time);
#else
#ifdef HAVE_CLOCK
return (double) (clock() - clock_wait_ticks) / (double) CLOCKS_PER_SEC;
#else
return 0.0; return 0.0;
#endif
#endif
#endif #endif
} }
#endif /*__WINDOWS__*/ #endif /*__WINDOWS__*/
void
PL_clock_wait_ticks(long waited)
{
#ifdef HAVE_CLOCK
clock_wait_ticks += waited;
#endif
}
double double
WallTime(void) WallTime(void)
@ -310,7 +283,7 @@ WallTime(void)
struct timespec tp; struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp); clock_gettime(CLOCK_REALTIME, &tp);
stime = (double)tp.tv_sec + (double)tp.tv_nsec/1000000000.0; stime = timespec_to_double(tp);
#else #else
#ifdef HAVE_GETTIMEOFDAY #ifdef HAVE_GETTIMEOFDAY
struct timeval tp; struct timeval tp;
@ -389,7 +362,7 @@ CpuCount()
#include <sys/sysctl.h> #include <sys/sysctl.h>
int int
CpuCount() CpuCount(void)
{ int count ; { int count ;
size_t size=sizeof(count) ; size_t size=sizeof(count) ;
@ -415,7 +388,7 @@ setOSPrologFlags(void)
{ int cpu_count = CpuCount(); { int cpu_count = CpuCount();
if ( cpu_count > 0 ) if ( cpu_count > 0 )
PL_set_prolog_flag("cpu_count", PL_INTEGER|FF_READONLY, cpu_count); PL_set_prolog_flag("cpu_count", PL_INTEGER, cpu_count);
} }
#endif #endif
@ -436,8 +409,7 @@ UsedMemory(void)
} }
#endif #endif
return (GD->statistics.heap + return (usedStack(global) +
usedStack(global) +
usedStack(local) + usedStack(local) +
usedStack(trail)); usedStack(trail));
} }
@ -448,8 +420,7 @@ FreeMemory(void)
{ {
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_DATA) #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_DATA)
uintptr_t used = UsedMemory(); uintptr_t used = UsedMemory();
struct rlimit limit;
struct rlimit limit;
if ( getrlimit(RLIMIT_DATA, &limit) == 0 ) if ( getrlimit(RLIMIT_DATA, &limit) == 0 )
return limit.rlim_cur - used; return limit.rlim_cur - used;
@ -470,7 +441,7 @@ FreeMemory(void)
some systems (__WINDOWS__) the seed of rand() is thread-local, while on some systems (__WINDOWS__) the seed of rand() is thread-local, while on
others it is global. We appear to have the choice between others it is global. We appear to have the choice between
# srand()/rand() # srand()/rand()
Differ in MT handling, often bad distribution Differ in MT handling, often bad distribution
# srandom()/random() # srandom()/random()
@ -522,16 +493,14 @@ _PL_Random(void)
} }
#ifdef HAVE_RANDOM #ifdef HAVE_RANDOM
#if SIZEOF_VOIDP == 4
{ uint64_t l = random(); { uint64_t l = random();
l ^= (uint64_t)random()<<32; l ^= (uint64_t)random()<<15;
l ^= (uint64_t)random()<<30;
l ^= (uint64_t)random()<<45;
return l; return l;
} }
#else
return random();
#endif
#else #else
{ uint64_t l = rand(); /* 0<n<2^15-1 */ { uint64_t l = rand(); /* 0<n<2^15-1 */
@ -845,19 +814,16 @@ struct canonical_dir
forwards char *canoniseDir(char *); forwards char *canoniseDir(char *);
#endif /*O_CANONISE_DIRS*/ #endif /*O_CANONISE_DIRS*/
#define CWDdir (LD->os._CWDdir) /* current directory */
#define CWDlen (LD->os._CWDlen) /* strlen(CWDdir) */
static void static void
initExpand(void) initExpand(void)
{ GET_LD {
#ifdef O_CANONISE_DIRS #ifdef O_CANONISE_DIRS
char *dir; char *dir;
char *cpaths; char *cpaths;
#endif #endif
CWDdir = NULL; GD->paths.CWDdir = NULL;
CWDlen = 0; GD->paths.CWDlen = 0;
#ifdef O_CANONISE_DIRS #ifdef O_CANONISE_DIRS
{ char envbuf[MAXPATHLEN]; { char envbuf[MAXPATHLEN];
@ -898,7 +864,15 @@ cleanupExpand(void)
canonical_dirlist = NULL; canonical_dirlist = NULL;
for( ; dn; dn = next ) for( ; dn; dn = next )
{ next = dn->next; { next = dn->next;
free(dn); if ( dn->canonical && dn->canonical != dn->name )
remove_string(dn->canonical);
remove_string(dn->name);
PL_free(dn);
}
if ( GD->paths.CWDdir )
{ remove_string(GD->paths.CWDdir);
GD->paths.CWDdir = NULL;
GD->paths.CWDlen = 0;
} }
} }
@ -925,7 +899,7 @@ registerParentDirs(const char *path)
} }
if ( statfunc(OsPath(dirname, tmp), &buf) == 0 ) if ( statfunc(OsPath(dirname, tmp), &buf) == 0 )
{ CanonicalDir dn = malloc(sizeof(*dn)); { CanonicalDir dn = PL_malloc(sizeof(*dn));
dn->name = store_string(dirname); dn->name = store_string(dirname);
dn->inode = buf.st_ino; dn->inode = buf.st_ino;
@ -980,7 +954,7 @@ verify_entry(CanonicalDir d)
remove_string(d->name); remove_string(d->name);
if ( d->canonical != d->name ) if ( d->canonical != d->name )
remove_string(d->canonical); remove_string(d->canonical);
free(d); PL_free(d);
} }
return FALSE; return FALSE;
@ -1008,12 +982,12 @@ canoniseDir(char *path)
} }
/* we need to use malloc() here */ /* we need to use malloc() here */
/* because allocHeap() only ensures */ /* because allocHeapOrHalt() only ensures */
/* alignment for `word', and inode_t */ /* alignment for `word', and inode_t */
/* is sometimes bigger! */ /* is sometimes bigger! */
if ( statfunc(OsPath(path, tmp), &buf) == 0 ) if ( statfunc(OsPath(path, tmp), &buf) == 0 )
{ CanonicalDir dn = malloc(sizeof(*dn)); { CanonicalDir dn = PL_malloc(sizeof(*dn));
char dirname[MAXPATHLEN]; char dirname[MAXPATHLEN];
char *e = path + strlen(path); char *e = path + strlen(path);
@ -1082,8 +1056,7 @@ cleanupExpand(void)
char * char *
canoniseFileName(char *path) canoniseFileName(char *path)
{ char *out = path, *in = path, *start = path; { char *out = path, *in = path, *start = path;
char *osave[100]; tmp_buffer saveb;
int osavep = 0;
#ifdef O_HASDRIVES /* C: */ #ifdef O_HASDRIVES /* C: */
if ( in[1] == ':' && isLetter(in[0]) ) if ( in[1] == ':' && isLetter(in[0]) )
@ -1092,8 +1065,8 @@ canoniseFileName(char *path)
out = start = in; out = start = in;
} }
#ifdef __MINGW32__ /* /c/ in MINGW is the same as c: */ #ifdef __MINGW32__ /* /c/ in MINGW is the same as c: */
if ( in[0] == '/' && isLetter(in[1]) && else if ( in[0] == '/' && isLetter(in[1]) &&
in[2] == '/' ) in[2] == '/' )
{ {
out[0] = in[1]; out[0] = in[1];
out[1] = ':'; out[1] = ':';
@ -1101,13 +1074,13 @@ canoniseFileName(char *path)
out = start = in; out = start = in;
} }
#endif #endif
#endif #endif
#ifdef O_HASSHARES /* //host/ */ #ifdef O_HASSHARES /* //host/ */
if ( in[0] == '/' && in[1] == '/' && isAlpha(in[2]) ) if ( in[0] == '/' && in[1] == '/' && isAlpha(in[2]) )
{ char *s; { char *s;
for(s = in+3; *s && (isAlpha(*s) || *s == '.'); s++) for(s = in+3; *s && (isAlpha(*s) || *s == '-' || *s == '.'); s++)
; ;
if ( *s == '/' ) if ( *s == '/' )
{ in = out = s+1; { in = out = s+1;
@ -1122,7 +1095,8 @@ canoniseFileName(char *path)
in += 2; in += 2;
if ( in[0] == '/' ) if ( in[0] == '/' )
*out++ = '/'; *out++ = '/';
osave[osavep++] = out; initBuffer(&saveb);
addBuffer(&saveb, out, char*);
while(*in) while(*in)
{ if (*in == '/') { if (*in == '/')
@ -1138,15 +1112,15 @@ canoniseFileName(char *path)
} }
if ( in[2] == EOS ) /* delete trailing /. */ if ( in[2] == EOS ) /* delete trailing /. */
{ *out = EOS; { *out = EOS;
return path; goto out;
} }
if ( in[2] == '.' && (in[3] == '/' || in[3] == EOS) ) if ( in[2] == '.' && (in[3] == '/' || in[3] == EOS) )
{ if ( osavep > 0 ) /* delete /foo/../ */ { if ( !isEmptyBuffer(&saveb) ) /* delete /foo/../ */
{ out = osave[--osavep]; { out = popBuffer(&saveb, char*);
in += 3; in += 3;
if ( in[0] == EOS && out > start+1 ) if ( in[0] == EOS && out > start+1 )
{ out[-1] = EOS; /* delete trailing / */ { out[-1] = EOS; /* delete trailing / */
return path; goto out;
} }
goto again; goto again;
} else if ( start[0] == '/' && out == start+1 ) } else if ( start[0] == '/' && out == start+1 )
@ -1160,12 +1134,15 @@ canoniseFileName(char *path)
in++; in++;
if ( out > path && out[-1] != '/' ) if ( out > path && out[-1] != '/' )
*out++ = '/'; *out++ = '/';
osave[osavep++] = out; addBuffer(&saveb, out, char*);
} else } else
*out++ = *in++; *out++ = *in++;
} }
*out++ = *in++; *out++ = *in++;
out:
discardBuffer(&saveb);
return path; return path;
} }
@ -1201,15 +1178,18 @@ canonisePath(char *path)
#ifdef O_CANONISE_DIRS #ifdef O_CANONISE_DIRS
{ char *e; { char *e;
char dirname[MAXPATHLEN]; char dirname[MAXPATHLEN];
size_t plen = strlen(path);
e = path + strlen(path) - 1; if ( plen > 0 )
for( ; *e != '/' && e > path; e-- ) { e = path + plen - 1;
; for( ; *e != '/' && e > path; e-- )
strncpy(dirname, path, e-path); ;
dirname[e-path] = EOS; strncpy(dirname, path, e-path);
canoniseDir(dirname); dirname[e-path] = EOS;
strcat(dirname, e); canoniseDir(dirname);
strcpy(path, dirname); strcat(dirname, e);
strcpy(path, dirname);
}
} }
#endif #endif
@ -1238,11 +1218,12 @@ takeWord(const char **string, char *wrd, int maxlen)
} }
bool char *
expandVars(const char *pattern, char *expanded, int maxlen) expandVars(const char *pattern, char *expanded, int maxlen)
{ GET_LD { GET_LD
int size = 0; int size = 0;
char wordbuf[MAXPATHLEN]; char wordbuf[MAXPATHLEN];
char *rc = expanded;
if ( *pattern == '~' ) if ( *pattern == '~' )
{ char *user; { char *user;
@ -1305,7 +1286,9 @@ expandVars(const char *pattern, char *expanded, int maxlen)
#endif #endif
size += (l = (int) strlen(value)); size += (l = (int) strlen(value));
if ( size+1 >= maxlen ) if ( size+1 >= maxlen )
return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_path_length); { PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_path_length);
return NULL;
}
strcpy(expanded, value); strcpy(expanded, value);
expanded += l; expanded += l;
UNLOCK(); UNLOCK();
@ -1345,8 +1328,9 @@ expandVars(const char *pattern, char *expanded, int maxlen)
size += (l = (int)strlen(value)); size += (l = (int)strlen(value));
if ( size+1 >= maxlen ) if ( size+1 >= maxlen )
{ UNLOCK(); { UNLOCK();
return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, PL_error(NULL, 0, NULL, ERR_REPRESENTATION,
ATOM_max_path_length); ATOM_max_path_length);
return NULL;
} }
strcpy(expanded, value); strcpy(expanded, value);
UNLOCK(); UNLOCK();
@ -1359,8 +1343,10 @@ expandVars(const char *pattern, char *expanded, int maxlen)
def: def:
size++; size++;
if ( size+1 >= maxlen ) if ( size+1 >= maxlen )
return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, { PL_error(NULL, 0, NULL, ERR_REPRESENTATION,
ATOM_max_path_length); ATOM_max_path_length);
return NULL;
}
*expanded++ = c; *expanded++ = c;
continue; continue;
@ -1369,61 +1355,14 @@ expandVars(const char *pattern, char *expanded, int maxlen)
} }
if ( ++size >= maxlen ) if ( ++size >= maxlen )
return PL_error(NULL, 0, NULL, ERR_REPRESENTATION, { PL_error(NULL, 0, NULL, ERR_REPRESENTATION,
ATOM_max_path_length); ATOM_max_path_length);
return NULL;
}
*expanded = EOS; *expanded = EOS;
succeed; return rc;
}
static int
ExpandFile(const char *pattern, char **vector)
{ char expanded[MAXPATHLEN];
int matches = 0;
if ( !expandVars(pattern, expanded, sizeof(expanded)) )
return -1;
vector[matches++] = store_string(expanded);
return matches;
}
char *
ExpandOneFile(const char *spec, char *file)
{ GET_LD
char *vector[256];
int size;
switch( (size=ExpandFile(spec, vector)) )
{ case -1:
return NULL;
case 0:
{ term_t tmp = PL_new_term_ref();
PL_put_atom_chars(tmp, spec);
PL_error(NULL, 0, "no match", ERR_EXISTENCE, ATOM_file, tmp);
return NULL;
}
case 1:
strcpy(file, vector[0]);
remove_string(vector[0]);
return file;
default:
{ term_t tmp = PL_new_term_ref();
int n;
for(n=0; n<size; n++)
remove_string(vector[n]);
PL_put_atom_chars(tmp, spec);
PL_error(NULL, 0, "ambiguous", ERR_EXISTENCE, ATOM_file, tmp);
return NULL;
}
}
} }
@ -1507,7 +1446,7 @@ AbsoluteFile(const char *spec, char *path)
if ( !file ) if ( !file )
return (char *) NULL; return (char *) NULL;
if ( truePrologFlag(PLFLAG_FILEVARS) ) if ( truePrologFlag(PLFLAG_FILEVARS) )
{ if ( !(file = ExpandOneFile(buf, tmp)) ) { if ( !(file = expandVars(buf, tmp, sizeof(tmp))) )
return (char *) NULL; return (char *) NULL;
} }
@ -1530,17 +1469,17 @@ AbsoluteFile(const char *spec, char *path)
} }
#endif /*O_HASDRIVES*/ #endif /*O_HASDRIVES*/
if ( !PL_cwd() ) if ( !PL_cwd(path, MAXPATHLEN) )
return NULL; return NULL;
if ( (CWDlen + strlen(file) + 1) >= MAXPATHLEN ) if ( (GD->paths.CWDlen + strlen(file) + 1) >= MAXPATHLEN )
{ PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_path_length); { PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_path_length);
return (char *) NULL; return (char *) NULL;
} }
strcpy(path, CWDdir); strcpy(path, GD->paths.CWDdir);
if ( file[0] != EOS ) if ( file[0] != EOS )
strcpy(&path[CWDlen], file); strcpy(&path[GD->paths.CWDlen], file);
if ( strchr(file, '.') || strchr(file, '/') ) if ( strchr(file, '.') || strchr(file, '/') )
return canonisePath(path); return canonisePath(path);
else else
@ -1550,20 +1489,20 @@ AbsoluteFile(const char *spec, char *path)
void void
PL_changed_cwd(void) PL_changed_cwd(void)
{ GET_LD { LOCK();
if ( GD->paths.CWDdir )
if ( CWDdir ) remove_string(GD->paths.CWDdir);
remove_string(CWDdir); GD->paths.CWDdir = NULL;
CWDdir = NULL; GD->paths.CWDlen = 0;
CWDlen = 0; UNLOCK();
} }
const char * static char *
PL_cwd(void) cwd_unlocked(char *cwd, size_t cwdlen)
{ GET_LD { GET_LD
if ( CWDlen == 0 ) if ( GD->paths.CWDlen == 0 )
{ char buf[MAXPATHLEN]; { char buf[MAXPATHLEN];
char *rval; char *rval;
@ -1593,16 +1532,34 @@ to be implemented directly. What about other Unixes?
} }
canonisePath(buf); canonisePath(buf);
CWDlen = strlen(buf); GD->paths.CWDlen = strlen(buf);
buf[CWDlen++] = '/'; buf[GD->paths.CWDlen++] = '/';
buf[CWDlen] = EOS; buf[GD->paths.CWDlen] = EOS;
if ( CWDdir ) if ( GD->paths.CWDdir )
remove_string(CWDdir); remove_string(GD->paths.CWDdir);
CWDdir = store_string(buf); GD->paths.CWDdir = store_string(buf);
} }
return (const char *)CWDdir; if ( GD->paths.CWDlen < cwdlen )
{ memcpy(cwd, GD->paths.CWDdir, GD->paths.CWDlen+1);
return cwd;
} else
{ PL_error(NULL, 0, NULL, ERR_REPRESENTATION, ATOM_max_path_length);
return NULL;
}
}
char *
PL_cwd(char *cwd, size_t cwdlen)
{ char *rc;
LOCK();
rc = cwd_unlocked(cwd, cwdlen);
UNLOCK();
return rc;
} }
@ -1652,14 +1609,13 @@ DirName(const char *f, char *dir)
bool bool
ChDir(const char *path) ChDir(const char *path)
{ GET_LD { char ospath[MAXPATHLEN];
char ospath[MAXPATHLEN];
char tmp[MAXPATHLEN]; char tmp[MAXPATHLEN];
OsPath(path, ospath); OsPath(path, ospath);
if ( path[0] == EOS || streq(path, ".") || if ( path[0] == EOS || streq(path, ".") ||
(CWDdir && streq(path, CWDdir)) ) (GD->paths.CWDdir && streq(path, GD->paths.CWDdir)) )
succeed; succeed;
AbsoluteFile(path, tmp); AbsoluteFile(path, tmp);
@ -1672,10 +1628,12 @@ ChDir(const char *path)
{ tmp[len++] = '/'; { tmp[len++] = '/';
tmp[len] = EOS; tmp[len] = EOS;
} }
CWDlen = len; LOCK(); /* Lock with PL_changed_cwd() */
if ( CWDdir ) GD->paths.CWDlen = len; /* and PL_cwd() */
remove_string(CWDdir); if ( GD->paths.CWDdir )
CWDdir = store_string(tmp); remove_string(GD->paths.CWDdir);
GD->paths.CWDdir = store_string(tmp);
UNLOCK();
succeed; succeed;
} }
@ -1689,7 +1647,7 @@ ChDir(const char *path)
*********************************/ *********************************/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
struct tm *LocalTime(time_t time, struct tm *r) struct tm *PL_localtime_r(time_t time, struct tm *r)
Convert time in Unix internal form (seconds since Jan 1 1970) into a Convert time in Unix internal form (seconds since Jan 1 1970) into a
structure providing easier access to the time. structure providing easier access to the time.
@ -1713,17 +1671,52 @@ ChDir(const char *path)
time_t Time() time_t Time()
Return time in seconds after Jan 1 1970 (Unix' time notion). Return time in seconds after Jan 1 1970 (Unix' time notion).
Note: MinGW has localtime_r(), but it is not locked and thus not
thread-safe. MinGW does not have localtime_s(), but we test for it in
configure.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
struct tm * struct tm *
LocalTime(long *t, struct tm *r) PL_localtime_r(const time_t *t, struct tm *r)
{ {
#if defined(_REENTRANT) && defined(HAVE_LOCALTIME_R) #ifdef HAVE_LOCALTIME_R
return localtime_r(t, r); return localtime_r(t, r);
#else #else
*r = *localtime((const time_t *) t); #ifdef HAVE_LOCALTIME_S
return localtime_s(r, t) == EINVAL ? NULL : t;
#else
struct tm *rc;
LOCK();
if ( (rc = localtime(t)) )
*r = *rc;
else
r = NULL;
UNLOCK();
return r; return r;
#endif #endif
#endif
}
char *
PL_asctime_r(const struct tm *tm, char *buf)
{
#ifdef HAVE_ASCTIME_R
return asctime_r(tm, buf);
#else
char *rc;
LOCK();
if ( (rc = asctime(tm)) )
strcpy(buf, rc);
else
buf = NULL;
UNLOCK();
return buf;
#endif
} }
@ -1857,7 +1850,7 @@ PushTty(IOSTREAM *s, ttybuf *buf, int mode)
if ( !truePrologFlag(PLFLAG_TTY_CONTROL) ) if ( !truePrologFlag(PLFLAG_TTY_CONTROL) )
succeed; succeed;
buf->state = allocHeap(sizeof(tty_state)); buf->state = allocHeapOrHalt(sizeof(tty_state));
#ifdef HAVE_TCSETATTR #ifdef HAVE_TCSETATTR
if ( tcgetattr(fd, &TTY_STATE(buf)) ) /* save the old one */ if ( tcgetattr(fd, &TTY_STATE(buf)) ) /* save the old one */
@ -1915,9 +1908,7 @@ PushTty(IOSTREAM *s, ttybuf *buf, int mode)
bool bool
PopTty(IOSTREAM *s, ttybuf *buf, int do_free) PopTty(IOSTREAM *s, ttybuf *buf, int do_free)
{ GET_LD { ttymode = buf->mode;
ttymode = buf->mode;
if ( buf->state ) if ( buf->state )
{ int fd = Sfileno(s); { int fd = Sfileno(s);
@ -1963,7 +1954,7 @@ PushTty(IOSTREAM *s, ttybuf *buf, int mode)
if ( !truePrologFlag(PLFLAG_TTY_CONTROL) ) if ( !truePrologFlag(PLFLAG_TTY_CONTROL) )
succeed; succeed;
buf->state = allocHeap(sizeof(tty_state)); buf->state = allocHeapOrHalt(sizeof(tty_state));
if ( ioctl(fd, TIOCGETP, &TTY_STATE(buf)) ) /* save the old one */ if ( ioctl(fd, TIOCGETP, &TTY_STATE(buf)) ) /* save the old one */
fail; fail;
@ -2178,7 +2169,7 @@ growEnviron(char **e, int amount)
for(e1=e, filled=0; *e1; e1++, filled++) for(e1=e, filled=0; *e1; e1++, filled++)
; ;
size = ROUND(filled+10+amount, 32); size = ROUND(filled+10+amount, 32);
env = (char **)malloc(size * sizeof(char *)); env = (char **)PL_malloc(size * sizeof(char *));
for ( e1=e, e2=env; *e1; *e2++ = *e1++ ) for ( e1=e, e2=env; *e1; *e2++ = *e1++ )
; ;
*e2 = (char *) NULL; *e2 = (char *) NULL;
@ -2192,7 +2183,7 @@ growEnviron(char **e, int amount)
{ char **env, **e1, **e2; { char **env, **e1, **e2;
size += 32; size += 32;
env = (char **)realloc(e, size * sizeof(char *)); env = (char **)PL_realloc(e, size * sizeof(char *));
for ( e1=e, e2=env; *e1; *e2++ = *e1++ ) for ( e1=e, e2=env; *e1; *e2++ = *e1++ )
; ;
*e2 = (char *) NULL; *e2 = (char *) NULL;
@ -2224,9 +2215,9 @@ matchName(const char *e, const char *name)
static void static void
setEntry(char **e, char *name, char *value) setEntry(char **e, char *name, char *value)
{ int l = (int)strlen(name); { size_t l = strlen(name);
*e = (char *) malloc(l + strlen(value) + 2); *e = PL_malloc_atomic(l + strlen(value) + 2);
strcpy(*e, name); strcpy(*e, name);
e[0][l++] = '='; e[0][l++] = '=';
strcpy(&e[0][l], value); strcpy(&e[0][l], value);
@ -2292,7 +2283,7 @@ Unsetenv(char *name)
an alternative. an alternative.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(__unix__) #ifdef __unix__
#define SPECIFIC_SYSTEM 1 #define SPECIFIC_SYSTEM 1
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -2465,30 +2456,15 @@ char *command;
#endif #endif
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[candidate]
exec(+Cmd, [+In, +Out, +Error], -Pid)
The streams may be one of standard stream, std, null stream, null, or
pipe(S), where S is a pipe stream
Detach if none is std!
TBD: Sort out status. The above is SICStus 3. YAP uses `Status' for last
argument (strange). SICStus 4 appears to drop this altogether.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
char *Symbols(char *buf) char *findExecutable(char *buf)
Return the path name of the executable of SWI-Prolog. Return the path name of the executable of SWI-Prolog.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef __WINDOWS__ /* Win32 version in pl-nt.c */ #ifndef __WINDOWS__ /* Win32 version in pl-nt.c */
static char * Which(const char *program, char *fullname);
char * char *
findExecutable(const char *av0, char *buffer) findExecutable(const char *av0, char *buffer)
@ -2500,7 +2476,7 @@ findExecutable(const char *av0, char *buffer)
return NULL; return NULL;
file = Which(buf, tmp); file = Which(buf, tmp);
#if __unix__ /* argv[0] can be an #! script! */ #if __unix__ /* argv[0] can be an #! script! */
if ( file ) if ( file )
{ int n, fd; { int n, fd;
char buf[MAXPATHLEN]; char buf[MAXPATHLEN];
@ -2532,14 +2508,8 @@ findExecutable(const char *av0, char *buffer)
return strcpy(buffer, file ? file : buf); return strcpy(buffer, file ? file : buf);
} }
#endif /*__WINDOWS__*/
#ifdef __unix__
#if defined(OS2) || defined(__DOS__) || defined(__WINDOWS__)
#define EXEC_EXTENSIONS { ".exe", ".com", ".bat", ".cmd", NULL }
#define PATHSEP ';'
#else
/* not Windows, must be a Linux-like thingy */
static char * static char *
okToExec(const char *s) okToExec(const char *s)
{ statstruct stbuff; { statstruct stbuff;
@ -2552,6 +2522,11 @@ okToExec(const char *s)
return (char *) NULL; return (char *) NULL;
} }
#define PATHSEP ':' #define PATHSEP ':'
#endif /* __unix__ */
#if defined(OS2) || defined(__DOS__) || defined(__WINDOWS__)
#define EXEC_EXTENSIONS { ".exe", ".com", ".bat", ".cmd", NULL }
#define PATHSEP ';'
#endif #endif
#ifdef EXEC_EXTENSIONS #ifdef EXEC_EXTENSIONS
@ -2636,6 +2611,7 @@ Which(const char *program, char *fullname)
return NULL; return NULL;
} }
#endif /*__WINDOWS__*/
/** int Pause(double time) /** int Pause(double time)

View File

@ -1,11 +1,10 @@
/* $Id$ /* Part of SWI-Prolog
Part of SWI-Prolog
Author: Jan Wielemaker Author: Jan Wielemaker
E-mail: J.wielemaker@uva.nl E-mail: J.wielemaker@vu.nl
WWW: http://www.swi-prolog.org WWW: http://www.swi-prolog.org
Copyright (C): 1985-2008, University of Amsterdam Copyright (C): 1985-2012, University of Amsterdam
VU University Amsterdam
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -19,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/*#define O_DEBUG 1*/ /*#define O_DEBUG 1*/
@ -80,6 +79,8 @@ static void setTZPrologFlag(void);
static void setVersionPrologFlag(void); static void setVersionPrologFlag(void);
#endif #endif
static atom_t lookupAtomFlag(atom_t key); static atom_t lookupAtomFlag(atom_t key);
static void initPrologFlagTable(void);
typedef struct _prolog_flag typedef struct _prolog_flag
{ short flags; /* Type | Flags */ { short flags; /* Type | Flags */
@ -138,7 +139,7 @@ setPrologFlag(const char *name, int flags, ...)
if ( flags & FF_KEEP ) if ( flags & FF_KEEP )
return; return;
} else } else
{ f = allocHeap(sizeof(*f)); { f = allocHeapOrHalt(sizeof(*f));
f->index = -1; f->index = -1;
f->flags = flags; f->flags = flags;
addHTable(GD->prolog_flag.table, (void *)an, f); addHTable(GD->prolog_flag.table, (void *)an, f);
@ -155,7 +156,8 @@ setPrologFlag(const char *name, int flags, ...)
val = (f->value.a == ATOM_true); val = (f->value.a == ATOM_true);
} else if ( !s ) /* 1st definition */ } else if ( !s ) /* 1st definition */
{ f->index = indexOfBoolMask(mask); { f->index = indexOfBoolMask(mask);
DEBUG(2, Sdprintf("Prolog flag %s at 0x%08lx\n", name, mask)); DEBUG(MSG_PROLOG_FLAG,
Sdprintf("Prolog flag %s at 0x%08lx\n", name, mask));
} }
f->value.a = (val ? ATOM_true : ATOM_false); f->value.a = (val ? ATOM_true : ATOM_false);
@ -211,12 +213,20 @@ setPrologFlag(const char *name, int flags, ...)
} }
static void
freePrologFlag(prolog_flag *f)
{ if ( (f->flags & FT_MASK) == FT_TERM )
PL_erase(f->value.t);
freeHeap(f, sizeof(*f));
}
#ifdef O_PLMT #ifdef O_PLMT
static void static void
copySymbolPrologFlagTable(Symbol s) copySymbolPrologFlagTable(Symbol s)
{ GET_LD { prolog_flag *f = s->value;
prolog_flag *f = s->value; prolog_flag *copy = allocHeapOrHalt(sizeof(*copy));
prolog_flag *copy = allocHeap(sizeof(*copy));
*copy = *f; *copy = *f;
if ( (f->flags & FT_MASK) == FT_TERM ) if ( (f->flags & FT_MASK) == FT_TERM )
@ -227,13 +237,7 @@ copySymbolPrologFlagTable(Symbol s)
static void static void
freeSymbolPrologFlagTable(Symbol s) freeSymbolPrologFlagTable(Symbol s)
{ GET_LD { freePrologFlag(s->value);
prolog_flag *f = s->value;
if ( (f->flags & FT_MASK) == FT_TERM )
PL_erase(f->value.t);
freeHeap(f, sizeof(*f));
} }
#endif #endif
@ -267,25 +271,34 @@ setDoubleQuotes(atom_t a, unsigned int *flagp)
static int static int
setUnknown(atom_t a, unsigned int *flagp) setUnknown(term_t value, atom_t a, Module m)
{ unsigned int flags; { unsigned int flags = m->flags & ~(UNKNOWN_MASK);
if ( a == ATOM_error ) if ( a == ATOM_error )
flags = UNKNOWN_ERROR; flags |= UNKNOWN_ERROR;
else if ( a == ATOM_warning ) else if ( a == ATOM_warning )
flags = UNKNOWN_WARNING; flags |= UNKNOWN_WARNING;
else if ( a == ATOM_fail ) else if ( a == ATOM_fail )
flags = UNKNOWN_FAIL; flags |= UNKNOWN_FAIL;
else else
{ GET_LD
term_t value = PL_new_term_ref();
PL_put_atom(value, a);
return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_unknown, value); return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_unknown, value);
if ( !(flags&UNKNOWN_ERROR) && (m == MODULE_user || m == MODULE_system) )
{ GET_LD
if ( m == MODULE_system && !SYSTEM_MODE )
{ term_t key = PL_new_term_ref();
PL_put_atom(key, ATOM_unknown);
return PL_error(NULL, 0, NULL, ERR_PERMISSION,
ATOM_modify, ATOM_flag, key);
}
if ( !SYSTEM_MODE )
printMessage(ATOM_warning, PL_CHARS, "unknown_in_module_user");
} }
*flagp &= ~(UNKNOWN_MASK); m->flags = flags;
*flagp |= flags;
succeed; succeed;
} }
@ -308,6 +321,21 @@ setWriteAttributes(atom_t a)
} }
static int
setAccessLevelFromAtom(atom_t a)
{ GET_LD
if ( getAccessLevelMask(a, &LD->prolog_flag.access_level) )
{ succeed;
} else
{ term_t value = PL_new_term_ref();
PL_put_atom(value, a);
return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_access_level, value);
}
}
static int static int
getOccursCheckMask(atom_t a, occurs_check_t *val) getOccursCheckMask(atom_t a, occurs_check_t *val)
{ if ( a == ATOM_false ) { if ( a == ATOM_false )
@ -357,6 +385,30 @@ setEncoding(atom_t a)
} }
static int
setStreamTypeCheck(atom_t a)
{ GET_LD
st_check check;
if ( a == ATOM_false )
check = ST_FALSE;
else if ( a == ATOM_loose )
check = ST_LOOSE;
else if ( a == ATOM_true )
check = ST_TRUE;
else
{ term_t value = PL_new_term_ref();
PL_put_atom(value, a);
return PL_error(NULL, 0, NULL, ERR_DOMAIN, ATOM_stream_type_check, value);
}
LD->IO.stream_type_check = check;
return TRUE;
}
static word static word
set_prolog_flag_unlocked(term_t key, term_t value, int flags) set_prolog_flag_unlocked(term_t key, term_t value, int flags)
{ GET_LD { GET_LD
@ -385,7 +437,7 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
#ifdef O_PLMT #ifdef O_PLMT
if ( GD->statistics.threads_created > 1 ) if ( GD->statistics.threads_created > 1 )
{ prolog_flag *f2 = allocHeap(sizeof(*f2)); { prolog_flag *f2 = allocHeapOrHalt(sizeof(*f2));
*f2 = *f; *f2 = *f;
if ( (f2->flags & FT_MASK) == FT_TERM ) if ( (f2->flags & FT_MASK) == FT_TERM )
@ -399,7 +451,8 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
} }
addHTable(LD->prolog_flag.table, (void *)k, f2); addHTable(LD->prolog_flag.table, (void *)k, f2);
DEBUG(1, Sdprintf("Localised Prolog flag %s\n", PL_atom_chars(k))); DEBUG(MSG_PROLOG_FLAG,
Sdprintf("Localised Prolog flag %s\n", PL_atom_chars(k)));
f = f2; f = f2;
} }
#endif #endif
@ -411,7 +464,7 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
anyway: anyway:
PL_register_atom(k); PL_register_atom(k);
f = allocHeap(sizeof(*f)); f = allocHeapOrHalt(sizeof(*f));
f->index = -1; f->index = -1;
switch( (flags & FT_MASK) ) switch( (flags & FT_MASK) )
@ -437,8 +490,9 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
goto wrong_type; goto wrong_type;
} }
if ( !(f->value.t = PL_record(value)) ) if ( !(f->value.t = PL_record(value)) )
goto wrong_type; { freeHeap(f, sizeof(*f));
f->value.t = PL_record(value); return FALSE;
}
} }
break; break;
} }
@ -483,7 +537,10 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
if ( (flags & FF_READONLY) ) if ( (flags & FF_READONLY) )
f->flags |= FF_READONLY; f->flags |= FF_READONLY;
addHTable(GD->prolog_flag.table, (void *)k, f); if ( !addHTable(GD->prolog_flag.table, (void *)k, f) )
{ freePrologFlag(f);
Sdprintf("OOPS; failed to set Prolog flag!?\n");
}
succeed; succeed;
} else } else
@ -516,9 +573,9 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
#ifndef __YAP_PROLOG__ #ifndef __YAP_PROLOG__
if ( k == ATOM_character_escapes ) if ( k == ATOM_character_escapes )
{ if ( val ) { if ( val )
set(m, CHARESCAPE); set(m, M_CHARESCAPE);
else else
clear(m, CHARESCAPE); clear(m, M_CHARESCAPE);
} else if ( k == ATOM_debug ) } else if ( k == ATOM_debug )
{ if ( val ) { if ( val )
{ debugmode(DBG_ALL, NULL); { debugmode(DBG_ALL, NULL);
@ -551,15 +608,19 @@ set_prolog_flag_unlocked(term_t key, term_t value, int flags)
if ( k == ATOM_double_quotes ) if ( k == ATOM_double_quotes )
{ rval = setDoubleQuotes(a, &m->flags); { rval = setDoubleQuotes(a, &m->flags);
} else if ( k == ATOM_unknown ) } else if ( k == ATOM_unknown )
{ rval = setUnknown(a, &m->flags); { rval = setUnknown(value, a, m);
} else if ( k == ATOM_write_attributes ) } else if ( k == ATOM_write_attributes )
{ rval = setWriteAttributes(a); { rval = setWriteAttributes(a);
} else if ( k == ATOM_occurs_check ) } else if ( k == ATOM_occurs_check )
{ rval = setOccursCheck(a); { rval = setOccursCheck(a);
} else } else if ( k == ATOM_access_level )
{ rval = setAccessLevelFromAtom(a);
} else
#endif #endif
if ( k == ATOM_encoding ) if ( k == ATOM_encoding )
{ rval = setEncoding(a); { rval = setEncoding(a);
} else if ( k == ATOM_stream_type_check )
{ rval = setStreamTypeCheck(a);
} }
if ( !rval ) if ( !rval )
fail; fail;
@ -705,7 +766,7 @@ unify_prolog_flag_value(Module m, atom_t key, prolog_flag *f, term_t val)
#ifndef __YAP_PROLOG__ #ifndef __YAP_PROLOG__
if ( key == ATOM_character_escapes ) if ( key == ATOM_character_escapes )
{ atom_t v = (true(m, CHARESCAPE) ? ATOM_true : ATOM_false); { atom_t v = (true(m, M_CHARESCAPE) ? ATOM_true : ATOM_false);
return PL_unify_atom(val, v); return PL_unify_atom(val, v);
} else if ( key == ATOM_double_quotes ) } else if ( key == ATOM_double_quotes )
@ -736,6 +797,7 @@ unify_prolog_flag_value(Module m, atom_t key, prolog_flag *f, term_t val)
break; break;
default: default:
assert(0); assert(0);
return FALSE;
} }
return PL_unify_atom(val, v); return PL_unify_atom(val, v);
@ -747,6 +809,14 @@ unify_prolog_flag_value(Module m, atom_t key, prolog_flag *f, term_t val)
{ return PL_unify_bool_ex(val, debugstatus.debugging); { return PL_unify_bool_ex(val, debugstatus.debugging);
} else if ( key == ATOM_debugger_show_context ) } else if ( key == ATOM_debugger_show_context )
{ return PL_unify_bool_ex(val, debugstatus.showContext); { return PL_unify_bool_ex(val, debugstatus.showContext);
} else if ( key == ATOM_break_level )
{ int bl = currentBreakLevel();
if ( bl >= 0 )
return PL_unify_integer(val, bl);
return FALSE;
} else if ( key == ATOM_access_level )
{ return PL_unify_atom(val, accessLevel());
} }
#endif /* YAP_PROLOG */ #endif /* YAP_PROLOG */
@ -861,7 +931,7 @@ pl_prolog_flag5(term_t key, term_t value,
fail; fail;
} else if ( PL_is_variable(key) ) } else if ( PL_is_variable(key) )
{ e = allocHeap(sizeof(*e)); { e = allocHeapOrHalt(sizeof(*e));
e->module = module; e->module = module;
@ -965,7 +1035,7 @@ pl_prolog_flag(term_t name, term_t value, control_t h)
#define SO_PATH "LD_LIBRARY_PATH" #define SO_PATH "LD_LIBRARY_PATH"
#endif #endif
void static void
initPrologFlagTable(void) initPrologFlagTable(void)
{ if ( !GD->prolog_flag.table ) { if ( !GD->prolog_flag.table )
{ {
@ -973,7 +1043,7 @@ initPrologFlagTable(void)
initPrologThreads(); /* may be called before PL_initialise() */ initPrologThreads(); /* may be called before PL_initialise() */
#endif #endif
GD->prolog_flag.table = newHTable(32); GD->prolog_flag.table = newHTable(64);
} }
} }
@ -983,7 +1053,7 @@ initPrologFlags(void)
{ GET_LD { GET_LD
#ifndef __YAP_PROLOG__ #ifndef __YAP_PROLOG__
setPrologFlag("iso", FT_BOOL, FALSE, PLFLAG_ISO); setPrologFlag("iso", FT_BOOL, FALSE, PLFLAG_ISO);
setPrologFlag("arch", FT_ATOM|FF_READONLY, ARCH); setPrologFlag("arch", FT_ATOM|FF_READONLY, PLARCH);
#if __WINDOWS__ #if __WINDOWS__
setPrologFlag("windows", FT_BOOL|FF_READONLY, TRUE, 0); setPrologFlag("windows", FT_BOOL|FF_READONLY, TRUE, 0);
#endif #endif
@ -996,12 +1066,17 @@ initPrologFlags(void)
#if defined(HAVE_GETPID) || defined(EMULATE_GETPID) #if defined(HAVE_GETPID) || defined(EMULATE_GETPID)
setPrologFlag("pid", FT_INTEGER|FF_READONLY, getpid()); setPrologFlag("pid", FT_INTEGER|FF_READONLY, getpid());
#endif #endif
setPrologFlag("optimise", FT_BOOL, GD->cmdline.optimise, PLFLAG_OPTIMISE);
setPrologFlag("generate_debug_info", FT_BOOL, setPrologFlag("generate_debug_info", FT_BOOL,
truePrologFlag(PLFLAG_DEBUGINFO), PLFLAG_DEBUGINFO); truePrologFlag(PLFLAG_DEBUGINFO), PLFLAG_DEBUGINFO);
setPrologFlag("last_call_optimisation", FT_BOOL, TRUE, PLFLAG_LASTCALL); setPrologFlag("last_call_optimisation", FT_BOOL, TRUE, PLFLAG_LASTCALL);
setPrologFlag("c_libs", FT_ATOM|FF_READONLY, C_LIBS); setPrologFlag("warn_override_implicit_import", FT_BOOL, TRUE,
setPrologFlag("c_cc", FT_ATOM|FF_READONLY, C_CC); PLFLAG_WARN_OVERRIDE_IMPLICIT_IMPORT);
setPrologFlag("c_ldflags", FT_ATOM|FF_READONLY, C_LDFLAGS); setPrologFlag("c_cc", FT_ATOM, C_CC);
setPrologFlag("c_libs", FT_ATOM, C_LIBS);
setPrologFlag("c_libplso", FT_ATOM, C_LIBPLSO);
setPrologFlag("c_ldflags", FT_ATOM, C_LDFLAGS);
setPrologFlag("c_cflags", FT_ATOM, C_CFLAGS);
#if defined(O_LARGEFILES) || SIZEOF_LONG == 8 #if defined(O_LARGEFILES) || SIZEOF_LONG == 8
setPrologFlag("large_files", FT_BOOL|FF_READONLY, TRUE, 0); setPrologFlag("large_files", FT_BOOL|FF_READONLY, TRUE, 0);
#endif #endif
@ -1041,6 +1116,7 @@ initPrologFlags(void)
setPrologFlag("debug_on_error", FT_BOOL, TRUE, PLFLAG_DEBUG_ON_ERROR); setPrologFlag("debug_on_error", FT_BOOL, TRUE, PLFLAG_DEBUG_ON_ERROR);
setPrologFlag("report_error", FT_BOOL, TRUE, PLFLAG_REPORT_ERROR); setPrologFlag("report_error", FT_BOOL, TRUE, PLFLAG_REPORT_ERROR);
#endif #endif
setPrologFlag("break_level", FT_INTEGER|FF_READONLY, 0, 0);
setPrologFlag("user_flags", FT_ATOM, "silent"); setPrologFlag("user_flags", FT_ATOM, "silent");
setPrologFlag("editor", FT_ATOM, "default"); setPrologFlag("editor", FT_ATOM, "default");
setPrologFlag("debugger_show_context", FT_BOOL, FALSE, 0); setPrologFlag("debugger_show_context", FT_BOOL, FALSE, 0);
@ -1065,28 +1141,39 @@ initPrologFlags(void)
setPrologFlag("integer_rounding_function", FT_ATOM|FF_READONLY, "toward_zero"); setPrologFlag("integer_rounding_function", FT_ATOM|FF_READONLY, "toward_zero");
setPrologFlag("max_arity", FT_ATOM|FF_READONLY, "unbounded"); setPrologFlag("max_arity", FT_ATOM|FF_READONLY, "unbounded");
setPrologFlag("answer_format", FT_ATOM, "~p"); setPrologFlag("answer_format", FT_ATOM, "~p");
setPrologFlag("colon_sets_calling_context", FT_BOOL, TRUE, 0);
setPrologFlag("character_escapes", FT_BOOL, TRUE, PLFLAG_CHARESCAPE); setPrologFlag("character_escapes", FT_BOOL, TRUE, PLFLAG_CHARESCAPE);
setPrologFlag("char_conversion", FT_BOOL, FALSE, PLFLAG_CHARCONVERSION); setPrologFlag("char_conversion", FT_BOOL, FALSE, PLFLAG_CHARCONVERSION);
setPrologFlag("backquoted_string", FT_BOOL, FALSE, PLFLAG_BACKQUOTED_STRING); setPrologFlag("backquoted_string", FT_BOOL, FALSE, PLFLAG_BACKQUOTED_STRING);
setPrologFlag("write_attributes", FT_ATOM, "ignore"); setPrologFlag("write_attributes", FT_ATOM, "ignore");
setPrologFlag("stream_type_check", FT_ATOM, "loose");
setPrologFlag("occurs_check", FT_ATOM, "false"); setPrologFlag("occurs_check", FT_ATOM, "false");
setPrologFlag("access_level", FT_ATOM, "user");
setPrologFlag("double_quotes", FT_ATOM, "codes"); setPrologFlag("double_quotes", FT_ATOM, "codes");
setPrologFlag("unknown", FT_ATOM, "error"); setPrologFlag("unknown", FT_ATOM, "error");
setPrologFlag("debug", FT_BOOL, FALSE, 0); setPrologFlag("debug", FT_BOOL, FALSE, 0);
setPrologFlag("verbose", FT_ATOM|FF_KEEP, GD->options.silent ? "silent" : "normal"); setPrologFlag("verbose", FT_ATOM|FF_KEEP, GD->options.silent ? "silent" : "normal");
setPrologFlag("verbose_load", FT_BOOL, TRUE, 0); setPrologFlag("verbose_load", FT_ATOM, "normal");
setPrologFlag("verbose_autoload", FT_BOOL, FALSE, 0); setPrologFlag("verbose_autoload", FT_BOOL, FALSE, 0);
setPrologFlag("verbose_file_search", FT_BOOL, FALSE, 0); setPrologFlag("verbose_file_search", FT_BOOL, FALSE, 0);
setPrologFlag("allow_variable_name_as_functor", FT_BOOL, FALSE, setPrologFlag("allow_variable_name_as_functor", FT_BOOL, FALSE,
ALLOW_VARNAME_FUNCTOR); ALLOW_VARNAME_FUNCTOR);
setPrologFlag("toplevel_var_size", FT_INTEGER, 1000); setPrologFlag("toplevel_var_size", FT_INTEGER, 1000);
setPrologFlag("toplevel_print_anon", FT_BOOL, TRUE, 0); setPrologFlag("toplevel_print_anon", FT_BOOL, TRUE, 0);
setPrologFlag("toplevel_prompt", FT_ATOM, "~m~d~l~! ?- ");
setPrologFlag("file_name_variables", FT_BOOL, FALSE, PLFLAG_FILEVARS);
setPrologFlag("fileerrors", FT_BOOL, TRUE, PLFLAG_FILEERRORS);
#ifdef __unix__ #ifdef __unix__
setPrologFlag("unix", FT_BOOL|FF_READONLY, TRUE, 0); setPrologFlag("unix", FT_BOOL|FF_READONLY, TRUE, 0);
#endif #endif
setPrologFlag("encoding", FT_ATOM, stringAtom(encoding_to_atom(LD->encoding)));
setPrologFlag("tty_control", FT_BOOL,
truePrologFlag(PLFLAG_TTY_CONTROL), PLFLAG_TTY_CONTROL);
setPrologFlag("signals", FT_BOOL|FF_READONLY, setPrologFlag("signals", FT_BOOL|FF_READONLY,
truePrologFlag(PLFLAG_SIGNALS), PLFLAG_SIGNALS); truePrologFlag(PLFLAG_SIGNALS), PLFLAG_SIGNALS);
setPrologFlag("readline", FT_BOOL/*|FF_READONLY*/, FALSE, 0);
#if defined(__WINDOWS__) && defined(_DEBUG) #if defined(__WINDOWS__) && defined(_DEBUG)
setPrologFlag("kernel_compile_mode", FT_ATOM|FF_READONLY, "debug"); setPrologFlag("kernel_compile_mode", FT_ATOM|FF_READONLY, "debug");
@ -1124,7 +1211,7 @@ initPrologFlags(void)
#ifndef __YAP_PROLOG__ #ifndef __YAP_PROLOG__
static void static void
setArgvPrologFlag() setArgvPrologFlag(void)
{ GET_LD { GET_LD
fid_t fid = PL_open_foreign_frame(); fid_t fid = PL_open_foreign_frame();
term_t e = PL_new_term_ref(); term_t e = PL_new_term_ref();
@ -1148,7 +1235,7 @@ setArgvPrologFlag()
#endif #endif
static void static void
setTZPrologFlag() setTZPrologFlag(void)
{ tzset(); { tzset();
setPrologFlag("timezone", FT_INTEGER|FF_READONLY, timezone); setPrologFlag("timezone", FT_INTEGER|FF_READONLY, timezone);
@ -1166,7 +1253,7 @@ setVersionPrologFlag(void)
int patch = (PLVERSION%100); int patch = (PLVERSION%100);
if ( !PL_unify_term(t, if ( !PL_unify_term(t,
PL_FUNCTOR_CHARS, "swi", 4, PL_FUNCTOR_CHARS, PLNAME, 4,
PL_INT, major, PL_INT, major,
PL_INT, minor, PL_INT, minor,
PL_INT, patch, PL_INT, patch,
@ -1179,6 +1266,19 @@ setVersionPrologFlag(void)
setGITVersion(); setGITVersion();
} }
#endif /* YAP_PROLOG */ #endif /* YAP_PROLOG */
void
cleanupPrologFlags(void)
{ if ( GD->prolog_flag.table )
{ Table t = GD->prolog_flag.table;
GD->prolog_flag.table = NULL;
t->free_symbol = freeSymbolPrologFlagTable;
destroyHTable(t);
}
}
/******************************* /*******************************
* PUBLISH PREDICATES * * PUBLISH PREDICATES *
*******************************/ *******************************/

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -40,7 +40,7 @@ SWI-Prolog.h and SWI-Stream.h
#include "SWI-Stream.h" #include "SWI-Stream.h"
#include "SWI-Prolog.h" #include "SWI-Prolog.h"
#if defined(__WINDOWS__) && !defined(__YAP_PROLOG__) #ifdef __WINDOWS__
#ifdef WIN64 #ifdef WIN64
#include "config/win64.h" #include "config/win64.h"
#else #else
@ -102,7 +102,6 @@ extern void add_history(char *); /* should be in readline.h */
extern int rl_begin_undo_group(void); /* delete when conflict arrises! */ extern int rl_begin_undo_group(void); /* delete when conflict arrises! */
extern int rl_end_undo_group(void); extern int rl_end_undo_group(void);
extern Function *rl_event_hook; extern Function *rl_event_hook;
#ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION #ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION
#define rl_filename_completion_function filename_completion_function #define rl_filename_completion_function filename_completion_function
extern char *filename_completion_function(const char *, int); extern char *filename_completion_function(const char *, int);
@ -368,7 +367,6 @@ input_on_fd(int fd)
return select(fd+1, &rfds, NULL, NULL, &tv) != 0; return select(fd+1, &rfds, NULL, NULL, &tv) != 0;
} }
static int static int
event_hook(void) event_hook(void)
{ if ( Sinput->position ) { if ( Sinput->position )
@ -487,9 +485,8 @@ Sread_readline(void *handle, char *buf, size_t size)
rl_prep_terminal(FALSE); rl_prep_terminal(FALSE);
rl_readline_state = state; rl_readline_state = state;
rl_done = 0; rl_done = 0;
} else { } else
line = pl_readline(prompt); line = pl_readline(prompt);
}
in_readline--; in_readline--;
if ( my_prompt ) if ( my_prompt )
@ -515,31 +512,26 @@ Sread_readline(void *handle, char *buf, size_t size)
} }
} }
#ifdef HAVE_CLOCK
PL_clock_wait_ticks(clock() - oldclock);
#endif
return rval; return rval;
} }
static int static int
prolog_complete(int ignore, int key) prolog_complete(int ignore, int key)
{ { if ( rl_point > 0 && rl_line_buffer[rl_point-1] != ' ' )
if ( rl_point > 0 && rl_line_buffer[rl_point-1] != ' ' ) { rl_begin_undo_group();
{ rl_begin_undo_group(); rl_complete(ignore, key);
rl_complete(ignore, key); if ( rl_point > 0 && rl_line_buffer[rl_point-1] == ' ' )
if ( rl_point > 0 && rl_line_buffer[rl_point-1] == ' ' ) {
{
#ifdef HAVE_RL_INSERT_CLOSE /* actually version >= 1.2 */ #ifdef HAVE_RL_INSERT_CLOSE /* actually version >= 1.2 */
rl_delete_text(rl_point-1, rl_point); rl_delete_text(rl_point-1, rl_point);
rl_point -= 1; rl_point -= 1;
#else #else
rl_delete(-1, key); rl_delete(-1, key);
#endif #endif
} }
rl_end_undo_group(); rl_end_undo_group();
} else } else
rl_complete(ignore, key); rl_complete(ignore, key);
return 0; return 0;
@ -551,7 +543,12 @@ atom_generator(const char *prefix, int state)
{ char *s = PL_atom_generator(prefix, state); { char *s = PL_atom_generator(prefix, state);
if ( s ) if ( s )
return strcpy(PL_malloc(1 + strlen(s)), s); { char *copy = malloc(1 + strlen(s));
if ( copy ) /* else pretend no completion */
strcpy(copy, s);
s = copy;
}
return s; return s;
} }
@ -574,20 +571,26 @@ prolog_completion(const char *text, int start, int end)
#undef read /* UXNT redefinition */ #undef read /* UXNT redefinition */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
For some obscure reasons, notably libreadline 6 can show very bad
interactive behaviour. There is a timeout set to 100000 (0.1 sec). It
isn't particularly clear what this timeout is doing. I _think_ it should
be synchronized PL_dispatch_hook(), and set to 0 if this hook is
non-null.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
install_t install_t
PL_install_readline(void) PL_install_readline(void)
{ GET_LD { GET_LD
bool old; access_level_t alevel;
#ifndef __WINDOWS__ #ifndef __WINDOWS__
if ( !truePrologFlag(PLFLAG_TTY_CONTROL) || !isatty(0) ) if ( !truePrologFlag(PLFLAG_TTY_CONTROL) || !isatty(0) )
return; return;
#endif #endif
old = systemMode(TRUE); alevel = setAccessLevel(ACCESS_LEVEL_SYSTEM);
#if HAVE_DECL_RL_CATCH_SIGNALS
rl_catch_signals = 0; rl_catch_signals = 0;
#endif
rl_readline_name = "Prolog"; rl_readline_name = "Prolog";
rl_attempted_completion_function = prolog_completion; rl_attempted_completion_function = prolog_completion;
#ifdef __WINDOWS__ #ifdef __WINDOWS__
@ -599,6 +602,9 @@ PL_install_readline(void)
#if HAVE_RL_INSERT_CLOSE #if HAVE_RL_INSERT_CLOSE
rl_add_defun("insert-close", rl_insert_close, ')'); rl_add_defun("insert-close", rl_insert_close, ')');
#endif #endif
#if HAVE_RL_SET_KEYBOARD_INPUT_TIMEOUT /* see (*) */
rl_set_keyboard_input_timeout(20000);
#endif
GD->os.rl_functions = *Sinput->functions; /* structure copy */ GD->os.rl_functions = *Sinput->functions; /* structure copy */
GD->os.rl_functions.read = Sread_readline; /* read through readline */ GD->os.rl_functions.read = Sread_readline; /* read through readline */
@ -607,14 +613,17 @@ PL_install_readline(void)
Soutput->functions = &GD->os.rl_functions; Soutput->functions = &GD->os.rl_functions;
Serror->functions = &GD->os.rl_functions; Serror->functions = &GD->os.rl_functions;
PL_register_foreign("rl_read_init_file", 1, pl_rl_read_init_file, 0); #define PRED(name, arity, func, attr) \
PL_register_foreign("rl_add_history", 1, pl_rl_add_history, PL_FA_NOTRACE); PL_register_foreign_in_module("system", name, arity, func, attr)
PL_register_foreign("rl_write_history", 1, pl_rl_write_history, 0);
PL_register_foreign("rl_read_history", 1, pl_rl_read_history, 0); PRED("rl_read_init_file", 1, pl_rl_read_init_file, 0);
PRED("rl_add_history", 1, pl_rl_add_history, PL_FA_NOTRACE);
PRED("rl_write_history", 1, pl_rl_write_history, 0);
PRED("rl_read_history", 1, pl_rl_read_history, 0);
PL_set_prolog_flag("readline", PL_BOOL, TRUE); PL_set_prolog_flag("readline", PL_BOOL, TRUE);
PL_set_prolog_flag("tty_control", PL_BOOL, TRUE); PL_set_prolog_flag("tty_control", PL_BOOL, TRUE);
PL_license("gpl", "GNU Readline library"); PL_license("gpl", "GNU Readline library");
systemMode(old); setAccessLevel(alevel);
} }
#else /*HAVE_LIBREADLINE*/ #else /*HAVE_LIBREADLINE*/

View File

@ -1,11 +1,10 @@
/* $Id$ /* Part of SWI-Prolog
Part of SWI-Prolog
Author: Jan Wielemaker Author: Jan Wielemaker
E-mail: J.Wielemaker@uva.nl E-mail: J.Wielemaker@vu.nl
WWW: http://www.swi-prolog.org WWW: http://www.swi-prolog.org
Copyright (C): 1985-2009, University of Amsterdam Copyright (C): 1985-2012, University of Amsterdam
VU University Amsterdam
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -19,21 +18,21 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#if defined(__WINDOWS__)||defined(__WIN32) #ifdef __WINDOWS__
#include <windows/uxnt.h> #include "windows/uxnt.h"
#ifndef _YAP_NOT_INSTALLED_
#ifdef WIN64 #ifdef WIN64
#define MD "config/win64.h" #include "config/win64.h"
#else #else
#define MD "config/win32.h" #include "config/win32.h"
#endif
#endif #endif
#include <winsock2.h> #include <winsock2.h>
#include "windows/mswchar.h" #include "windows/mswchar.h"
#define CRLF_MAPPING 1 #define CRLF_MAPPING 1
#else
#include <config.h>
#endif #endif
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -48,12 +47,6 @@ recursive locks. If a stream handle might be known to another thread
locking is required. locking is required.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifdef MD
#include MD
#else
#include <config.h>
#endif
#if _FILE_OFFSET_BITS == 64 || defined(_LARGE_FILES) #if _FILE_OFFSET_BITS == 64 || defined(_LARGE_FILES)
#define O_LARGEFILES 1 /* use for conditional code in Prolog */ #define O_LARGEFILES 1 /* use for conditional code in Prolog */
#else #else
@ -62,8 +55,9 @@ locking is required.
#define PL_KERNEL 1 #define PL_KERNEL 1
#include <wchar.h> #include <wchar.h>
typedef wchar_t pl_wchar_t; #define NEEDS_SWINSOCK
#include "SWI-Stream.h" #include "SWI-Stream.h"
#include "SWI-Prolog.h"
#include "pl-utf8.h" #include "pl-utf8.h"
#include <sys/types.h> #include <sys/types.h>
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
@ -104,7 +98,7 @@ typedef wchar_t pl_wchar_t;
#endif #endif
#define ROUND(p, n) ((((p) + (n) - 1) & ~((n) - 1))) #define ROUND(p, n) ((((p) + (n) - 1) & ~((n) - 1)))
#define UNDO_SIZE ROUND(MB_LEN_MAX, sizeof(wchar_t)) #define UNDO_SIZE ROUND(PL_MB_LEN_MAX, sizeof(wchar_t))
#ifndef FALSE #ifndef FALSE
#define FALSE 0 #define FALSE 0
@ -127,7 +121,7 @@ static int S__seterror(IOSTREAM *s);
#ifdef O_PLMT #ifdef O_PLMT
#define SLOCK(s) if ( s->mutex ) recursiveMutexLock(s->mutex) #define SLOCK(s) if ( s->mutex ) recursiveMutexLock(s->mutex)
#define SUNLOCK(s) if ( s->mutex ) recursiveMutexUnlock(s->mutex) #define SUNLOCK(s) if ( s->mutex ) recursiveMutexUnlock(s->mutex)
static inline int inline int
STRYLOCK(IOSTREAM *s) STRYLOCK(IOSTREAM *s)
{ if ( s->mutex && { if ( s->mutex &&
recursiveMutexTryLock(s->mutex) == EBUSY ) recursiveMutexTryLock(s->mutex) == EBUSY )
@ -141,13 +135,9 @@ STRYLOCK(IOSTREAM *s)
#define STRYLOCK(s) (TRUE) #define STRYLOCK(s) (TRUE)
#endif #endif
typedef void *record_t;
typedef void *Module;
typedef intptr_t term_t;
typedef intptr_t atom_t;
#include "pl-error.h" #include "pl-error.h"
extern int fatalError(const char *fm, ...); extern int fatalError(const char *fm, ...);
extern int PL_handle_signals(void); extern int PL_handle_signals(void);
extern IOENC initEncoding(void); extern IOENC initEncoding(void);
extern int reportStreamError(IOSTREAM *s); extern int reportStreamError(IOSTREAM *s);
@ -368,6 +358,69 @@ Sunlock(IOSTREAM *s)
} }
/*******************************
* TIMEOUT *
*******************************/
#ifdef HAVE_SELECT
#ifndef __WINDOWS__
typedef int SOCKET;
#define INVALID_SOCKET -1
#define Swinsock(s) Sfileno(s)
#define NFDS(n) (n+1)
#else
#define NFDS(n) (0) /* 1st arg of select is ignored */
#endif
static int
S__wait(IOSTREAM *s)
{ SOCKET fd = Swinsock(s);
fd_set wait;
struct timeval time;
int rc;
if ( fd == INVALID_SOCKET )
{ errno = EPERM; /* no permission to select */
s->flags |= SIO_FERR;
return -1;
}
time.tv_sec = s->timeout / 1000;
time.tv_usec = (s->timeout % 1000) * 1000;
FD_ZERO(&wait);
FD_SET(fd, &wait);
for(;;)
{ if ( (s->flags & SIO_INPUT) )
rc = select(NFDS(fd), &wait, NULL, NULL, &time);
else
rc = select(NFDS(fd), NULL, &wait, NULL, &time);
if ( rc < 0 && errno == EINTR )
{ if ( PL_handle_signals() < 0 )
{ errno = EPLEXCEPTION;
return -1;
}
continue;
}
break;
}
if ( rc == 0 )
{ s->flags |= (SIO_TIMEOUT|SIO_FERR);
return -1;
}
return 0; /* ok, data available */
}
#endif /*HAVE_SELECT*/
/******************************* /*******************************
* FLUSH/FILL * * FLUSH/FILL *
*******************************/ *******************************/
@ -385,7 +438,18 @@ S__flushbuf(IOSTREAM *s)
while ( from < to ) while ( from < to )
{ size_t size = (size_t)(to - from); { size_t size = (size_t)(to - from);
ssize_t n = (*s->functions->write)(s->handle, from, size); ssize_t n;
#ifdef HAVE_SELECT
s->flags &= ~SIO_TIMEOUT;
if ( s->timeout >= 0 )
{ if ( (rc=S__wait(s)) < 0 )
goto partial;
}
#endif
n = (*s->functions->write)(s->handle, from, size);
if ( n > 0 ) /* wrote some */ if ( n > 0 ) /* wrote some */
{ from += n; { from += n;
@ -398,6 +462,9 @@ S__flushbuf(IOSTREAM *s)
} }
} }
#ifdef HAVE_SELECT
partial:
#endif
if ( to == from ) /* full flush */ if ( to == from ) /* full flush */
{ rc = s->bufp - s->buffer; { rc = s->bufp - s->buffer;
s->bufp = s->buffer; s->bufp = s->buffer;
@ -442,52 +509,6 @@ S__flushbufc(int c, IOSTREAM *s)
} }
static int
Swait_for_data(IOSTREAM *s)
{ int fd = Sfileno(s);
fd_set wait;
struct timeval time;
int rc;
if ( fd < 0 )
{ errno = EPERM; /* no permission to select */
s->flags |= SIO_FERR;
return -1;
}
time.tv_sec = s->timeout / 1000;
time.tv_usec = (s->timeout % 1000) * 1000;
FD_ZERO(&wait);
#ifdef __WINDOWS__
FD_SET((SOCKET)fd, &wait);
#else
FD_SET(fd, &wait);
#endif
for(;;)
{ rc = select(fd+1, &wait, NULL, NULL, &time);
if ( rc < 0 && errno == EINTR )
{ if ( PL_handle_signals() < 0 )
{ errno = EPLEXCEPTION;
return -1;
}
continue;
}
break;
}
if ( rc == 0 )
{ s->flags |= (SIO_TIMEOUT|SIO_FERR);
return -1;
}
return 0; /* ok, data available */
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
S__fillbuf() fills the read-buffer, returning the first character of it. S__fillbuf() fills the read-buffer, returning the first character of it.
It also realises the SWI-Prolog timeout facility. It also realises the SWI-Prolog timeout facility.
@ -497,8 +518,11 @@ int
S__fillbuf(IOSTREAM *s) S__fillbuf(IOSTREAM *s)
{ int c; { int c;
if ( s->flags & (SIO_FEOF|SIO_FERR) ) if ( s->flags & (SIO_FEOF|SIO_FERR) ) /* reading past eof */
{ s->flags |= SIO_FEOF2; /* reading past eof */ { if ( s->flags & SIO_FEOF2ERR )
s->flags |= (SIO_FEOF2|SIO_FERR);
else
s->flags |= SIO_FEOF2;
return -1; return -1;
} }
@ -508,7 +532,7 @@ S__fillbuf(IOSTREAM *s)
if ( s->timeout >= 0 && !s->downstream ) if ( s->timeout >= 0 && !s->downstream )
{ int rc; { int rc;
if ( (rc=Swait_for_data(s)) < 0 ) if ( (rc=S__wait(s)) < 0 )
return rc; return rc;
} }
#endif #endif
@ -517,7 +541,8 @@ S__fillbuf(IOSTREAM *s)
{ char chr; { char chr;
ssize_t n; ssize_t n;
if ( (n=(*s->functions->read)(s->handle, &chr, 1)) == 1 ) n = (*s->functions->read)(s->handle, &chr, 1);
if ( n == 1 )
{ c = char_to_int(chr); { c = char_to_int(chr);
return c; return c;
} else if ( n == 0 ) } else if ( n == 0 )
@ -548,7 +573,8 @@ S__fillbuf(IOSTREAM *s)
len = s->bufsize; len = s->bufsize;
} }
if ( (n=(*s->functions->read)(s->handle, s->limitp, len)) > 0 ) n = (*s->functions->read)(s->handle, s->limitp, len);
if ( n > 0 )
{ s->limitp += n; { s->limitp += n;
c = char_to_int(*s->bufp++); c = char_to_int(*s->bufp++);
return c; return c;
@ -777,7 +803,7 @@ put_code(int c, IOSTREAM *s)
} }
goto simple; goto simple;
case ENC_ANSI: case ENC_ANSI:
{ char b[MB_LEN_MAX]; { char b[PL_MB_LEN_MAX];
size_t n; size_t n;
if ( !s->mbstate ) if ( !s->mbstate )
@ -863,7 +889,10 @@ Sputcode(int c, IOSTREAM *s)
if ( s->tee && s->tee->magic == SIO_MAGIC ) if ( s->tee && s->tee->magic == SIO_MAGIC )
Sputcode(c, s->tee); Sputcode(c, s->tee);
if ( c == '\n' && (s->flags&SIO_TEXT) && s->newline == SIO_NL_DOS ) if ( c == '\n' &&
(s->flags&SIO_TEXT) &&
s->newline == SIO_NL_DOS &&
s->lastc != '\r' )
{ if ( put_code('\r', s) < 0 ) { if ( put_code('\r', s) < 0 )
return -1; return -1;
} }
@ -886,7 +915,7 @@ Scanrepresent(int c, IOSTREAM *s)
return -1; return -1;
case ENC_ANSI: case ENC_ANSI:
{ mbstate_t state; { mbstate_t state;
char b[MB_LEN_MAX]; char b[PL_MB_LEN_MAX];
memset(&state, 0, sizeof(state)); memset(&state, 0, sizeof(state));
if ( wcrtomb(b, (wchar_t)c, &state) != (size_t)-1 ) if ( wcrtomb(b, (wchar_t)c, &state) != (size_t)-1 )
@ -1072,14 +1101,15 @@ returns \n, but it returns the same for a single \n.
Often, we could keep track of bufp and reset this, but we must deal with Often, we could keep track of bufp and reset this, but we must deal with
the case where we fetch a new buffer. In this case, we must copy the few the case where we fetch a new buffer. In this case, we must copy the few
remaining bytes to the `unbuffer' area. remaining bytes to the `unbuffer' area. If SIO_USERBUF is set, we do not
have this spare buffer space. This is used for reading from strings,
which cannot fetch a new buffer anyway.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int int
Speekcode(IOSTREAM *s) Speekcode(IOSTREAM *s)
{ int c; { int c;
char *start; char *start;
IOPOS *psave = s->position;
size_t safe = (size_t)-1; size_t safe = (size_t)-1;
if ( !s->buffer ) if ( !s->buffer )
@ -1094,15 +1124,19 @@ Speekcode(IOSTREAM *s)
if ( (s->flags & SIO_FEOF) ) if ( (s->flags & SIO_FEOF) )
return -1; return -1;
if ( s->bufp + UNDO_SIZE > s->limitp ) if ( s->bufp + UNDO_SIZE > s->limitp && !(s->flags&SIO_USERBUF) )
{ safe = s->limitp - s->bufp; { safe = s->limitp - s->bufp;
memcpy(s->buffer-safe, s->bufp, safe); memcpy(s->buffer-safe, s->bufp, safe);
} }
start = s->bufp; start = s->bufp;
s->position = NULL; if ( s->position )
c = Sgetcode(s); { IOPOS psave = *s->position;
s->position = psave; c = Sgetcode(s);
*s->position = psave;
} else
{ c = Sgetcode(s);
}
if ( Sferror(s) ) if ( Sferror(s) )
return -1; return -1;
@ -1110,7 +1144,7 @@ Speekcode(IOSTREAM *s)
if ( s->bufp > start ) if ( s->bufp > start )
{ s->bufp = start; { s->bufp = start;
} else } else if ( c != -1 )
{ assert(safe != (size_t)-1); { assert(safe != (size_t)-1);
s->bufp = s->buffer-safe; s->bufp = s->buffer-safe;
} }
@ -1341,10 +1375,6 @@ Sfeof(IOSTREAM *s)
return -1; return -1;
} }
if ( s->downstream != NULL &&
Sfeof(s->downstream))
return TRUE;
if ( S__fillbuf(s) == -1 ) if ( S__fillbuf(s) == -1 )
return TRUE; return TRUE;
@ -1440,6 +1470,11 @@ Ssetenc(IOSTREAM *s, IOENC enc, IOENC *old)
} }
s->encoding = enc; s->encoding = enc;
if ( enc == ENC_OCTET )
s->flags &= ~SIO_TEXT;
else
s->flags |= SIO_TEXT;
return 0; return 0;
} }
@ -1490,23 +1525,23 @@ Sunit_size(IOSTREAM *s)
Return the size of the underlying data object. Should be optimized; Return the size of the underlying data object. Should be optimized;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
long int64_t
Ssize(IOSTREAM *s) Ssize(IOSTREAM *s)
{ if ( s->functions->control ) { if ( s->functions->control )
{ long size; { int64_t size;
if ( (*s->functions->control)(s->handle, SIO_GETSIZE, (void *)&size) == 0 ) if ( (*s->functions->control)(s->handle, SIO_GETSIZE, (void *)&size) == 0 )
return size; return size;
} }
if ( s->functions->seek ) if ( s->functions->seek )
{ long here = Stell(s); { int64_t here = Stell64(s);
long end; int64_t end;
if ( Sseek(s, 0, SIO_SEEK_END) == 0 ) if ( Sseek64(s, 0, SIO_SEEK_END) == 0 )
end = Stell(s); end = Stell64(s);
else else
end = -1; end = -1;
Sseek(s, here, SIO_SEEK_SET); Sseek64(s, here, SIO_SEEK_SET);
return end; return end;
} }
@ -1667,13 +1702,13 @@ unallocStream(IOSTREAM *s)
#ifdef O_PLMT #ifdef O_PLMT
if ( s->mutex ) if ( s->mutex )
{ recursiveMutexDelete(s->mutex); { recursiveMutexDelete(s->mutex);
free(s->mutex); PL_free(s->mutex);
s->mutex = NULL; s->mutex = NULL;
} }
#endif #endif
if ( !(s->flags & SIO_STATIC) ) if ( !(s->flags & SIO_STATIC) )
free(s); PL_free(s);
} }
@ -1711,7 +1746,7 @@ Sclose(IOSTREAM *s)
#ifdef __WINDOWS__ #ifdef __WINDOWS__
if ( (s->flags & SIO_ADVLOCK) ) if ( (s->flags & SIO_ADVLOCK) )
{ OVERLAPPED ov; { OVERLAPPED ov;
HANDLE h = (HANDLE)_get_osfhandle((int)s->handle); HANDLE h = (HANDLE)_get_osfhandle((int)((uintptr_t)s->handle));
memset(&ov, 0, sizeof(ov)); memset(&ov, 0, sizeof(ov));
UnlockFileEx(h, 0, 0, 0xffffffff, &ov); UnlockFileEx(h, 0, 0, 0xffffffff, &ov);
@ -1732,9 +1767,9 @@ Sclose(IOSTREAM *s)
if ( rval < 0 ) if ( rval < 0 )
reportStreamError(s); reportStreamError(s);
run_close_hooks(s); /* deletes Prolog registration */ run_close_hooks(s); /* deletes Prolog registration */
s->magic = SIO_CMAGIC;
SUNLOCK(s); SUNLOCK(s);
s->magic = SIO_CMAGIC;
if ( s->message ) if ( s->message )
free(s->message); free(s->message);
if ( s->references == 0 ) if ( s->references == 0 )
@ -1845,11 +1880,23 @@ Svprintf(const char *fm, va_list args)
} }
#define NEXTCHR(s, c) if ( utf8 ) \ #define NEXTCHR(s, c) \
{ (s) = utf8_get_char((s), &(c)); \ switch (enc) \
} else \ { case ENC_ANSI: \
{ c = *(s)++; c &= 0xff; \ c = *(s)++; c &= 0xff; \
} break; \
case ENC_UTF8: \
(s) = utf8_get_char((s), &(c)); \
break; \
case ENC_WCHAR: \
{ wchar_t *_w = (wchar_t*)(s); \
c = *_w++; \
(s) = (char*)_w; \
break; \
} \
default: \
break; \
}
#define OUTCHR(s, c) do { printed++; \ #define OUTCHR(s, c) do { printed++; \
if ( Sputcode((c), (s)) < 0 ) goto error; \ if ( Sputcode((c), (s)) < 0 ) goto error; \
@ -1911,7 +1958,7 @@ Svfprintf(IOSTREAM *s, const char *fm, va_list args)
char fbuf[100], *fs = fbuf, *fe = fbuf; char fbuf[100], *fs = fbuf, *fe = fbuf;
int islong = 0; int islong = 0;
int pad = ' '; int pad = ' ';
int utf8 = FALSE; IOENC enc = ENC_ANSI;
for(;;) for(;;)
{ switch(*fm) { switch(*fm)
@ -1952,13 +1999,19 @@ Svfprintf(IOSTREAM *s, const char *fm, va_list args)
{ islong++; /* 1: %ld */ { islong++; /* 1: %ld */
fm++; fm++;
} }
if ( *fm == 'l' ) switch ( *fm )
{ islong++; /* 2: %lld */ { case 'l':
fm++; islong++; /* 2: %lld */
} fm++;
if ( *fm == 'U' ) /* %Us: UTF-8 string */ break;
{ utf8 = TRUE; case 'U': /* %Us: UTF-8 string */
fm++; enc = ENC_UTF8;
fm++;
break;
case 'W': /* %Ws: wide string */
enc = ENC_WCHAR;
fm++;
break;
} }
switch(*fm) switch(*fm)
@ -1983,41 +2036,53 @@ Svfprintf(IOSTREAM *s, const char *fm, va_list args)
case 'u': case 'u':
case 'x': case 'x':
case 'X': case 'X':
{ intptr_t v = 0; /* make compiler silent */ { int vi = 0;
int64_t vl = 0; long vl = 0; /* make compiler silent */
int64_t vll = 0;
char fmbuf[8], *fp=fmbuf; char fmbuf[8], *fp=fmbuf;
switch( islong ) switch( islong )
{ case 0: { case 0:
v = va_arg(args, int); vi = va_arg(args, int);
break; break;
case 1: case 1:
v = va_arg(args, long); vl = va_arg(args, long);
break; break;
case 2: case 2:
vl = va_arg(args, int64_t); vll = va_arg(args, int64_t);
break; break;
default:
assert(0);
} }
*fp++ = '%'; *fp++ = '%';
if ( modified ) if ( modified )
*fp++ = '#'; *fp++ = '#';
*fp++ = 'l'; switch( islong )
if ( islong < 2 ) { case 0:
{ *fp++ = *fm; *fp++ = *fm;
*fp = '\0'; *fp = '\0';
SNPRINTF3(fmbuf, v); SNPRINTF3(fmbuf, vi);
} else break;
{ case 1:
*fp++ = 'l';
*fp++ = *fm;
*fp = '\0';
SNPRINTF3(fmbuf, vl);
break;
case 2:
#ifdef __WINDOWS__ #ifdef __WINDOWS__
strcat(fp-1, "I64"); /* Synchronise with INT64_FORMAT! */ *fp++ = 'I'; /* Synchronise with INT64_FORMAT! */
fp += strlen(fp); *fp++ = '6';
*fp++ = '4';
#else #else
*fp++ = 'l'; *fp++ = 'l';
*fp++ = 'l';
#endif #endif
*fp++ = *fm; *fp++ = *fm;
*fp = '\0'; *fp = '\0';
SNPRINTF3(fmbuf, vl); SNPRINTF3(fmbuf, vll);
break;
} }
break; break;
@ -2075,12 +2140,25 @@ Svfprintf(IOSTREAM *s, const char *fm, va_list args)
{ size_t w; { size_t w;
if ( fs == fbuf ) if ( fs == fbuf )
w = fe - fs; { w = fe - fs;
else } else
w = strlen(fs); { switch(enc)
{ case ENC_ANSI:
if ( utf8 ) w = strlen(fs);
w = utf8_strlen(fs, w); break;
case ENC_UTF8:
w = strlen(fs);
w = utf8_strlen(fs, w);
break;
case ENC_WCHAR:
w = wcslen((wchar_t*)fs);
break;
default:
assert(0);
w = 0; /* make compiler happy */
break;
}
}
if ( (ssize_t)w < arg1 ) if ( (ssize_t)w < arg1 )
{ w = arg1 - w; { w = arg1 - w;
@ -2609,7 +2687,7 @@ Scontrol_file(void *handle, int action, void *arg)
switch(action) switch(action)
{ case SIO_GETSIZE: { case SIO_GETSIZE:
{ intptr_t *rval = arg; { int64_t *rval = arg;
struct stat buf; struct stat buf;
if ( fstat(fd, &buf) == 0 ) if ( fstat(fd, &buf) == 0 )
@ -2621,6 +2699,11 @@ Scontrol_file(void *handle, int action, void *arg)
case SIO_SETENCODING: case SIO_SETENCODING:
case SIO_FLUSHOUTPUT: case SIO_FLUSHOUTPUT:
return 0; return 0;
case SIO_GETFILENO:
{ int *p = arg;
*p = fd;
return 0;
}
default: default:
return -1; return -1;
} }
@ -2662,13 +2745,20 @@ provide the socket-id through Sfileno, this code crashes on
tcp_open_socket(). As ttys and its detection is of no value on Windows tcp_open_socket(). As ttys and its detection is of no value on Windows
anyway, we skip this. Second, Windows doesn't have fork(), so FD_CLOEXEC anyway, we skip this. Second, Windows doesn't have fork(), so FD_CLOEXEC
is of no value. is of no value.
For now, we use PL_malloc_uncollectable(). In the end, this is really
one of the object-types we want to leave to GC.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef FD_CLOEXEC /* This is not defined in MacOS */
#define FD_CLOEXEC 1
#endif
IOSTREAM * IOSTREAM *
Snew(void *handle, int flags, IOFUNCTIONS *functions) Snew(void *handle, int flags, IOFUNCTIONS *functions)
{ IOSTREAM *s; { IOSTREAM *s;
if ( !(s = malloc(sizeof(IOSTREAM))) ) if ( !(s = PL_malloc_uncollectable(sizeof(IOSTREAM))) )
{ errno = ENOMEM; { errno = ENOMEM;
return NULL; return NULL;
} }
@ -2680,7 +2770,11 @@ Snew(void *handle, int flags, IOFUNCTIONS *functions)
s->functions = functions; s->functions = functions;
s->timeout = -1; /* infinite */ s->timeout = -1; /* infinite */
s->posbuf.lineno = 1; s->posbuf.lineno = 1;
s->encoding = ENC_ISO_LATIN_1; if ( (flags&SIO_TEXT) )
{ s->encoding = initEncoding();
} else
{ s->encoding = ENC_OCTET;
}
#if CRLF_MAPPING #if CRLF_MAPPING
s->newline = SIO_NL_DOS; s->newline = SIO_NL_DOS;
#endif #endif
@ -2688,8 +2782,8 @@ Snew(void *handle, int flags, IOFUNCTIONS *functions)
s->position = &s->posbuf; s->position = &s->posbuf;
#ifdef O_PLMT #ifdef O_PLMT
if ( !(flags & SIO_NOMUTEX) ) if ( !(flags & SIO_NOMUTEX) )
{ if ( !(s->mutex = malloc(sizeof(recursiveMutex))) ) { if ( !(s->mutex = PL_malloc(sizeof(recursiveMutex))) )
{ free(s); { PL_free(s);
return NULL; return NULL;
} }
recursiveMutexInit(s->mutex); recursiveMutexInit(s->mutex);
@ -2701,7 +2795,7 @@ Snew(void *handle, int flags, IOFUNCTIONS *functions)
if ( (fd = Sfileno(s)) >= 0 ) if ( (fd = Sfileno(s)) >= 0 )
{ if ( isatty(fd) ) { if ( isatty(fd) )
s->flags |= SIO_ISATTY; s->flags |= SIO_ISATTY;
#if defined(F_SETFD) && defined(FD_CLOEXEC) #ifdef F_SETFD
fcntl(fd, F_SETFD, FD_CLOEXEC); fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif #endif
} }
@ -2804,13 +2898,23 @@ Sopen_file(const char *path, const char *how)
struct flock buf; struct flock buf;
memset(&buf, 0, sizeof(buf)); memset(&buf, 0, sizeof(buf));
buf.l_type = (lock == lread ? F_RDLCK : F_WRLCK); buf.l_whence = SEEK_SET;
buf.l_type = (lock == lread ? F_RDLCK : F_WRLCK);
if ( fcntl(fd, wait ? F_SETLKW : F_SETLK, &buf) < 0 ) while( fcntl(fd, wait ? F_SETLKW : F_SETLK, &buf) != 0 )
{ int save = errno; { if ( errno == EINTR )
close(fd); { if ( PL_handle_signals() < 0 )
errno = save; { close(fd);
return NULL; return NULL;
}
continue;
} else
{ int save = errno;
close(fd);
errno = save;
return NULL;
}
} }
#else /* we don't have locking */ #else /* we don't have locking */
#if __WINDOWS__ #if __WINDOWS__
@ -2891,12 +2995,10 @@ Sfileno(IOSTREAM *s)
if ( s->flags & SIO_FILE ) if ( s->flags & SIO_FILE )
{ intptr_t h = (intptr_t)s->handle; { intptr_t h = (intptr_t)s->handle;
n = (int)h; n = (int)h;
} else if ( s->flags & SIO_PIPE )
{ n = fileno((FILE *)s->handle);
} else if ( s->functions->control && } else if ( s->functions->control &&
(*s->functions->control)(s->handle, (*s->functions->control)(s->handle,
SIO_GETFILENO, SIO_GETFILENO,
(void *)&n) == 0 ) (void *)&n) == 0 )
{ ; { ;
} else } else
{ errno = EINVAL; { errno = EINVAL;
@ -2907,6 +3009,30 @@ Sfileno(IOSTREAM *s)
} }
#ifdef __WINDOWS__
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
On Windows, type SOCKET is an unsigned int and all values
[0..INVALID_SOCKET) are valid. It is also not allowed to run normal
file-functions on it or the application will crash. There seems to be no
way out except for introducing an extra function at this level :-(
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
SOCKET
Swinsock(IOSTREAM *s)
{ SOCKET n = INVALID_SOCKET;
if ( s->functions->control &&
(*s->functions->control)(s->handle,
SIO_GETWINSOCK,
(void *)&n) == 0 )
{ return n;
}
errno = EINVAL;
return INVALID_SOCKET;
}
#endif
/******************************* /*******************************
* PIPES * * PIPES *
*******************************/ *******************************/
@ -2915,13 +3041,9 @@ Sfileno(IOSTREAM *s)
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#include "windows/popen.c" #include "windows/popen.c"
#ifdef popen
#undef popen #undef popen
#endif
#define popen(cmd, how) pt_popen(cmd, how)
#ifdef pclose
#undef pclose #undef pclose
#endif #define popen(cmd, how) pt_popen(cmd, how)
#define pclose(fd) pt_pclose(fd) #define pclose(fd) pt_pclose(fd)
#endif #endif
@ -2958,11 +3080,31 @@ Sclose_pipe(void *handle)
} }
static int
Scontrol_pipe(void *handle, int action, void *arg)
{ FILE *fp = handle;
switch(action)
{ case SIO_GETFILENO:
{ int *ap = arg;
*ap = fileno(fp);
return 0;
}
case SIO_FLUSHOUTPUT:
case SIO_SETENCODING:
return 0;
default:
return -1;
}
}
IOFUNCTIONS Spipefunctions = IOFUNCTIONS Spipefunctions =
{ Sread_pipe, { Sread_pipe,
Swrite_pipe, Swrite_pipe,
(Sseek_function)0, (Sseek_function)0,
Sclose_pipe Sclose_pipe,
Scontrol_pipe
}; };
@ -2983,9 +3125,9 @@ Sopen_pipe(const char *command, const char *type)
{ int flags; { int flags;
if ( *type == 'r' ) if ( *type == 'r' )
flags = SIO_PIPE|SIO_INPUT|SIO_FBUF; flags = SIO_INPUT|SIO_FBUF;
else else
flags = SIO_PIPE|SIO_OUTPUT|SIO_FBUF; flags = SIO_OUTPUT|SIO_FBUF;
return Snew((void *)fd, flags, &Spipefunctions); return Snew((void *)fd, flags, &Spipefunctions);
} }
@ -3229,12 +3371,20 @@ Sopenmem(char **buffer, size_t *sizep, const char *mode)
static ssize_t static ssize_t
Sread_string(void *handle, char *buf, size_t size) Sread_string(void *handle, char *buf, size_t size)
{ return 0; /* signal EOF */ { (void)handle;
(void)buf;
(void)size;
return 0; /* signal EOF */
} }
static ssize_t static ssize_t
Swrite_string(void *handle, char *buf, size_t size) Swrite_string(void *handle, char *buf, size_t size)
{ errno = ENOSPC; /* signal error */ { (void)handle;
(void)buf;
(void)size;
errno = ENOSPC; /* signal error */
return -1; return -1;
} }
@ -3267,7 +3417,7 @@ Sopen_string(IOSTREAM *s, char *buf, size_t size, const char *mode)
{ int flags = SIO_FBUF|SIO_USERBUF; { int flags = SIO_FBUF|SIO_USERBUF;
if ( !s ) if ( !s )
{ if ( !(s = malloc(sizeof(IOSTREAM))) ) { if ( !(s = PL_malloc_uncollectable(sizeof(IOSTREAM))) ) /* TBD: Use GC */
{ errno = ENOMEM; { errno = ENOMEM;
return NULL; return NULL;
} }
@ -3310,7 +3460,7 @@ Sopen_string(IOSTREAM *s, char *buf, size_t size, const char *mode)
#define STDIO(n, f) { NULL, NULL, NULL, NULL, \ #define STDIO(n, f) { NULL, NULL, NULL, NULL, \
EOF, SIO_MAGIC, 0, f, {0, 0, 0}, NULL, \ EOF, SIO_MAGIC, 0, f, {0, 0, 0}, NULL, \
((void *)(n)), &Sttyfunctions, \ (void *)(n), &Sttyfunctions, \
0, NULL, \ 0, NULL, \
(void (*)(void *))0, NULL, \ (void (*)(void *))0, NULL, \
-1, \ -1, \
@ -3321,7 +3471,7 @@ Sopen_string(IOSTREAM *s, char *buf, size_t size, const char *mode)
#define SIO_STDIO (SIO_FILE|SIO_STATIC|SIO_NOCLOSE|SIO_ISATTY|SIO_TEXT) #define SIO_STDIO (SIO_FILE|SIO_STATIC|SIO_NOCLOSE|SIO_ISATTY|SIO_TEXT)
#define STDIO_STREAMS \ #define STDIO_STREAMS \
STDIO(0, SIO_STDIO|SIO_LBUF|SIO_INPUT|SIO_NOFEOF), /* Sinput */ \ STDIO(0, SIO_STDIO|SIO_LBUF|SIO_INPUT|SIO_NOFEOF), /* Sinput */ \
STDIO(1, SIO_STDIO|SIO_LBUF|SIO_OUTPUT|SIO_REPPL), /* Soutput */ \ STDIO(1, SIO_STDIO|SIO_LBUF|SIO_OUTPUT|SIO_REPPL), /* Soutput */ \
STDIO(2, SIO_STDIO|SIO_NBUF|SIO_OUTPUT|SIO_REPPL) /* Serror */ STDIO(2, SIO_STDIO|SIO_NBUF|SIO_OUTPUT|SIO_REPPL) /* Serror */
@ -3335,31 +3485,33 @@ static const IOSTREAM S__iob0[] =
}; };
/* vsc: Scleanup should reset init done */ static int S__initialised = FALSE;
static int done;
void void
SinitStreams(void) SinitStreams(void)
{ { if ( !S__initialised )
if ( !done++ )
{ int i; { int i;
IOENC enc = initEncoding(); IOENC enc;
S__initialised = TRUE;
enc = initEncoding();
for(i=0; i<=2; i++) for(i=0; i<=2; i++)
{ if ( !isatty(i) ) { IOSTREAM *s = &S__iob[i];
{ S__iob[i].flags &= ~SIO_ISATTY;
S__iob[i].functions = &Sfilefunctions; /* Check for pipe? */ if ( !isatty(i) )
{ s->flags &= ~SIO_ISATTY;
s->functions = &Sfilefunctions; /* Check for pipe? */
} }
if ( S__iob[i].encoding == ENC_ISO_LATIN_1 ) if ( s->encoding == ENC_ISO_LATIN_1 )
S__iob[i].encoding = enc; s->encoding = enc;
#ifdef O_PLMT #ifdef O_PLMT
S__iob[i].mutex = malloc(sizeof(recursiveMutex)); s->mutex = PL_malloc(sizeof(recursiveMutex));
recursiveMutexInit(S__iob[i].mutex); recursiveMutexInit(s->mutex);
#endif #endif
#if CRLF_MAPPING #if CRLF_MAPPING
_setmode(i, O_BINARY); _setmode(i, O_BINARY);
S__iob[i].newline = SIO_NL_DOS; s->newline = SIO_NL_DOS;
#endif #endif
} }
@ -3461,11 +3613,12 @@ Scleanup(void)
S__iob[i].mutex = NULL; S__iob[i].mutex = NULL;
recursiveMutexDelete(m); recursiveMutexDelete(m);
free(m); PL_free(m);
} }
#endif #endif
*s = S__iob0[i]; /* re-initialise */ *s = S__iob0[i]; /* re-initialise */
} }
done = 0;
S__initialised = FALSE;
} }

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "pl-incl.h" #include "pl-incl.h"
@ -34,45 +34,10 @@ String operations that are needed for the shared IO library.
* ALLOCATION * * ALLOCATION *
*******************************/ *******************************/
#ifdef O_DEBUG
#define CHAR_INUSE 0x42
#define CHAR_FREED 0x41
char * char *
store_string(const char *s) store_string(const char *s)
{ if ( s ) { if ( s )
{ GET_LD { char *copy = (char *)allocHeapOrHalt(strlen(s)+1);
char *copy = (char *)allocHeap(strlen(s)+2);
*copy++ = CHAR_INUSE;
strcpy(copy, s);
return copy;
} else
{ return NULL;
}
}
void
remove_string(char *s)
{ if ( s )
{ GET_LD
assert(s[-1] == CHAR_INUSE);
s[-1] = CHAR_FREED;
freeHeap(s-1, strlen(s)+2);
}
}
#else /*O_DEBUG*/
char *
store_string(const char *s)
{ if ( s )
{ GET_LD
char *copy = (char *)allocHeap(strlen(s)+1);
strcpy(copy, s); strcpy(copy, s);
return copy; return copy;
@ -85,14 +50,9 @@ store_string(const char *s)
void void
remove_string(char *s) remove_string(char *s)
{ if ( s ) { if ( s )
{ GET_LD
freeHeap(s, strlen(s)+1); freeHeap(s, strlen(s)+1);
}
} }
#endif /*O_DEBUG*/
/******************************* /*******************************
* NUMBERS * * NUMBERS *
*******************************/ *******************************/
@ -239,13 +199,13 @@ int_mbscoll(const char *s1, const char *s2, int icase)
if ( l1 < 1024 && (w1 = alloca(sizeof(wchar_t)*(l1+1))) ) if ( l1 < 1024 && (w1 = alloca(sizeof(wchar_t)*(l1+1))) )
{ ml1 = FALSE; { ml1 = FALSE;
} else } else
{ w1 = PL_malloc(sizeof(wchar_t)*(l1+1)); { w1 = PL_malloc_atomic(sizeof(wchar_t)*(l1+1));
ml1 = TRUE; ml1 = TRUE;
} }
if ( l2 < 1024 && (w2 = alloca(sizeof(wchar_t)*(l2+1))) ) if ( l2 < 1024 && (w2 = alloca(sizeof(wchar_t)*(l2+1))) )
{ ml2 = FALSE; { ml2 = FALSE;
} else } else
{ w2 = PL_malloc(sizeof(wchar_t)*(l2+1)); { w2 = PL_malloc_atomic(sizeof(wchar_t)*(l2+1));
ml2 = TRUE; ml2 = TRUE;
} }

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef PL_STRING_H_INCLUDED #ifndef PL_STRING_H_INCLUDED
@ -27,7 +27,7 @@
COMMON(char *) store_string(const char *s); COMMON(char *) store_string(const char *s);
COMMON(void) remove_string(char *s); COMMON(void) remove_string(char *s);
COMMON(char) digitName(int n, int smll); COMMON(char) digitName(int n, int small);
COMMON(int) digitValue(int b, int c); COMMON(int) digitValue(int b, int c);
COMMON(bool) strprefix(const char *string, const char *prefix); COMMON(bool) strprefix(const char *string, const char *prefix);
COMMON(bool) strpostfix(const char *string, const char *postfix); COMMON(bool) strpostfix(const char *string, const char *postfix);

View File

@ -1,11 +1,10 @@
/* $Id$ /* Part of SWI-Prolog
Part of SWI-Prolog
Author: Jan Wielemaker Author: Jan Wielemaker
E-mail: jan@swi.psy.uva.nl E-mail: J.Wielemaker@vu.nl
WWW: http://www.swi-prolog.org WWW: http://www.swi-prolog.org
Copyright (C): 1985-2002, University of Amsterdam Copyright (C): 1985-2012, University of Amsterdam
VU University Amsterdam
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -19,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
/*#define O_DEBUG 1*/ /*#define O_DEBUG 1*/
@ -41,35 +40,35 @@ create, advance over and destroy enumerator objects. These objects are
used to enumerate the symbols of these tables, used primarily for the used to enumerate the symbols of these tables, used primarily for the
pl_current_* predicates. pl_current_* predicates.
The enumerators cause two things: (1) as intptr_t enumerators are The enumerators cause two things: (1) as long as enumerators are
associated, the table will not be rehashed and (2) if symbols are associated, the table will not be rehashed and (2) if symbols are
deleted that are referenced by an enumerator, the enumerator is deleted that are referenced by an enumerator, the enumerator is
automatically advanced to the next free symbol. This, in general, makes automatically advanced to the next free symbol. This, in general, makes
the enumeration of hash-tables safe. the enumeration of hash-tables safe.
TODO: abort should delete any pending enumerators. This should be TBD: Resizing hash-tables causes major headaches for concurrent access.
thread-local, as thread_exit/1 should do the same. We can avoid this by using a dynamic array for the list of hash-entries.
Ongoing work in the RDF store shows hash-tables that can handle
concurrent lock-free access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void static Symbol *
allocHTableEntries(Table ht) allocHTableEntries(int buckets)
{ GET_LD { size_t bytes = buckets * sizeof(Symbol);
int n;
Symbol *p; Symbol *p;
ht->entries = allocHeap(ht->buckets * sizeof(Symbol)); p = allocHeapOrHalt(bytes);
memset(p, 0, bytes);
for(n=0, p = &ht->entries[0]; n < ht->buckets; n++, p++) return p;
*p = NULL;
} }
Table Table
newHTable(int buckets) newHTable(int buckets)
{ GET_LD { Table ht;
Table ht;
ht = allocHeap(sizeof(struct table)); ht = allocHeapOrHalt(sizeof(struct table));
ht->buckets = (buckets & ~TABLE_MASK); ht->buckets = (buckets & ~TABLE_MASK);
ht->size = 0; ht->size = 0;
ht->enumerators = NULL; ht->enumerators = NULL;
@ -79,25 +78,24 @@ newHTable(int buckets)
if ( (buckets & TABLE_UNLOCKED) ) if ( (buckets & TABLE_UNLOCKED) )
ht->mutex = NULL; ht->mutex = NULL;
else else
{ ht->mutex = allocHeap(sizeof(simpleMutex)); { ht->mutex = allocHeapOrHalt(sizeof(simpleMutex));
simpleMutexInit(ht->mutex); simpleMutexInit(ht->mutex);
} }
#endif #endif
allocHTableEntries(ht); ht->entries = allocHTableEntries(ht->buckets);
return ht; return ht;
} }
void void
destroyHTable(Table ht) destroyHTable(Table ht)
{ GET_LD {
#ifdef O_PLMT #ifdef O_PLMT
if ( ht->mutex ) if ( ht->mutex )
{ simpleMutexDelete(ht->mutex); { simpleMutexDelete(ht->mutex);
freeHeap(ht->mutex, sizeof(*ht->mutex)); freeHeap(ht->mutex, sizeof(*ht->mutex));
ht->mutex = NULL; ht->mutex = NULL;
} }
#endif #endif
@ -107,19 +105,19 @@ destroyHTable(Table ht)
} }
#if O_DEBUG || O_HASHSTAT #if O_DEBUG
#define HASHSTAT(c) c
static int lookups; static int lookups;
static int cmps; static int cmps;
void void
exitTables(int status, void *arg) exitTables(int status, void *arg)
{ Sdprintf("hashstat: Anonymous tables: %d lookups using %d compares\n", { (void)status;
(void)arg;
Sdprintf("hashstat: Anonymous tables: %d lookups using %d compares\n",
lookups, cmps); lookups, cmps);
} }
#else #endif
#define HASHSTAT(c)
#endif /*O_DEBUG*/
void void
@ -129,7 +127,7 @@ initTables(void)
if ( !done ) if ( !done )
{ done = TRUE; { done = TRUE;
HASHSTAT(PL_on_halt(exitTables, NULL)); DEBUG(MSG_HASH_STAT, PL_on_halt(exitTables, NULL));
} }
} }
@ -138,9 +136,9 @@ Symbol
lookupHTable(Table ht, void *name) lookupHTable(Table ht, void *name)
{ Symbol s = ht->entries[pointerHashValue(name, ht->buckets)]; { Symbol s = ht->entries[pointerHashValue(name, ht->buckets)];
HASHSTAT(lookups++); DEBUG(MSG_HASH_STAT, lookups++);
for( ; s; s = s->next) for( ; s; s = s->next)
{ HASHSTAT(cmps++); { DEBUG(MSG_HASH_STAT, cmps++);
if ( s->name == name ) if ( s->name == name )
return s; return s;
} }
@ -170,41 +168,75 @@ checkHTable(Table ht)
/* MT: Locked by calling addHTable() /* MT: Locked by calling addHTable()
*/ */
static void static Symbol
rehashHTable(Table ht) rehashHTable(Table ht, Symbol map)
{ GET_LD { Symbol *newentries, *oldentries;
Symbol *oldtab; int newbuckets, oldbuckets;
int oldbucks; int i;
int i; int safe_copy = (ht->mutex != NULL);
oldtab = ht->entries; newbuckets = ht->buckets*2;
oldbucks = ht->buckets; newentries = allocHTableEntries(newbuckets);
ht->buckets *= 2;
allocHTableEntries(ht);
DEBUG(1, Sdprintf("Rehashing table %p to %d entries\n", ht, ht->buckets)); DEBUG(MSG_HASH_STAT,
Sdprintf("Rehashing table %p to %d entries\n", ht, ht->buckets));
for(i=0; i<oldbucks; i++) for(i=0; i<ht->buckets; i++)
{ Symbol s, n; { Symbol s, n;
for(s=oldtab[i]; s; s = n) if ( safe_copy )
{ int v = (int)pointerHashValue(s->name, ht->buckets); { for(s=ht->entries[i]; s; s = n)
{ int v = (int)pointerHashValue(s->name, newbuckets);
Symbol s2 = allocHeapOrHalt(sizeof(*s2));
n = s->next; n = s->next;
s->next = ht->entries[v]; if ( s == map )
ht->entries[v] = s; map = s2;
*s2 = *s;
s2->next = newentries[v];
newentries[v] = s2;
}
} else
{ for(s=ht->entries[i]; s; s = n)
{ int v = (int)pointerHashValue(s->name, newbuckets);
n = s->next;
s->next = newentries[v];
newentries[v] = s;
}
} }
} }
freeHeap(oldtab, oldbucks * sizeof(Symbol)); oldentries = ht->entries;
DEBUG(0, checkHTable(ht)); oldbuckets = ht->buckets;
ht->entries = newentries;
ht->buckets = newbuckets;
if ( safe_copy )
{ /* Here we should be waiting until */
/* active lookup are finished */
for(i=0; i<oldbuckets; i++)
{ Symbol s, n;
for(s=oldentries[i]; s; s = n)
{ n = s->next;
s->next = NULL; /* that causes old readers to stop */
freeHeap(s, sizeof(*s));
}
}
}
freeHeap(oldentries, oldbuckets * sizeof(Symbol));
DEBUG(CHK_SECURE, checkHTable(ht));
return map;
} }
Symbol Symbol
addHTable(Table ht, void *name, void *value) addHTable(Table ht, void *name, void *value)
{ GET_LD { Symbol s;
Symbol s;
int v; int v;
LOCK_TABLE(ht); LOCK_TABLE(ht);
@ -213,7 +245,7 @@ addHTable(Table ht, void *name, void *value)
{ UNLOCK_TABLE(ht); { UNLOCK_TABLE(ht);
return NULL; return NULL;
} }
s = allocHeap(sizeof(struct symbol)); s = allocHeapOrHalt(sizeof(struct symbol));
s->name = name; s->name = name;
s->value = value; s->value = value;
s->next = ht->entries[v]; s->next = ht->entries[v];
@ -223,7 +255,7 @@ addHTable(Table ht, void *name, void *value)
ht, name, value, ht->size)); ht, name, value, ht->size));
if ( ht->buckets * 2 < ht->size && !ht->enumerators ) if ( ht->buckets * 2 < ht->size && !ht->enumerators )
rehashHTable(ht); s = rehashHTable(ht, s);
UNLOCK_TABLE(ht); UNLOCK_TABLE(ht);
DEBUG(1, checkHTable(ht)); DEBUG(1, checkHTable(ht));
@ -237,8 +269,7 @@ Note: s must be in the table!
void void
deleteSymbolHTable(Table ht, Symbol s) deleteSymbolHTable(Table ht, Symbol s)
{ GET_LD { int v;
int v;
Symbol *h; Symbol *h;
TableEnum e; TableEnum e;
@ -255,6 +286,9 @@ deleteSymbolHTable(Table ht, Symbol s)
{ if ( *h == s ) { if ( *h == s )
{ *h = (*h)->next; { *h = (*h)->next;
s->next = NULL; /* force crash */
s->name = NULL;
s->value = NULL;
freeHeap(s, sizeof(struct symbol)); freeHeap(s, sizeof(struct symbol));
ht->size--; ht->size--;
@ -268,8 +302,7 @@ deleteSymbolHTable(Table ht, Symbol s)
void void
clearHTable(Table ht) clearHTable(Table ht)
{ GET_LD { int n;
int n;
TableEnum e; TableEnum e;
LOCK_TABLE(ht); LOCK_TABLE(ht);
@ -309,24 +342,23 @@ Table copyHTable(Table org)
Table Table
copyHTable(Table org) copyHTable(Table org)
{ GET_LD { Table ht;
Table ht;
int n; int n;
ht = allocHeap(sizeof(struct table)); ht = allocHeapOrHalt(sizeof(struct table));
LOCK_TABLE(org); LOCK_TABLE(org);
*ht = *org; /* copy all attributes */ *ht = *org; /* copy all attributes */
#ifdef O_PLMT #ifdef O_PLMT
ht->mutex = NULL; ht->mutex = NULL;
#endif #endif
allocHTableEntries(ht); ht->entries = allocHTableEntries(ht->buckets);
for(n=0; n < ht->buckets; n++) for(n=0; n < ht->buckets; n++)
{ Symbol s, *q; { Symbol s, *q;
q = &ht->entries[n]; q = &ht->entries[n];
for(s = org->entries[n]; s; s = s->next) for(s = org->entries[n]; s; s = s->next)
{ Symbol s2 = allocHeap(sizeof(*s2)); { Symbol s2 = allocHeapOrHalt(sizeof(*s2));
*q = s2; *q = s2;
q = &s2->next; q = &s2->next;
@ -340,7 +372,7 @@ copyHTable(Table org)
} }
#ifdef O_PLMT #ifdef O_PLMT
if ( org->mutex ) if ( org->mutex )
{ ht->mutex = allocHeap(sizeof(simpleMutex)); { ht->mutex = allocHeapOrHalt(sizeof(simpleMutex));
simpleMutexInit(ht->mutex); simpleMutexInit(ht->mutex);
} }
#endif #endif
@ -356,8 +388,7 @@ copyHTable(Table org)
TableEnum TableEnum
newTableEnum(Table ht) newTableEnum(Table ht)
{ GET_LD { TableEnum e = allocHeapOrHalt(sizeof(struct table_enum));
TableEnum e = allocHeap(sizeof(struct table_enum));
Symbol n; Symbol n;
LOCK_TABLE(ht); LOCK_TABLE(ht);
@ -378,8 +409,7 @@ newTableEnum(Table ht)
void void
freeTableEnum(TableEnum e) freeTableEnum(TableEnum e)
{ GET_LD { TableEnum *ep;
TableEnum *ep;
Table ht; Table ht;
if ( !e ) if ( !e )

View File

@ -19,7 +19,7 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <string.h> /* get size_t */ #include <string.h> /* get size_t */

View File

@ -19,13 +19,15 @@
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#ifndef UTF8_H_INCLUDED #ifndef UTF8_H_INCLUDED
#define UTF8_H_INCLUDED #define UTF8_H_INCLUDED
#define PL_MB_LEN_MAX 16
#define UTF8_MALFORMED_REPLACEMENT 0xfffd #define UTF8_MALFORMED_REPLACEMENT 0xfffd
#define ISUTF8_MB(c) ((unsigned)(c) >= 0xc0 && (unsigned)(c) <= 0xfd) #define ISUTF8_MB(c) ((unsigned)(c) >= 0xc0 && (unsigned)(c) <= 0xfd)