Compare commits

...

3 Commits

13 changed files with 545 additions and 128 deletions
+1 -1
View File
@@ -610,7 +610,7 @@ int HawkStd::open_pio (Pipe& io)
break;
}
pio = hawk_pio_open((hawk_gem_t*)*this, 0, io.getName(), flags);
pio = hawk_pio_open((hawk_gem_t*)*this, 0, io.getName(), flags, HAWK_NULL, HAWK_NULL);
if (!pio) return -1;
#if defined(HAWK_OOCH_IS_UCH)
+9 -2
View File
@@ -250,6 +250,7 @@ struct hawk_htb_t
hawk_oow_t size;
hawk_oow_t capa;
hawk_oow_t threshold;
hawk_oow_t rev;
hawk_htb_pair_t** bucket;
};
@@ -284,13 +285,15 @@ typedef struct hawk_htb_itr_t hawk_htb_itr_t;
/**
* The HAWK_HTB_SIZE() macro returns the number of pairs in a hash table.
*/
#define HAWK_HTB_SIZE(m) (*(const hawk_oow_t*)&(m)->size)
#define HAWK_HTB_SIZE(m) ((const hawk_oow_t)(m)->size)
/**
* The HAWK_HTB_CAPA() macro returns the maximum number of pairs that can be
* stored in a hash table without further reorganization.
*/
#define HAWK_HTB_CAPA(m) (*(const hawk_oow_t*)&(m)->capa)
#define HAWK_HTB_CAPA(m) ((const hawk_oow_t)(m)->capa)
#define HAWK_HTB_REV(m) ((const hawk_oow_t)(m)->rev)
#define HAWK_HTB_FACTOR(m) (*(const int*)&(m)->factor)
#define HAWK_HTB_KSCALE(m) (*(const int*)&(m)->scale[HAWK_HTB_KEY])
@@ -406,6 +409,10 @@ HAWK_EXPORT hawk_oow_t hawk_htb_getcapa (
const hawk_htb_t* htb /**< hash table */
);
HAWK_EXPORT hawk_oow_t hawk_htb_getrev (
const hawk_htb_t* htb /**< hash table */
);
/**
* The hawk_htb_search() function searches a hash table to find a pair with a
* matching key. It returns the pointer to the pair found. If it fails
+4
View File
@@ -45,6 +45,7 @@
# define hawk_map_getxtn(map) hawk_htb_getxtn(map)
# define hawk_map_getsize(map) hawk_htb_getsize(map)
# define hawk_map_getcapa(map) hawk_htb_getcapa(map)
# define hawk_map_getrev(map) hawk_htb_getrev(map)
# define hawk_map_getstyle(map) hawk_htb_getstyle(map)
# define hawk_map_setstyle(map,cbs) hawk_htb_setstyle(map,cbs)
# define hawk_map_search(map,kptr,klen) hawk_htb_search(map,kptr,klen)
@@ -80,6 +81,7 @@
# define HAWK_MAP_SIZER_DEFAULT HAWK_HTB_SIZER_DEFAULT
# define HAWK_MAP_HASHER_DEFAULT HAWK_HTB_HASHER_DEFAULT
# define HAWK_MAP_SIZE(map) HAWK_HTB_SIZE(map)
# define HAWK_MAP_REV(map) HAWK_HTB_REV(map)
# define HAWK_MAP_KCOPIER(map) HAWK_HTB_KCOPIER(map)
# define HAWK_MAP_VCOPIER(map) HAWK_HTB_VCOPIER(map)
# define HAWK_MAP_KFREEER(map) HAWK_HTB_KFREEER(map)
@@ -108,6 +110,7 @@
# define hawk_map_getxtn(map) hawk_rbt_getxtn(map)
# define hawk_map_getsize(map) hawk_rbt_getsize(map)
# define hawk_map_getcapa(map) hawk_rbt_getsize(map)
# define hawk_map_getrev(map) hawk_rbt_getrev(map)
# define hawk_map_getstyle(map) hawk_rbt_getstyle(map)
# define hawk_map_setstyle(map,cbs) hawk_rbt_setstyle(map,cbs)
# define hawk_map_search(map,kptr,klen) hawk_rbt_search(map,kptr,klen)
@@ -143,6 +146,7 @@
# define HAWK_MAP_SIZER_DEFAULT (HAWK_NULL)
# define HAWK_MAP_HASHER_DEFAULT (HAWK_NULL)
# define HAWK_MAP_SIZE(map) HAWK_RBT_SIZE(map)
# define HAWK_MAP_REV(map) HAWK_RBT_REV(map)
# define HAWK_MAP_KCOPIER(map) HAWK_RBT_KCOPIER(map)
# define HAWK_MAP_VCOPIER(map) HAWK_RBT_VCOPIER(map)
# define HAWK_MAP_KFREEER(map) HAWK_RBT_KFREEER(map)
+22 -9
View File
@@ -120,8 +120,21 @@ enum hawk_pio_hid_t
};
typedef enum hawk_pio_hid_t hawk_pio_hid_t;
enum hawk_pio_env_mk_type_t
{
HAWK_PIO_ENV_MK_BCH_PP, /* P1 ... PN HAWK_NUL where P1 .. PN points to K=V */
HAWK_PIO_ENV_MK_BCH_PN, /* K1=V\0K2=V\0\0 */
HAWK_PIO_ENV_MK_UCH_PP,
};
typedef int (*hawk_pio_fncptr_t) (void* ctx, char** envp);
typedef enum hawk_pio_env_mk_type_t hawk_pio_env_mk_type_t;
typedef void* (*hawk_pio_env_mk_t) (
hawk_pio_env_mk_type_t type,
void* ctx
);
typedef int (*hawk_pio_fncptr_t) (void* ctx);
/**
* The hawk_pio_fnc_t type defines a structure to point to the function
@@ -170,7 +183,6 @@ struct hawk_pio_pin_t
hawk_pio_t* self;
};
/**
* The hawk_pio_t type defines a structure to store status for piped I/O
* to a child process. The hawk_pio_xxx() funtions are written around this
@@ -198,18 +210,17 @@ extern "C" {
* pipes to it. #HAWK_PIO_SHELL causes the function to execute \a cmd via
* the default shell of an underlying system: /bin/sh on *nix, cmd.exe on win32.
* On *nix systems, a full path to the command is needed if it is not specified.
* If \a env is #HAWK_NULL, the environment of \a cmd inherits that of the
* calling process. If you want to pass an empty environment, you can pass
* an empty \a env object with no items inserted. If #HAWK_PIO_BCSTRCMD is
* specified in \a flags, \a cmd is treated as a multi-byte string whose
* character type is #hawk_bch_t.
* If #HAWK_PIO_BCSTRCMD is specified in \a flags, \a cmd is treated as a
* multi-byte string whose character type is #hawk_bch_t.
* \return #hawk_pio_t object on success, #HAWK_NULL on failure
*/
HAWK_EXPORT hawk_pio_t* hawk_pio_open (
hawk_gem_t* gem, /**< gem */
hawk_oow_t ext, /**< extension size */
const hawk_ooch_t* cmd, /**< command to execute */
int flags /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
int flags, /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
hawk_pio_env_mk_t env_mk,
void* env_cx
);
/**
@@ -230,7 +241,9 @@ HAWK_EXPORT int hawk_pio_init (
hawk_pio_t* pio, /**< pio object */
hawk_gem_t* gem, /**< gem */
const hawk_ooch_t* cmd, /**< command to execute */
int flags /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
int flags, /**< 0 or a number OR'ed of the #hawk_pio_flag_t enumerators*/
hawk_pio_env_mk_t env_mk,
void* env_cx
);
/**
+2
View File
@@ -254,6 +254,7 @@ struct hawk_rbt_t
hawk_rbt_pair_t xnil; /**< internal nil node */
hawk_oow_t size; /**< number of pairs */
hawk_rbt_pair_t* root; /**< root pair */
hawk_oow_t rev; /**< revision */
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
hawk_rbt_itr_t _prot_itr; /**< protected iterators */
#endif
@@ -280,6 +281,7 @@ struct hawk_rbt_t
* The HAWK_RBT_SIZE() macro returns the number of pairs in red-black tree.
*/
#define HAWK_RBT_SIZE(m) ((const hawk_oow_t)(m)->size)
#define HAWK_RBT_REV(m) ((const hawk_oow_t)(m)->rev)
#define HAWK_RBT_KSCALE(m) ((const int)(m)->scale[HAWK_RBT_KEY])
#define HAWK_RBT_VSCALE(m) ((const int)(m)->scale[HAWK_RBT_VAL])
+19 -5
View File
@@ -311,6 +311,7 @@ int hawk_htb_init (hawk_htb_t* htb, hawk_gem_t* gem, hawk_oow_t capa, int factor
htb->capa = capa;
htb->threshold = htb->capa * htb->factor / 100;
if (htb->capa > 0 && htb->threshold <= 0) htb->threshold = 1;
htb->rev = 0;
htb->style = &style[0];
return 0;
@@ -343,6 +344,11 @@ hawk_oow_t hawk_htb_getcapa (const hawk_htb_t* htb)
return htb->capa;
}
hawk_oow_t hawk_htb_getrev (const hawk_htb_t* htb)
{
return htb->rev;
}
pair_t* hawk_htb_search (const hawk_htb_t* htb, const void* kptr, hawk_oow_t klen)
{
pair_t* pair;
@@ -451,7 +457,7 @@ static HAWK_INLINE pair_t* insert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen,
case UPSERT:
case UPDATE:
p = change_pair_val(htb, pair, vptr, vlen);
if (p == HAWK_NULL)
if (!p)
{
/* error in changing the value */
return HAWK_NULL;
@@ -465,6 +471,7 @@ static HAWK_INLINE pair_t* insert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen,
else NEXT(prev) = p;
NEXT(p) = next;
}
htb->rev++;
return p;
case ENSERT:
@@ -507,6 +514,7 @@ static HAWK_INLINE pair_t* insert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen,
htb->bucket[hc] = pair;
htb->size++;
htb->rev++;
return pair; /* new key added */
}
@@ -525,7 +533,6 @@ pair_t* hawk_htb_insert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen, void* vpt
return insert(htb, kptr, klen, vptr, vlen, INSERT);
}
pair_t* hawk_htb_update (hawk_htb_t* htb, void* kptr, hawk_oow_t klen, void* vptr, hawk_oow_t vlen)
{
return insert(htb, kptr, klen, vptr, vlen, UPDATE);
@@ -548,7 +555,7 @@ pair_t* hawk_htb_cbsert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen, cbserter_
{
/* found a pair with a matching key */
p = cbserter(htb, pair, kptr, klen, ctx);
if (p == HAWK_NULL)
if (!p)
{
/* error returned by the callback function */
return HAWK_NULL;
@@ -562,6 +569,7 @@ pair_t* hawk_htb_cbsert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen, cbserter_
else NEXT(prev) = p;
NEXT(p) = next;
}
htb->rev++;
return p;
}
@@ -587,6 +595,7 @@ pair_t* hawk_htb_cbsert (hawk_htb_t* htb, void* kptr, hawk_oow_t klen, cbserter_
NEXT(pair) = htb->bucket[hc];
htb->bucket[hc] = pair;
htb->size++;
htb->rev++;
return pair; /* new key added */
}
@@ -610,6 +619,7 @@ int hawk_htb_delete (hawk_htb_t* htb, const void* kptr, hawk_oow_t klen)
hawk_htb_freepair(htb, pair);
htb->size--;
htb->rev++;
return 0;
}
@@ -624,14 +634,15 @@ int hawk_htb_delete (hawk_htb_t* htb, const void* kptr, hawk_oow_t klen)
void hawk_htb_clear (hawk_htb_t* htb)
{
hawk_oow_t i;
hawk_oow_t i, sz;
pair_t* pair, * next;
sz = htb->size;
for (i = 0; i < htb->capa; i++)
{
pair = htb->bucket[i];
while (pair != HAWK_NULL)
while (pair)
{
next = NEXT(pair);
hawk_htb_freepair(htb, pair);
@@ -641,6 +652,9 @@ void hawk_htb_clear (hawk_htb_t* htb)
htb->bucket[i] = HAWK_NULL;
}
HAWK_ASSERT(htb->size == 0);
if (sz) htb->rev++;
}
void hawk_htb_walk (hawk_htb_t* htb, walker_t walker, void* ctx)
+3 -1
View File
@@ -6688,15 +6688,17 @@ static int unsetenv(const char *name)
/* check if the entry starts with name + '=' */
if (hawk_comp_bcstr_limited(*ep, name, len, 0) == 0 && (*ep)[len] == '=')
{
char* old;
/* found it. shift remaining pointers down. */
char** next = ep;
old = *ep;
while (*next)
{
*next = *(next + 1);
next++;
}
free(*ep);
free(old);
break;
}
}
+33 -35
View File
@@ -191,14 +191,14 @@ static int close_open_fds_using_proc (hawk_pio_t* pio, int* excepts, hawk_oow_t
}
#endif
hawk_pio_t* hawk_pio_open (hawk_gem_t* gem, hawk_oow_t xtnsize, const hawk_ooch_t* cmd, int flags)
hawk_pio_t* hawk_pio_open (hawk_gem_t* gem, hawk_oow_t xtnsize, const hawk_ooch_t* cmd, int flags, hawk_pio_env_mk_t env_mk, void* env_ctx)
{
hawk_pio_t* pio;
pio = (hawk_pio_t*)hawk_gem_allocmem(gem, HAWK_SIZEOF(hawk_pio_t) + xtnsize);
if (pio)
{
if (hawk_pio_init(pio, gem, cmd, flags) <= -1)
if (hawk_pio_init(pio, gem, cmd, flags, env_mk, env_ctx) <= -1)
{
hawk_gem_freemem(gem, pio);
pio = HAWK_NULL;
@@ -458,16 +458,10 @@ static HAWK_INLINE int is_fd_valid_and_nocloexec (int fd)
return !(flags & FD_CLOEXEC)? 1: 0;
}
static hawk_pio_pid_t standard_fork_and_exec (hawk_pio_t* pio, int pipes[], param_t* param, char** envp)
static hawk_pio_pid_t standard_fork_and_exec (hawk_pio_t* pio, int pipes[], param_t* param, char*const* envp)
{
hawk_pio_pid_t pid;
#if defined(HAVE_CRT_EXTERNS_H)
# define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
pid = HAWK_FORK();
if (pid <= -1)
{
@@ -574,7 +568,6 @@ static hawk_pio_pid_t standard_fork_and_exec (hawk_pio_t* pio, int pipes[], para
if (pio->flags & HAWK_PIO_DROPOUT) HAWK_CLOSE(1);
if (pio->flags & HAWK_PIO_DROPERR) HAWK_CLOSE(2);
if (pio->flags & HAWK_PIO_FNCCMD)
{
/* -----------------------------------------------
@@ -583,7 +576,10 @@ static hawk_pio_pid_t standard_fork_and_exec (hawk_pio_t* pio, int pipes[], para
hawk_pio_fnc_t* fnc = (hawk_pio_fnc_t*)param;
int retx;
retx = fnc->ptr(fnc->ctx, envp);
/* when the function pointer is a worker function,
* the function must use the context(fnc->ctx) passed
* in as a paramter to find out actual environmen values (e.g. ENVIRON) */
retx = fnc->ptr(fnc->ctx);
if (devnull >= 0) HAWK_CLOSE(devnull);
HAWK_EXIT(retx);
}
@@ -619,7 +615,7 @@ static int set_pipe_nonblock (hawk_pio_t* pio, hawk_pio_hnd_t fd, int enabled)
}
int hawk_pio_init (hawk_pio_t* pio, hawk_gem_t* gem, const hawk_ooch_t* cmd, int flags)
int hawk_pio_init (hawk_pio_t* pio, hawk_gem_t* gem, const hawk_ooch_t* cmd, int flags, hawk_pio_env_mk_t env_mk, void* env_ctx)
{
hawk_pio_hnd_t handle[6] /*=
{
@@ -673,29 +669,14 @@ int hawk_pio_init (hawk_pio_t* pio, hawk_gem_t* gem, const hawk_ooch_t* cmd, int
posix_spawnattr_t psattr;
hawk_pio_pid_t pid;
param_t param;
#if defined(HAVE_CRT_EXTERNS_H)
#define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
#elif defined(HAWK_SYSCALL0) && defined(SYS_vfork)
hawk_pio_pid_t pid;
param_t param;
#if defined(HAVE_CRT_EXTERNS_H)
#define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
int highest_fd;
int dummy;
#else
hawk_pio_pid_t pid;
param_t param;
#if defined(HAVE_CRT_EXTERNS_H)
#define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
#endif
HAWK_MEMSET(pio, 0, HAWK_SIZEOF(*pio));
@@ -1276,7 +1257,7 @@ create_process:
HAWK_SIZEOF(load_error),
EXEC_ASYNCRESULT,
cmd_line,
HAWK_NULL,
HAWK_NULL, /* environment - e.g. "PATH=/bin\0HOME=/tmp\0FOO=bar\0\0" */
&child_rc,
cmd_file
);
@@ -1307,7 +1288,6 @@ create_process:
return -1;
#else
if (flags & HAWK_PIO_WRITEIN)
{
if (HAWK_PIPE(&handle[0]) <= -1)
@@ -1350,12 +1330,32 @@ create_process:
{
/* i know i'm abusing typecasting here.
* cmd is supposed to be hawk_pio_fnc_t*, anyway */
pid = standard_fork_and_exec(pio, handle, (param_t*)cmd, environ);
pid = standard_fork_and_exec(pio, handle, (param_t*)cmd, HAWK_NULL);
if (pid <= -1) goto oops;
pio->child = pid;
}
else
{
char*const* envp;
if (env_mk)
{
envp = (char*const*)env_mk(HAWK_PIO_ENV_MK_BCH_PP, env_ctx);
if (HAWK_UNLIKELY(!envp)) goto oops;
/* pio doesn't free the memory block returned by the callback function.
* there is no callback triggered for dealloction either.
* the caller side must do track heap memory chunks allocated for this environment */
}
else
{
#if defined(HAVE_CRT_EXTERNS_H)
#define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
envp = environ;
}
#if defined(HAVE_POSIX_SPAWN) && !(defined(HAWK_SYSCALL0) && defined(SYS_vfork))
if ((pserr = posix_spawn_file_actions_init(&fa)) != 0)
@@ -1531,7 +1531,7 @@ create_process:
posix_spawnattr_setflags (&psattr, POSIX_SPAWN_USEVFORK);
#endif
pserr = posix_spawn(&pid, param.argv[0], &fa, &psattr, param.argv, environ);
pserr = posix_spawn(&pid, param.argv[0], &fa, &psattr, param.argv, envp);
#if defined(__linux)
posix_spawnattr_destroy (&psattr);
@@ -1683,7 +1683,7 @@ create_process:
if (flags & HAWK_PIO_DROPOUT) HAWK_SYSCALL1(dummy, SYS_close, 1);
if (flags & HAWK_PIO_DROPERR) HAWK_SYSCALL1(dummy, SYS_close, 2);
HAWK_SYSCALL3(dummy, SYS_execve, param.argv[0], param.argv, environ);
HAWK_SYSCALL3(dummy, SYS_execve, param.argv[0], param.argv, envp);
/*free_param(pio, &param); don't free this in the vfork version */
child_oops:
@@ -1696,7 +1696,6 @@ create_process:
pio->child = pid;
#else
if (make_param(pio, cmd, flags, &param) <= -1) goto oops;
/* check if the command(the command requested or /bin/sh) is
@@ -1708,7 +1707,7 @@ create_process:
goto oops;
}
pid = standard_fork_and_exec(pio, handle, &param, environ);
pid = standard_fork_and_exec(pio, handle, &param, envp);
if (pid <= -1)
{
free_param(pio, &param);
@@ -1719,7 +1718,6 @@ create_process:
free_param(pio, &param);
pio->child = pid;
#endif
}
if (flags & HAWK_PIO_WRITEIN)
+13 -1
View File
@@ -221,6 +221,7 @@ int hawk_rbt_init (hawk_rbt_t* rbt, hawk_gem_t* gem, int kscale, int vscale)
rbt->scale[HAWK_RBT_KEY] = (kscale < 1)? 1: kscale;
rbt->scale[HAWK_RBT_VAL] = (vscale < 1)? 1: vscale;
rbt->size = 0;
rbt->rev = 0;
rbt->style = &style[0];
@@ -262,6 +263,11 @@ hawk_oow_t hawk_rbt_getsize (const hawk_rbt_t* rbt)
return rbt->size;
}
hawk_oow_t hawk_rbt_getrev (const hawk_rbt_t* rbt)
{
return rbt->rev;
}
hawk_rbt_pair_t* hawk_rbt_search (const hawk_rbt_t* rbt, const void* kptr, hawk_oow_t klen)
{
hawk_rbt_pair_t* pair = rbt->root;
@@ -506,7 +512,9 @@ static hawk_rbt_pair_t* insert (hawk_rbt_t* rbt, void* kptr, hawk_oow_t klen, vo
{
case UPSERT:
case UPDATE:
return change_pair_val(rbt, x_cur, vptr, vlen);
x_cur = change_pair_val(rbt, x_cur, vptr, vlen);
if (HAWK_LIKELY(x_cur)) rbt->rev++;
return x_cur;
case ENSERT:
/* return existing pair */
@@ -561,6 +569,7 @@ static hawk_rbt_pair_t* insert (hawk_rbt_t* rbt, void* kptr, hawk_oow_t klen, vo
rbt->root->color = HAWK_RBT_BLACK;
rbt->size++;
rbt->rev++;
return x_new;
}
@@ -639,6 +648,7 @@ hawk_rbt_pair_t* hawk_rbt_cbsert (hawk_rbt_t* rbt, void* kptr, hawk_oow_t klen,
if (x_cur == rbt->root) rbt->root = x_new;
}
rbt->rev++;
return x_new;
}
@@ -678,6 +688,7 @@ hawk_rbt_pair_t* hawk_rbt_cbsert (hawk_rbt_t* rbt, void* kptr, hawk_oow_t klen,
rbt->root->color = HAWK_RBT_BLACK;
rbt->size++;
rbt->rev++;
return x_new;
}
@@ -837,6 +848,7 @@ static void delete_pair (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair)
}
rbt->size--;
rbt->rev++;
#if defined(HAWK_ENABLE_RBT_ITR_PROTECTION)
/* an iterator set by hawk_rbt_getfirstpair() or hawk_rbt_getnextpair(), if deleted, gets invalidated.
+247 -12
View File
@@ -189,6 +189,10 @@ typedef struct rxtn_t
hawk_htb_t cmgrtab;
hawk_rtx_ecb_t ecb;
void* envp; /* cached environment value */
hawk_map_t* env_map;
hawk_oow_t env_map_rev;
} rxtn_t;
typedef struct ioattr_t
@@ -208,6 +212,14 @@ static HAWK_INLINE rxtn_t* GET_RXTN(hawk_rtx_t* rtx) { return (rxtn_t*)((hawk_ui
/* ========================================================================= */
/* TODO: use wenviron where it's available */
typedef hawk_bch_t env_char_t;
#define ENV_CHAR_IS_BCH
static env_char_t** commit_environ (hawk_rtx_t* rtx, int gbl_id);
/* ========================================================================= */
static void* sys_alloc (hawk_mmgr_t* mmgr, hawk_oow_t size)
{
return malloc(size);
@@ -2036,6 +2048,58 @@ static int parse_rwpipe_uri (const hawk_ooch_t* uri, int* flags, hawk_nwad_t* nw
}
#endif
static void* envp_maker (hawk_pio_env_mk_type_t env_mk_type, void* ctx)
{
hawk_rtx_t* rtx = ctx;
hawk_t* hawk = hawk_rtx_gethawk(rtx);
if (env_mk_type == HAWK_PIO_ENV_MK_BCH_PP)
{
hawk_val_t* v_env;
hawk_map_t* env_map;
hawk_oow_t env_map_rev;
env_char_t** envp;
xtn_t* xtn;
rxtn_t* rxtn;
xtn = GET_XTN(hawk);
rxtn = GET_RXTN(rtx);
v_env = hawk_rtx_getgbl(rtx, xtn->gbl_environ);
HAWK_ASSERT(v_env != HAWK_NULL);
if (HAWK_RTX_GETVALTYPE(rtx, v_env) == HAWK_VAL_MAP)
{
env_map = ((hawk_val_map_t*)v_env)->map;
HAWK_ASSERT(env_map != HAWK_NULL);
env_map_rev = HAWK_MAP_REV(env_map);
}
else
{
env_map = HAWK_NULL;
env_map_rev = 0;
}
if (!rxtn->envp ||
rxtn->env_map != env_map ||
(env_map && rxtn->env_map_rev != env_map_rev))
{
envp = commit_environ(rtx, xtn->gbl_environ);
if (!envp) return HAWK_NULL;
if (rxtn->envp) hawk_rtx_freemem(rtx, rxtn->envp);
rxtn->envp = envp;
rxtn->env_map = env_map;
rxtn->env_map_rev = env_map_rev;
}
return rxtn->envp;
}
/* TODO: support more types */
/* unsupported env_mk_type */
return HAWK_NULL;
}
static hawk_ooi_t pio_handler_open (hawk_rtx_t* rtx, hawk_rio_arg_t* riod)
{
hawk_pio_t* handle;
@@ -2074,9 +2138,11 @@ static hawk_ooi_t pio_handler_open (hawk_rtx_t* rtx, hawk_rio_arg_t* riod)
hawk_rtx_getgem(rtx),
0,
riod->name,
flags | HAWK_PIO_SHELL | HAWK_PIO_TEXT | HAWK_PIO_IGNOREECERR
flags | HAWK_PIO_SHELL | HAWK_PIO_TEXT | HAWK_PIO_IGNOREECERR,
envp_maker,
rtx
);
if (handle == HAWK_NULL) return -1;
if (!handle) return -1;
#if defined(HAWK_OOCH_IS_UCH)
{
@@ -2776,6 +2842,14 @@ static void fini_rxtn (hawk_rtx_t* rtx, void* ctx)
hawk_htb_fini(&rxtn->cmgrtab);
rxtn->cmgrtab_inited = 0;
}
if (rxtn->envp)
{
hawk_rtx_freemem(rtx, rxtn->envp);
rxtn->envp = HAWK_NULL;
}
rxtn->env_map = HAWK_NULL;
rxtn->env_map_rev = 0;
}
static int build_argcv (hawk_rtx_t* rtx, int argc_id, int argv_id, const hawk_ooch_t* id, hawk_ooch_t* icf[])
@@ -2876,16 +2950,6 @@ static int build_argcv (hawk_rtx_t* rtx, int argc_id, int argv_id, const hawk_oo
return 0;
}
/* TODO: use wenviron where it's available */
typedef hawk_bch_t env_char_t;
#define ENV_CHAR_IS_BCH
#if defined(HAVE_CRT_EXTERNS_H)
#define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
static int build_environ (hawk_rtx_t* rtx, int gbl_id, env_char_t* envarr[])
{
hawk_val_t* v_env;
@@ -3015,8 +3079,179 @@ static int build_environ (hawk_rtx_t* rtx, int gbl_id, env_char_t* envarr[])
return 0;
}
static env_char_t** commit_environ (hawk_rtx_t* rtx, int gbl_id)
{
hawk_val_t* v_env;
hawk_map_t* map;
hawk_map_itr_t itr;
hawk_map_pair_t* pair;
env_char_t** envp;
env_char_t* ptr;
hawk_oow_t count, ptr_bytes, str_bytes;
v_env = hawk_rtx_getgbl(rtx, gbl_id);
HAWK_ASSERT(v_env != HAWK_NULL);
if (HAWK_RTX_GETVALTYPE(rtx, v_env) != HAWK_VAL_MAP)
{
/* it may be nil. but we can't prevent ENVIRON from being set to
* other scalar types, we should handle this case gracefully */
envp = (env_char_t**)hawk_rtx_allocmem(rtx, HAWK_SIZEOF(*envp) * 1);
if (HAWK_UNLIKELY(!envp)) return HAWK_NULL;
envp[0] = HAWK_NULL;
return envp;
}
map = ((hawk_val_map_t*)v_env)->map;
HAWK_ASSERT(map != HAWK_NULL);
count = 0;
str_bytes = 0;
hawk_init_map_itr(&itr, 0);
pair = hawk_map_getfirstpair(map, &itr);
while (pair)
{
hawk_oow_t klen, vlen;
klen = HAWK_MAP_KLEN(pair);
#if defined(ENV_CHAR_IS_BCH) && defined(HAWK_OOCH_IS_UCH)
{
hawk_oow_t tmp_ulen, tmp_blen;
tmp_ulen = klen;
if (hawk_rtx_convutobchars(rtx, HAWK_MAP_KPTR(pair), &tmp_ulen, HAWK_NULL, &tmp_blen) <= -1) return HAWK_NULL;
klen = tmp_blen;
}
#elif defined(ENV_CHAR_IS_UCH) && defined(HAWK_OOCH_IS_BCH)
{
hawk_oow_t tmp_blen, tmp_ulen;
tmp_blen = klen;
if (hawk_rtx_convbtouchars(rtx, HAWK_MAP_KPTR(pair), &tmp_blen, HAWK_NULL, &tmp_ulen, 1) <= -1) return HAWK_NULL;
klen = tmp_ulen;
}
#endif
#if defined(ENV_CHAR_IS_BCH)
{
hawk_bch_t* vptr;
vptr = hawk_rtx_getvalbcstr(rtx, HAWK_MAP_VPTR(pair), &vlen);
if (HAWK_UNLIKELY(!vptr)) return HAWK_NULL;
hawk_rtx_freevalbcstr(rtx, HAWK_MAP_VPTR(pair), vptr);
}
#else
{
hawk_uch_t* vptr;
vptr = hawk_rtx_getvalucstr(rtx, HAWK_MAP_VPTR(pair), &vlen);
if (HAWK_UNLIKELY(!vptr)) return HAWK_NULL;
hawk_rtx_freevalucstr(rtx, HAWK_MAP_VPTR(pair), vptr);
}
#endif
str_bytes += klen + 1 + vlen + 1;
count++;
pair = hawk_map_getnextpair(map, &itr);
}
ptr_bytes = HAWK_SIZEOF(*envp) * (count + 1);
envp = (env_char_t**)hawk_rtx_allocmem(rtx, ptr_bytes + (str_bytes * HAWK_SIZEOF(*ptr)));
if (HAWK_UNLIKELY(!envp)) return HAWK_NULL;
ptr = (env_char_t*)((hawk_uint8_t*)envp + ptr_bytes);
count = 0;
hawk_init_map_itr(&itr, 0);
pair = hawk_map_getfirstpair(map, &itr);
while (pair)
{
hawk_oow_t klen, vlen;
envp[count++] = ptr;
klen = HAWK_MAP_KLEN(pair);
#if ((defined(ENV_CHAR_IS_BCH) && defined(HAWK_OOCH_IS_BCH)) || \
(defined(ENV_CHAR_IS_UCH) && defined(HAWK_OOCH_IS_UCH)))
HAWK_MEMCPY(ptr, HAWK_MAP_KPTR(pair), klen);
ptr += klen;
#elif defined(ENV_CHAR_IS_BCH)
{
hawk_oow_t tmp_ulen, tmp_blen;
tmp_ulen = klen;
tmp_blen = str_bytes;
if (hawk_rtx_convutobchars(rtx, HAWK_MAP_KPTR(pair), &tmp_ulen, ptr, &tmp_blen) <= -1)
{
hawk_rtx_freemem(rtx, envp);
return HAWK_NULL;
}
ptr += tmp_blen;
klen = tmp_blen;
}
#else
{
hawk_oow_t tmp_blen, tmp_ulen;
tmp_blen = klen;
tmp_ulen = str_bytes;
if (hawk_rtx_convbtouchars(rtx, HAWK_MAP_KPTR(pair), &tmp_blen, ptr, &tmp_ulen, 1) <= -1)
{
hawk_rtx_freemem(rtx, envp);
return HAWK_NULL;
}
ptr += tmp_ulen;
klen = tmp_ulen;
}
#endif
*ptr++ = '=';
#if defined(ENV_CHAR_IS_BCH)
{
hawk_bch_t* vptr;
vptr = hawk_rtx_getvalbcstr(rtx, HAWK_MAP_VPTR(pair), &vlen);
if (HAWK_UNLIKELY(!vptr))
{
hawk_rtx_freemem(rtx, envp);
return HAWK_NULL;
}
HAWK_MEMCPY(ptr, vptr, vlen);
ptr += vlen;
hawk_rtx_freevalbcstr(rtx, HAWK_MAP_VPTR(pair), vptr);
}
#else
{
hawk_uch_t* vptr;
vptr = hawk_rtx_getvalucstr(rtx, HAWK_MAP_VPTR(pair), &vlen);
if (HAWK_UNLIKELY(!vptr))
{
hawk_rtx_freemem(rtx, envp);
return HAWK_NULL;
}
HAWK_MEMCPY(ptr, vptr, vlen);
ptr += vlen;
hawk_rtx_freevalucstr(rtx, HAWK_MAP_VPTR(pair), vptr);
}
#endif
*ptr++ = '\0';
pair = hawk_map_getnextpair(map, &itr);
}
envp[count] = HAWK_NULL;
return envp;
}
static int make_additional_globals (hawk_rtx_t* rtx, xtn_t* xtn, const hawk_ooch_t* id, hawk_ooch_t* icf[])
{
#if defined(HAVE_CRT_EXTERNS_H)
#define environ (*(_NSGetEnviron()))
#else
extern char** environ;
#endif
if (build_argcv(rtx, xtn->gbl_argc, xtn->gbl_argv, id, icf) <= -1 ||
build_environ(rtx, xtn->gbl_environ, environ) <= -1) return -1;
return 0;
+1 -1
View File
@@ -22,7 +22,7 @@ check_SCRIPTS += h-003.hawk h-004.hawk h-009.hawk h-010.hawk \
h-016.hawk h-017.hawk h-018.hawk h-019.hawk h-020.hawk \
h-021.hawk h-022.hawk h-023.hawk h-024.hawk
check_SCRIPTS += regress-filename.sh regress-extra-info.sh
check_SCRIPTS += regress-filename.sh regress-extra-info.sh regress-environ.sh
check_ERRORS = e-001.err
+1 -1
View File
@@ -659,7 +659,7 @@ check_SCRIPTS = $(am__append_1) h-003.hawk h-004.hawk h-009.hawk \
h-010.hawk h-011.hawk h-012.hawk h-013.hawk h-014.hawk \
h-015.hawk h-016.hawk h-017.hawk h-018.hawk h-019.hawk \
h-020.hawk h-021.hawk h-022.hawk h-023.hawk h-024.hawk \
regress-filename.sh regress-extra-info.sh
regress-filename.sh regress-extra-info.sh regress-environ.sh
check_ERRORS = e-001.err
EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \
journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \
+130
View File
@@ -0,0 +1,130 @@
#!/bin/sh
[ $# -ge 1 ] && HAWK_BIN="$1"
[ -z "$HAWK_BIN" ] && HAWK_BIN="hawk"
set -u
tmp_prog="/tmp/hawk-regress-environ-$$.hawk"
tmp_pipe="/tmp/hawk-regress-environ-$$.pipe"
trap 'rm -f "$tmp_prog" "$tmp_pipe"' EXIT
cat > "$tmp_prog" <<'EOF'
function emit_env(tag, cmd)
{
cmd = "sh -c 'printf \"" tag ":%s\\n\" \"${HAWK_TEST_ENV_PIPE-unset}\" >&3'"
print "" | cmd
close(cmd)
}
BEGIN {
print hawk::typename(ENVIRON["HAWK_TEST_ENV_INT"]) ":" ENVIRON["HAWK_TEST_ENV_INT"];
print hawk::typename(ENVIRON["HAWK_TEST_ENV_NEG"]) ":" ENVIRON["HAWK_TEST_ENV_NEG"];
print hawk::typename(ENVIRON["HAWK_TEST_ENV_FLT"]) ":" sprintf("%.2f", ENVIRON["HAWK_TEST_ENV_FLT"]);
print hawk::typename(ENVIRON["HAWK_TEST_ENV_STR"]) ":" ENVIRON["HAWK_TEST_ENV_STR"];
print hawk::typename(ENVIRON["HAWK_TEST_ENV_EMPTY"]) ":" length(ENVIRON["HAWK_TEST_ENV_EMPTY"]);
print hawk::typename(ENVIRON["HAWK_TEST_ENV_MISSING"]) ":" hawk::isnil(ENVIRON["HAWK_TEST_ENV_MISSING"]);
ENVIRON["HAWK_TEST_ENV_NEW"] = 456;
print hawk::typename(ENVIRON["HAWK_TEST_ENV_NEW"]) ":" ENVIRON["HAWK_TEST_ENV_NEW"];
ENVIRON["HAWK_TEST_ENV_NEW"] = 7.5;
print hawk::typename(ENVIRON["HAWK_TEST_ENV_NEW"]) ":" sprintf("%.1f", ENVIRON["HAWK_TEST_ENV_NEW"]);
ENVIRON["HAWK_TEST_ENV_NEW"] = "xyz";
print hawk::typename(ENVIRON["HAWK_TEST_ENV_NEW"]) ":" ENVIRON["HAWK_TEST_ENV_NEW"];
delete ENVIRON["HAWK_TEST_ENV_STR"];
print hawk::typename(ENVIRON["HAWK_TEST_ENV_STR"]) ":" hawk::isnil(ENVIRON["HAWK_TEST_ENV_STR"]);
emit_env("initial");
ENVIRON["HAWK_TEST_ENV_PIPE"] = "changed";
emit_env("changed");
delete ENVIRON["HAWK_TEST_ENV_PIPE"];
emit_env("deleted");
ENVIRON = @{};
ENVIRON["HAWK_TEST_ENV_PIPE"] = "replaced";
emit_env("replaced");
ENVIRON = 123;
emit_env("scalar");
}
EOF
test_no=0
failed=0
ok() {
test_no=$((test_no + 1))
echo "ok $test_no - $1"
}
not_ok() {
test_no=$((test_no + 1))
failed=1
echo "not ok $test_no - $1"
echo "# expected: $2"
echo "# actual: $3"
}
check_eq() {
desc="$1"
expected="$2"
actual="$3"
if [ "x$actual" = "x$expected" ]
then
ok "$desc"
else
not_ok "$desc" "$expected" "$actual"
fi
}
echo "1..16"
if out=$(env -i \
HAWK_TEST_ENV_INT=123 \
HAWK_TEST_ENV_NEG=-7 \
HAWK_TEST_ENV_FLT=1.25 \
HAWK_TEST_ENV_STR=abc123 \
HAWK_TEST_ENV_EMPTY= \
HAWK_TEST_ENV_PIPE=initial \
"$HAWK_BIN" -f "$tmp_prog" 3>"$tmp_pipe" 2>&1)
then
ok "run environ regression"
else
not_ok "run environ regression" "exit code 0" "command failed: $out"
out=""
fi
line1=$(printf '%s\n' "$out" | sed -n '1p')
line2=$(printf '%s\n' "$out" | sed -n '2p')
line3=$(printf '%s\n' "$out" | sed -n '3p')
line4=$(printf '%s\n' "$out" | sed -n '4p')
line5=$(printf '%s\n' "$out" | sed -n '5p')
line6=$(printf '%s\n' "$out" | sed -n '6p')
line7=$(printf '%s\n' "$out" | sed -n '7p')
line8=$(printf '%s\n' "$out" | sed -n '8p')
line9=$(printf '%s\n' "$out" | sed -n '9p')
line10=$(printf '%s\n' "$out" | sed -n '10p')
pipe1=$(sed -n '1p' "$tmp_pipe")
pipe2=$(sed -n '2p' "$tmp_pipe")
pipe3=$(sed -n '3p' "$tmp_pipe")
pipe4=$(sed -n '4p' "$tmp_pipe")
pipe5=$(sed -n '5p' "$tmp_pipe")
check_eq "int env imported as int" "int:123" "$line1"
check_eq "negative int env imported as int" "int:-7" "$line2"
check_eq "float env imported as flt" "flt:1.25" "$line3"
check_eq "string env imported as str" "str:abc123" "$line4"
check_eq "empty env imported as empty string" "str:0" "$line5"
check_eq "missing env yields nil" "nil:1" "$line6"
check_eq "assigned int remains int" "int:456" "$line7"
check_eq "assigned float remains flt" "flt:7.5" "$line8"
check_eq "assigned string remains str" "str:xyz" "$line9"
check_eq "deleted env entry becomes nil" "nil:1" "$line10"
check_eq "pipe sees initial imported env" "initial:initial" "$pipe1"
check_eq "pipe sees in-place env update" "changed:changed" "$pipe2"
check_eq "pipe sees deleted env entry" "deleted:unset" "$pipe3"
check_eq "pipe sees replaced environ map" "replaced:replaced" "$pipe4"
check_eq "pipe sees scalar environ as empty" "scalar:unset" "$pipe5"
exit "$failed"