mirror of
https://github.com/zsh-users/zsh
synced 2024-11-05 16:08:45 +00:00
12411, 12419: Andrej: environment handling with fewer assumptions
This commit is contained in:
parent
19b4ca246a
commit
4a5882eeb3
5 changed files with 411 additions and 215 deletions
|
@ -1,3 +1,12 @@
|
|||
2000-07-28 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* Andrej: 12419: Src/builtin.c, Src/params.c: use putenv() and
|
||||
getenv() if available and try to make minimal assumptions about
|
||||
environment handling.
|
||||
|
||||
* Andrej: 12411: check for brk() and sbrk() and use sbrk() if no
|
||||
brk().
|
||||
|
||||
2000-07-27 Peter Stephenson <pws@pwstephenson.fsnet.co.uk>
|
||||
|
||||
* 12415: Src/utils.c: fix bug in 12414 when quoting metafied field
|
||||
|
|
|
@ -1634,7 +1634,6 @@ typeset_single(char *cname, char *pname, Param pm, int func,
|
|||
pm->env = addenv(pname, getsparam(pname), pm->flags);
|
||||
} else if (pm->env && !(pm->flags & PM_HASHELEM)) {
|
||||
delenv(pm->env);
|
||||
zsfree(pm->env);
|
||||
pm->env = NULL;
|
||||
}
|
||||
if (value)
|
||||
|
@ -1711,7 +1710,6 @@ typeset_single(char *cname, char *pname, Param pm, int func,
|
|||
tpm->ct = pm->ct;
|
||||
if (pm->env) {
|
||||
delenv(pm->env);
|
||||
zsfree(pm->env);
|
||||
}
|
||||
tpm->env = pm->env = NULL;
|
||||
|
||||
|
|
402
Src/mem.c
402
Src/mem.c
|
@ -34,7 +34,7 @@
|
|||
There are two ways to allocate memory in zsh. The first way is
|
||||
to call zalloc/zcalloc, which call malloc/calloc directly. It
|
||||
is legal to call realloc() or free() on memory allocated this way.
|
||||
The second way is to call halloc/hcalloc, which allocates memory
|
||||
The second way is to call zhalloc/hcalloc, which allocates memory
|
||||
from one of the memory pools on the heap stack. Such memory pools
|
||||
will automatically created when the heap allocation routines are
|
||||
called. To be sure that they are freed at appropriate times
|
||||
|
@ -54,35 +54,29 @@
|
|||
Memory allocated in this way does not have to be freed explicitly;
|
||||
it will all be freed when the pool is destroyed. In fact,
|
||||
attempting to free this memory may result in a core dump.
|
||||
The pair of pointers ncalloc and alloc may point to either
|
||||
zalloc & zcalloc or halloc & hcalloc; permalloc() sets them to the
|
||||
former, and heapalloc() sets them to the latter. This can be useful.
|
||||
For example, the dupstruct() routine duplicates a syntax tree,
|
||||
allocating the new memory for the tree using alloc(). If you want
|
||||
to duplicate a structure for a one-time use (i.e. to execute the list
|
||||
in a for loop), call heapalloc(), then dupstruct(). If you want
|
||||
to duplicate a structure in order to preserve it (i.e. a function
|
||||
definition), call permalloc(), then dupstruct().
|
||||
|
||||
If we use zsh's own allocator we use a simple trick to avoid that
|
||||
the (*real*) heap fills up with empty zsh-heaps: we allocate a
|
||||
large block of memory before allocating a heap pool, this memory
|
||||
is freed again immediately after the pool is allocated. If there
|
||||
are only small blocks on the free list this guarantees that the
|
||||
memory for the pool is at the end of the memory which means that
|
||||
we can give it back to the system when the pool is freed.
|
||||
If possible, the heaps are allocated using mmap() so that the
|
||||
(*real*) heap isn't filled up with empty zsh heaps. If mmap()
|
||||
is not available and zsh's own allocator is used, we use a simple trick
|
||||
to avoid that: we allocate a large block of memory before allocating
|
||||
a heap pool, this memory is freed again immediately after the pool
|
||||
is allocated. If there are only small blocks on the free list this
|
||||
guarantees that the memory for the pool is at the end of the memory
|
||||
which means that we can give it back to the system when the pool is
|
||||
freed.
|
||||
*/
|
||||
|
||||
/* != 0 if we are allocating in the heaplist */
|
||||
|
||||
/**/
|
||||
int useheap;
|
||||
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
|
||||
|
||||
/* Current allocation pointers. ncalloc() is either zalloc() or halloc(); *
|
||||
* alloc() is either zcalloc() or hcalloc(). */
|
||||
#include <sys/mman.h>
|
||||
|
||||
/**/
|
||||
void *(*ncalloc) _((size_t)), *(*alloc) _((size_t));
|
||||
#if defined(MAP_ANONYMOUS) && defined(MAP_PRIVATE)
|
||||
|
||||
#define USE_MMAP 1
|
||||
#define MMAP_FLAGS (MAP_ANONYMOUS | MAP_PRIVATE)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ZSH_MEM_WARNING
|
||||
# ifndef DEBUG
|
||||
|
@ -96,63 +90,77 @@ static int h_m[1025], h_push, h_pop, h_free;
|
|||
|
||||
#endif
|
||||
|
||||
#define H_ISIZE sizeof(long)
|
||||
#define HEAPSIZE (8192 - H_ISIZE)
|
||||
/* Make sure we align to the longest fundamental type. */
|
||||
union mem_align {
|
||||
zlong l;
|
||||
double d;
|
||||
};
|
||||
|
||||
#define H_ISIZE sizeof(union mem_align)
|
||||
#define HEAPSIZE (16384 - H_ISIZE)
|
||||
#define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
|
||||
#define HEAPFREE (16384 - H_ISIZE)
|
||||
|
||||
/* set default allocation to heap stack */
|
||||
|
||||
/**/
|
||||
int
|
||||
global_heapalloc(void)
|
||||
{
|
||||
int luh = useheap;
|
||||
|
||||
alloc = hcalloc;
|
||||
ncalloc = halloc;
|
||||
useheap = 1;
|
||||
return luh;
|
||||
}
|
||||
|
||||
/* set default allocation to malloc() */
|
||||
|
||||
/**/
|
||||
int
|
||||
global_permalloc(void)
|
||||
{
|
||||
int luh = useheap;
|
||||
|
||||
alloc = zcalloc;
|
||||
ncalloc = zalloc;
|
||||
useheap = 0;
|
||||
return luh;
|
||||
}
|
||||
|
||||
/* heappush saves the current heap state using this structure */
|
||||
|
||||
struct heapstack {
|
||||
struct heapstack *next; /* next one in list for this heap */
|
||||
size_t used;
|
||||
};
|
||||
|
||||
/* A zsh heap. */
|
||||
|
||||
struct heap {
|
||||
struct heap *next; /* next one */
|
||||
size_t used; /* bytes used from the heap */
|
||||
struct heapstack *sp; /* used by pushheap() to save the value used */
|
||||
#define arena(X) ((char *) (X) + sizeof(struct heap))
|
||||
};
|
||||
|
||||
/* list of zsh heap */
|
||||
/* list of zsh heaps */
|
||||
|
||||
static Heap heaps;
|
||||
|
||||
/* first heap with free space, not always correct */
|
||||
|
||||
static Heap fheap;
|
||||
|
||||
/* Use new heaps from now on. This returns the old heap-list. */
|
||||
|
||||
/**/
|
||||
mod_export Heap
|
||||
new_heaps(void)
|
||||
{
|
||||
Heap h = heaps;
|
||||
|
||||
fheap = heaps = NULL;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/* Re-install the old heaps again, freeing the new ones. */
|
||||
|
||||
/**/
|
||||
mod_export void
|
||||
old_heaps(Heap old)
|
||||
{
|
||||
Heap h, n;
|
||||
|
||||
for (h = heaps; h; h = n) {
|
||||
n = h->next;
|
||||
DPUTS(h->sp, "BUG: old_heaps() with pushed heaps");
|
||||
#ifdef USE_MMAP
|
||||
munmap((void *) h, sizeof(*h));
|
||||
#else
|
||||
zfree(h, sizeof(*h));
|
||||
#endif
|
||||
}
|
||||
heaps = old;
|
||||
fheap = NULL;
|
||||
}
|
||||
|
||||
/* Temporarily switch to other heaps (or back again). */
|
||||
|
||||
/**/
|
||||
mod_export Heap
|
||||
switch_heaps(Heap new)
|
||||
{
|
||||
Heap h = heaps;
|
||||
|
||||
heaps = new;
|
||||
fheap = NULL;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/* save states of zsh heaps */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
pushheap(void)
|
||||
{
|
||||
Heap h;
|
||||
|
@ -174,7 +182,7 @@ pushheap(void)
|
|||
/* reset heaps to previous state */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
freeheap(void)
|
||||
{
|
||||
Heap h, hn, hl = NULL;
|
||||
|
@ -182,6 +190,8 @@ freeheap(void)
|
|||
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
|
||||
h_free++;
|
||||
#endif
|
||||
|
||||
fheap = NULL;
|
||||
for (h = heaps; h; h = hn) {
|
||||
hn = h->next;
|
||||
if (h->sp) {
|
||||
|
@ -189,9 +199,16 @@ freeheap(void)
|
|||
memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used);
|
||||
#endif
|
||||
h->used = h->sp->used;
|
||||
if (!fheap && h->used < HEAP_ARENA_SIZE)
|
||||
fheap = h;
|
||||
hl = h;
|
||||
} else
|
||||
} else {
|
||||
#ifdef USE_MMAP
|
||||
munmap((void *) h, h->size);
|
||||
#else
|
||||
zfree(h, HEAPSIZE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (hl)
|
||||
hl->next = NULL;
|
||||
|
@ -202,7 +219,7 @@ freeheap(void)
|
|||
/* reset heap to previous state and destroy state information */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
popheap(void)
|
||||
{
|
||||
Heap h, hn, hl = NULL;
|
||||
|
@ -212,6 +229,7 @@ popheap(void)
|
|||
h_pop++;
|
||||
#endif
|
||||
|
||||
fheap = NULL;
|
||||
for (h = heaps; h; h = hn) {
|
||||
hn = h->next;
|
||||
if ((hs = h->sp)) {
|
||||
|
@ -220,11 +238,18 @@ popheap(void)
|
|||
memset(arena(h) + hs->used, 0xff, h->used - hs->used);
|
||||
#endif
|
||||
h->used = hs->used;
|
||||
if (!fheap && h->used < HEAP_ARENA_SIZE)
|
||||
fheap = h;
|
||||
zfree(hs, sizeof(*hs));
|
||||
|
||||
hl = h;
|
||||
} else
|
||||
} else {
|
||||
#ifdef USE_MMAP
|
||||
munmap((void *) h, h->size);
|
||||
#else
|
||||
zfree(h, HEAPSIZE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (hl)
|
||||
hl->next = NULL;
|
||||
|
@ -235,8 +260,8 @@ popheap(void)
|
|||
/* allocate memory from the current memory pool */
|
||||
|
||||
/**/
|
||||
void *
|
||||
halloc(size_t size)
|
||||
mod_export void *
|
||||
zhalloc(size_t size)
|
||||
{
|
||||
Heap h;
|
||||
size_t n;
|
||||
|
@ -244,22 +269,21 @@ halloc(size_t size)
|
|||
size = (size + H_ISIZE - 1) & ~(H_ISIZE - 1);
|
||||
|
||||
#if defined(ZSH_MEM) && defined(ZSH_MEM_DEBUG)
|
||||
h_m[size < 1024 ? (size / H_ISIZE) : 1024]++;
|
||||
h_m[size < (1024 * H_ISIZE) ? (size / H_ISIZE) : 1024]++;
|
||||
#endif
|
||||
|
||||
/* find a heap with enough free space */
|
||||
|
||||
for (h = heaps; h; h = h->next) {
|
||||
for (h = (fheap ? fheap : heaps); h; h = h->next) {
|
||||
if (HEAP_ARENA_SIZE >= (n = size + h->used)) {
|
||||
h->used = n;
|
||||
return arena(h) + n - size;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Heap hp;
|
||||
/* not found, allocate new heap */
|
||||
#ifdef ZSH_MEM
|
||||
#if defined(ZSH_MEM) && !defined(USE_MMAP)
|
||||
static int called = 0;
|
||||
void *foo = called ? (void *)malloc(HEAPFREE) : NULL;
|
||||
/* tricky, see above */
|
||||
|
@ -269,9 +293,38 @@ halloc(size_t size)
|
|||
n = HEAP_ARENA_SIZE > size ? HEAPSIZE : size + sizeof(*h);
|
||||
for (hp = NULL, h = heaps; h; hp = h, h = h->next);
|
||||
|
||||
h = (Heap) zalloc(n);
|
||||
#ifdef USE_MMAP
|
||||
{
|
||||
static size_t pgsz = 0;
|
||||
|
||||
#ifdef ZSH_MEM
|
||||
if (!pgsz) {
|
||||
|
||||
#ifdef _SC_PAGESIZE
|
||||
pgsz = sysconf(_SC_PAGESIZE); /* SVR4 */
|
||||
#else
|
||||
# ifdef _SC_PAGE_SIZE
|
||||
pgsz = sysconf(_SC_PAGE_SIZE); /* HPUX */
|
||||
# else
|
||||
pgsz = getpagesize();
|
||||
# endif
|
||||
#endif
|
||||
|
||||
pgsz--;
|
||||
}
|
||||
n = (n + pgsz) & ~pgsz;
|
||||
h = (Heap) mmap(NULL, n, PROT_READ | PROT_WRITE,
|
||||
MMAP_FLAGS, -1, 0);
|
||||
if (h == ((Heap) -1)) {
|
||||
zerr("fatal error: out of heap memory", NULL, 0);
|
||||
exit(1);
|
||||
}
|
||||
h->size = n;
|
||||
}
|
||||
#else
|
||||
h = (Heap) zalloc(n);
|
||||
#endif
|
||||
|
||||
#if defined(ZSH_MEM) && !defined(USE_MMAP)
|
||||
if (called)
|
||||
zfree(foo, HEAPFREE);
|
||||
called = 1;
|
||||
|
@ -285,6 +338,7 @@ halloc(size_t size)
|
|||
hp->next = h;
|
||||
else
|
||||
heaps = h;
|
||||
fheap = NULL;
|
||||
|
||||
unqueue_signals();
|
||||
return arena(h);
|
||||
|
@ -292,7 +346,7 @@ halloc(size_t size)
|
|||
}
|
||||
|
||||
/**/
|
||||
void *
|
||||
mod_export void *
|
||||
hrealloc(char *p, size_t old, size_t new)
|
||||
{
|
||||
Heap h, ph;
|
||||
|
@ -303,7 +357,7 @@ hrealloc(char *p, size_t old, size_t new)
|
|||
if (old == new)
|
||||
return p;
|
||||
if (!old && !p)
|
||||
return halloc(new);
|
||||
return zhalloc(new);
|
||||
|
||||
/* find the heap with p */
|
||||
|
||||
|
@ -317,8 +371,11 @@ hrealloc(char *p, size_t old, size_t new)
|
|||
|
||||
if (p + old < arena(h) + h->used) {
|
||||
if (new > old) {
|
||||
char *ptr = (char *) halloc(new);
|
||||
char *ptr = (char *) zhalloc(new);
|
||||
memcpy(ptr, p, old);
|
||||
#ifdef ZSH_MEM_DEBUG
|
||||
memset(p, 0xff, old);
|
||||
#endif
|
||||
return ptr;
|
||||
} else
|
||||
return new ? p : NULL;
|
||||
|
@ -332,9 +389,15 @@ hrealloc(char *p, size_t old, size_t new)
|
|||
ph->next = h->next;
|
||||
else
|
||||
heaps = h->next;
|
||||
fheap = NULL;
|
||||
#ifdef USE_MMAP
|
||||
munmap((void *) h, h->size);
|
||||
#else
|
||||
zfree(h, HEAPSIZE);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
#ifndef USE_MMAP
|
||||
if (old > HEAP_ARENA_SIZE || new > HEAP_ARENA_SIZE) {
|
||||
size_t n = HEAP_ARENA_SIZE > new ? HEAPSIZE : new + sizeof(*h);
|
||||
|
||||
|
@ -345,13 +408,16 @@ hrealloc(char *p, size_t old, size_t new)
|
|||
}
|
||||
h->used = new;
|
||||
return arena(h);
|
||||
#endif
|
||||
}
|
||||
#ifndef USE_MMAP
|
||||
DPUTS(h->used > HEAP_ARENA_SIZE, "BUG: hrealloc at invalid address");
|
||||
#endif
|
||||
if (h->used + (new - old) <= HEAP_ARENA_SIZE) {
|
||||
h->used += new - old;
|
||||
return p;
|
||||
} else {
|
||||
char *t = halloc(new);
|
||||
char *t = zhalloc(new);
|
||||
memcpy(t, p, old > new ? new : old);
|
||||
h->used -= old;
|
||||
#ifdef ZSH_MEM_DEBUG
|
||||
|
@ -364,12 +430,12 @@ hrealloc(char *p, size_t old, size_t new)
|
|||
/* allocate memory from the current memory pool and clear it */
|
||||
|
||||
/**/
|
||||
void *
|
||||
mod_export void *
|
||||
hcalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = halloc(size);
|
||||
ptr = zhalloc(size);
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
@ -377,7 +443,7 @@ hcalloc(size_t size)
|
|||
/* allocate permanent memory */
|
||||
|
||||
/**/
|
||||
void *
|
||||
mod_export void *
|
||||
zalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
@ -393,7 +459,7 @@ zalloc(size_t size)
|
|||
}
|
||||
|
||||
/**/
|
||||
void *
|
||||
mod_export void *
|
||||
zcalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
@ -416,7 +482,7 @@ zcalloc(size_t size)
|
|||
* POSIX compliant, but I'm not sure how to do that. */
|
||||
|
||||
/**/
|
||||
void *
|
||||
mod_export void *
|
||||
zrealloc(void *ptr, size_t size)
|
||||
{
|
||||
if (ptr) {
|
||||
|
@ -441,20 +507,20 @@ zrealloc(void *ptr, size_t size)
|
|||
}
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
dupstring(const char *s)
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (!s)
|
||||
return NULL;
|
||||
t = (char *)ncalloc(strlen((char *)s) + 1);
|
||||
t = (char *) zhalloc(strlen((char *)s) + 1);
|
||||
strcpy(t, s);
|
||||
return t;
|
||||
}
|
||||
|
||||
/**/
|
||||
char *
|
||||
mod_export char *
|
||||
ztrdup(const char *s)
|
||||
{
|
||||
char *t;
|
||||
|
@ -466,17 +532,18 @@ ztrdup(const char *s)
|
|||
return t;
|
||||
}
|
||||
|
||||
/**/
|
||||
#ifdef ZSH_MEM
|
||||
|
||||
/*
|
||||
Below is a simple segment oriented memory allocator for systems on
|
||||
which it is better than the system's one. Memory is given in blocks
|
||||
aligned to an integer multiple of sizeof(long) (4 bytes on most machines,
|
||||
but 8 bytes on e.g. a dec alpha). Each block is preceded by a header
|
||||
which contains the length of the data part (in bytes). In allocated
|
||||
blocks only this field of the structure m_hdr is senseful. In free
|
||||
blocks the second field (next) is a pointer to the next free segment
|
||||
on the free list.
|
||||
aligned to an integer multiple of sizeof(union mem_align), which will
|
||||
probably be 64-bit as it is the longer of zlong or double. Each block is
|
||||
preceded by a header which contains the length of the data part (in
|
||||
bytes). In allocated blocks only this field of the structure m_hdr is
|
||||
senseful. In free blocks the second field (next) is a pointer to the next
|
||||
free segment on the free list.
|
||||
|
||||
On top of this simple allocator there is a second allocator for small
|
||||
chunks of data. It should be both faster and less space-consuming than
|
||||
|
@ -532,22 +599,33 @@ ztrdup(const char *s)
|
|||
|
||||
struct m_shdr {
|
||||
struct m_shdr *next; /* next one on free list */
|
||||
#ifdef PAD_64_BIT
|
||||
/* dummy to make this 64-bit aligned */
|
||||
struct m_shdr *dummy;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct m_hdr {
|
||||
long len; /* length of memory block */
|
||||
zlong len; /* length of memory block */
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
/* either 1 or 2 zlong's, whichever makes up 64 bits. */
|
||||
zlong dummy1;
|
||||
#endif
|
||||
struct m_hdr *next; /* if free: next on free list
|
||||
if block of small blocks: next one with
|
||||
small blocks of same size*/
|
||||
struct m_shdr *free; /* if block of small blocks: free list */
|
||||
long used; /* if block of small blocks: number of used
|
||||
zlong used; /* if block of small blocks: number of used
|
||||
blocks */
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
zlong dummy2;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/* alignment for memory blocks */
|
||||
|
||||
#define M_ALIGN (sizeof(long))
|
||||
#define M_ALIGN (sizeof(union mem_align))
|
||||
|
||||
/* length of memory header, length of first field of memory header and
|
||||
minimal size of a block left free (if we allocate memory and take a
|
||||
|
@ -556,9 +634,23 @@ struct m_hdr {
|
|||
the free list) */
|
||||
|
||||
#define M_HSIZE (sizeof(struct m_hdr))
|
||||
#define M_ISIZE (sizeof(long))
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
# define M_ISIZE (2*sizeof(zlong))
|
||||
#else
|
||||
# define M_ISIZE (sizeof(zlong))
|
||||
#endif
|
||||
#define M_MIN (2 * M_ISIZE)
|
||||
|
||||
/* M_FREE is the number of bytes that have to be free before memory is
|
||||
* given back to the system
|
||||
* M_KEEP is the number of bytes that will be kept when memory is given
|
||||
* back; note that this has to be less than M_FREE
|
||||
* M_ALLOC is the number of extra bytes to request from the system */
|
||||
|
||||
#define M_FREE 32768
|
||||
#define M_KEEP 16384
|
||||
#define M_ALLOC M_KEEP
|
||||
|
||||
/* a pointer to the last free block, a pointer to the free list (the blocks
|
||||
on this list are kept in order - lowest address first) */
|
||||
|
||||
|
@ -589,13 +681,21 @@ static char *m_high, *m_low;
|
|||
|
||||
|
||||
#define M_SIDX(S) ((S) / M_ISIZE)
|
||||
#define M_SNUM 50
|
||||
#define M_SNUM 128
|
||||
#define M_SLEN(M) ((M)->len / M_SNUM)
|
||||
#if defined(PAD_64_BIT) && !defined(ZSH_64_BIT_TYPE)
|
||||
/* Include the dummy in the alignment */
|
||||
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
|
||||
sizeof(long) + sizeof(struct m_hdr *))
|
||||
2*sizeof(zlong) + sizeof(struct m_hdr *))
|
||||
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
|
||||
sizeof(long) - sizeof(struct m_hdr *)) / M_SNUM)
|
||||
#define M_NSMALL 8
|
||||
2*sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
|
||||
#else
|
||||
#define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) + \
|
||||
sizeof(zlong) + sizeof(struct m_hdr *))
|
||||
#define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) - \
|
||||
sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
|
||||
#endif
|
||||
#define M_NSMALL 8
|
||||
|
||||
static struct m_hdr *m_small[M_NSMALL];
|
||||
|
||||
|
@ -613,7 +713,9 @@ malloc(MALLOC_ARG_T size)
|
|||
{
|
||||
struct m_hdr *m, *mp, *mt;
|
||||
long n, s, os = 0;
|
||||
#ifndef USE_MMAP
|
||||
struct heap *h, *hp, *hf = NULL, *hfp = NULL;
|
||||
#endif
|
||||
|
||||
/* some systems want malloc to return the highest valid address plus one
|
||||
if it is called with an argument of zero */
|
||||
|
@ -657,9 +759,9 @@ malloc(MALLOC_ARG_T size)
|
|||
m->used++;
|
||||
|
||||
/* if all small blocks in this block are allocated, the block is
|
||||
put at the end of the list blocks wth small blocks of this
|
||||
put at the end of the list blocks with small blocks of this
|
||||
size (i.e., we try to keep blocks with free blocks at the
|
||||
beginning of the list, to make the search faster */
|
||||
beginning of the list, to make the search faster) */
|
||||
|
||||
if (m->used == M_SNUM && m->next) {
|
||||
for (mt = m; mt->next; mt = mt->next);
|
||||
|
@ -686,12 +788,14 @@ malloc(MALLOC_ARG_T size)
|
|||
} else
|
||||
s = 0;
|
||||
|
||||
/* search the free list for an block of at least the requested size */
|
||||
/* search the free list for an block of at least the requested size */
|
||||
for (mp = NULL, m = m_free; m && m->len < size; mp = m, m = m->next);
|
||||
|
||||
/* if there is an empty zsh heap at a lower address we steal it and take
|
||||
the memory from it, putting the rest on the free list (remember
|
||||
that the blocks on the free list are ordered) */
|
||||
#ifndef USE_MMAP
|
||||
|
||||
/* if there is an empty zsh heap at a lower address we steal it and take
|
||||
the memory from it, putting the rest on the free list (remember
|
||||
that the blocks on the free list are ordered) */
|
||||
|
||||
for (hp = NULL, h = heaps; h; hp = h, h = h->next)
|
||||
if (!h->used &&
|
||||
|
@ -718,16 +822,26 @@ malloc(MALLOC_ARG_T size)
|
|||
|
||||
for (mp = NULL, m = m_free; m && m->len < size; mp = m, m = m->next);
|
||||
}
|
||||
#endif
|
||||
if (!m) {
|
||||
long nal;
|
||||
/* no matching free block was found, we have to request new
|
||||
memory from the system */
|
||||
n = (size + M_HSIZE + m_pgsz - 1) & ~(m_pgsz - 1);
|
||||
n = (size + M_HSIZE + M_ALLOC + m_pgsz - 1) & ~(m_pgsz - 1);
|
||||
|
||||
if (((char *)(m = (struct m_hdr *)sbrk(n))) == ((char *)-1)) {
|
||||
DPUTS(1, "MEM: allocation error at sbrk.");
|
||||
unqueue_signals();
|
||||
return NULL;
|
||||
}
|
||||
if ((nal = ((long)(char *)m) & (M_ALIGN-1))) {
|
||||
if ((char *)sbrk(M_ALIGN - nal) == (char *)-1) {
|
||||
DPUTS(1, "MEM: allocation error at sbrk.");
|
||||
unqueue_signals();
|
||||
return NULL;
|
||||
}
|
||||
m = (struct m_hdr *) ((char *)m + (M_ALIGN - nal));
|
||||
}
|
||||
/* set m_low, for the check in free() */
|
||||
if (!m_low)
|
||||
m_low = (char *)m;
|
||||
|
@ -822,7 +936,7 @@ malloc(MALLOC_ARG_T size)
|
|||
0 for this parameter means: `don't know' */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
zfree(void *p, int sz)
|
||||
{
|
||||
struct m_hdr *m = (struct m_hdr *)(((char *)p) - M_ISIZE), *mp, *mt = NULL;
|
||||
|
@ -1000,12 +1114,18 @@ zfree(void *p, int sz)
|
|||
and now there is more than one page size of memory, we can give
|
||||
it back to the system (and we do it ;-) */
|
||||
if ((((char *)m_lfree) + M_ISIZE + m_lfree->len) == m_high &&
|
||||
m_lfree->len >= m_pgsz + M_MIN) {
|
||||
long n = (m_lfree->len - M_MIN) & ~(m_pgsz - 1);
|
||||
m_lfree->len >= m_pgsz + M_MIN + M_FREE) {
|
||||
long n = (m_lfree->len - M_MIN - M_KEEP) & ~(m_pgsz - 1);
|
||||
|
||||
m_lfree->len -= n;
|
||||
if (brk(m_high -= n) == -1)
|
||||
#ifdef HAVE_BRK
|
||||
if (brk(m_high -= n) == -1) {
|
||||
#else
|
||||
m_high -= n;
|
||||
if (sbrk(-n) == (void *)-1) {
|
||||
#endif /* HAVE_BRK */
|
||||
DPUTS(1, "MEM: allocation error at brk.");
|
||||
}
|
||||
|
||||
#ifdef ZSH_MEM_DEBUG
|
||||
m_b += n;
|
||||
|
@ -1028,7 +1148,7 @@ free(FREE_ARG_T p)
|
|||
those that have a zero byte at the end) */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
zsfree(char *p)
|
||||
{
|
||||
if (p)
|
||||
|
@ -1104,7 +1224,7 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
int i, ii, fi, ui, j;
|
||||
struct m_hdr *m, *mf, *ms;
|
||||
char *b, *c, buf[40];
|
||||
long u = 0, f = 0;
|
||||
long u = 0, f = 0, to, cu;
|
||||
|
||||
if (ops['v']) {
|
||||
printf("The lower and the upper addresses of the heap. Diff gives\n");
|
||||
|
@ -1127,13 +1247,17 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
printf("values, i.e. the number of blocks of that size that is\n");
|
||||
printf("currently allocated. Total is the product of size and diff,\n");
|
||||
printf("i.e. the number of bytes that are allocated for blocks of\n");
|
||||
printf("this size.\n");
|
||||
printf("this size. The last field gives the accumulated number of\n");
|
||||
printf("bytes for all sizes.\n");
|
||||
}
|
||||
printf("\nsize\tmalloc\tfree\tdiff\ttotal\n");
|
||||
for (i = 0; i < 1024; i++)
|
||||
if (m_m[i] || m_f[i])
|
||||
printf("%ld\t%d\t%d\t%d\t%ld\n", (long)i * M_ISIZE, m_m[i], m_f[i],
|
||||
m_m[i] - m_f[i], (long)i * M_ISIZE * (m_m[i] - m_f[i]));
|
||||
printf("\nsize\tmalloc\tfree\tdiff\ttotal\tcum\n");
|
||||
for (i = 0, cu = 0; i < 1024; i++)
|
||||
if (m_m[i] || m_f[i]) {
|
||||
to = (long) i * M_ISIZE * (m_m[i] - m_f[i]);
|
||||
printf("%ld\t%d\t%d\t%d\t%ld\t%ld\n",
|
||||
(long)i * M_ISIZE, m_m[i], m_f[i], m_m[i] - m_f[i],
|
||||
to, (cu += to));
|
||||
}
|
||||
|
||||
if (m_m[i] || m_f[i])
|
||||
printf("big\t%d\t%d\t%d\n", m_m[i], m_f[i], m_m[i] - m_f[i]);
|
||||
|
@ -1157,7 +1281,7 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
printf("blocks is shown. For otherwise used blocks the first few\n");
|
||||
printf("bytes are shown as an ASCII dump.\n");
|
||||
}
|
||||
printf("\nblock list:\nnum\ttnum\taddr\tlen\tstate\tcum\n");
|
||||
printf("\nblock list:\nnum\ttnum\taddr\t\tlen\tstate\tcum\n");
|
||||
for (m = m_l, mf = m_free, ii = fi = ui = 1; ((char *)m) < m_high;
|
||||
m = (struct m_hdr *)(((char *)m) + M_ISIZE + m->len), ii++) {
|
||||
for (j = 0, ms = NULL; j < M_NSMALL && !ms; j++)
|
||||
|
@ -1168,8 +1292,9 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
if (m == mf)
|
||||
buf[0] = '\0';
|
||||
else if (m == ms)
|
||||
sprintf(buf, "%ld %ld %ld", M_SNUM - ms->used, ms->used,
|
||||
(m->len - sizeof(struct m_hdr)) / M_SNUM + 1);
|
||||
sprintf(buf, "%ld %ld %ld", (long)(M_SNUM - ms->used),
|
||||
(long)ms->used,
|
||||
(long)(m->len - sizeof(struct m_hdr)) / M_SNUM + 1);
|
||||
|
||||
else {
|
||||
for (i = 0, b = buf, c = (char *)&m->next; i < 20 && i < m->len;
|
||||
|
@ -1180,7 +1305,7 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
|
||||
printf("%d\t%d\t%ld\t%ld\t%s\t%ld\t%s\n", ii,
|
||||
(m == mf) ? fi++ : ui++,
|
||||
(long)m, m->len,
|
||||
(long)m, (long)m->len,
|
||||
(m == mf) ? "free" : ((m == ms) ? "small" : "used"),
|
||||
(m == mf) ? (f += m->len) : (u += m->len),
|
||||
buf);
|
||||
|
@ -1201,7 +1326,8 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
printf("%ld\t", (long)i * M_ISIZE);
|
||||
|
||||
for (ii = 0, m = m_small[i]; m; m = m->next) {
|
||||
printf("(%ld/%ld) ", M_SNUM - m->used, m->used);
|
||||
printf("(%ld/%ld) ", (long)(M_SNUM - m->used),
|
||||
(long)m->used);
|
||||
if (!((++ii) & 7))
|
||||
printf("\n\t");
|
||||
}
|
||||
|
@ -1233,10 +1359,11 @@ bin_mem(char *name, char **argv, char *ops, int func)
|
|||
|
||||
#endif
|
||||
|
||||
/**/
|
||||
#else /* not ZSH_MEM */
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
zfree(void *p, int sz)
|
||||
{
|
||||
if (p)
|
||||
|
@ -1244,11 +1371,12 @@ zfree(void *p, int sz)
|
|||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
mod_export void
|
||||
zsfree(char *p)
|
||||
{
|
||||
if (p)
|
||||
free(p);
|
||||
}
|
||||
|
||||
/**/
|
||||
#endif
|
||||
|
|
209
Src/params.c
209
Src/params.c
|
@ -455,10 +455,13 @@ void
|
|||
createparamtable(void)
|
||||
{
|
||||
Param ip, pm;
|
||||
char **new_environ, **envp, **envp2, **sigptr, **t;
|
||||
char **old_environ = environ;
|
||||
#ifndef HAVE_PUTENV
|
||||
char **new_environ;
|
||||
int envsize;
|
||||
#endif
|
||||
char **envp, **envp2, **sigptr, **t;
|
||||
char buf[50], *str, *iname, *hostnam;
|
||||
int num_env, oae = opts[ALLEXPORT];
|
||||
int oae = opts[ALLEXPORT];
|
||||
#ifdef HAVE_UNAME
|
||||
struct utsname unamebuf;
|
||||
char *machinebuf;
|
||||
|
@ -501,15 +504,19 @@ createparamtable(void)
|
|||
|
||||
setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username));
|
||||
|
||||
#ifndef HAVE_PUTENV
|
||||
/* Copy the environment variables we are inheriting to dynamic *
|
||||
* memory, so we can do mallocs and frees on it. */
|
||||
num_env = arrlen(environ);
|
||||
new_environ = (char **) zalloc(sizeof(char *) * (num_env + 1));
|
||||
*new_environ = NULL;
|
||||
envsize = sizeof(char *)*(1 + arrlen(environ));
|
||||
new_environ = (char **) zalloc(envsize);
|
||||
memcpy (new_environ, environ, envsize);
|
||||
environ = new_environ;
|
||||
#endif
|
||||
|
||||
/* Now incorporate environment variables we are inheriting *
|
||||
* into the parameter hash table. */
|
||||
for (envp = new_environ, envp2 = environ; *envp2; envp2++) {
|
||||
* into the parameter hash table. Copy them into dynamic *
|
||||
* memory so that we can free them if needed */
|
||||
for (envp = envp2 = environ; *envp2; envp2++) {
|
||||
for (str = *envp2; *str && *str != '='; str++);
|
||||
if (*str == '=') {
|
||||
iname = NULL;
|
||||
|
@ -517,25 +524,22 @@ createparamtable(void)
|
|||
if (!idigit(**envp2) && isident(*envp2) && !strchr(*envp2, '[')) {
|
||||
iname = *envp2;
|
||||
if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
|
||||
!(pm->flags & PM_DONTIMPORT)) &&
|
||||
(pm = setsparam(iname, metafy(str + 1, -1, META_DUP))) &&
|
||||
!(pm->flags & PM_EXPORTED)) {
|
||||
!(pm->flags & PM_DONTIMPORT || pm->flags & PM_EXPORTED)) &&
|
||||
(pm = setsparam(iname, metafy(str + 1, -1, META_DUP)))) {
|
||||
*str = '=';
|
||||
pm->flags |= PM_EXPORTED;
|
||||
pm->env = *envp++ = ztrdup(*envp2);
|
||||
*envp = NULL;
|
||||
if (pm->flags & PM_SPECIAL) {
|
||||
environ = new_environ;
|
||||
pm->env = replenv(pm->env, getsparam(pm->nam),
|
||||
pm->flags);
|
||||
environ = old_environ;
|
||||
}
|
||||
if (pm->flags & PM_SPECIAL)
|
||||
pm->env = mkenvstr (pm->nam,
|
||||
getsparam(pm->nam), pm->flags);
|
||||
else
|
||||
pm->env = ztrdup(*envp2);
|
||||
*envp++ = pm->env;
|
||||
}
|
||||
}
|
||||
*str = '=';
|
||||
}
|
||||
}
|
||||
environ = new_environ;
|
||||
*envp = '\0';
|
||||
opts[ALLEXPORT] = oae;
|
||||
|
||||
pm = (Param) paramtab->getnode(paramtab, "HOME");
|
||||
|
@ -660,7 +664,6 @@ createparam(char *name, int flags)
|
|||
*/
|
||||
if (oldpm->env) {
|
||||
delenv(oldpm->env);
|
||||
zsfree(oldpm->env);
|
||||
oldpm->env = NULL;
|
||||
}
|
||||
paramtab->removenode(paramtab, name);
|
||||
|
@ -1489,7 +1492,7 @@ export_param(Param pm)
|
|||
else
|
||||
val = pm->gets.cfn(pm);
|
||||
if (pm->env)
|
||||
pm->env = replenv(pm->env, val, pm->flags);
|
||||
pm->env = replenv(pm->nam, val, pm->flags);
|
||||
else {
|
||||
pm->flags |= PM_EXPORTED;
|
||||
pm->env = addenv(pm->nam, val, pm->flags);
|
||||
|
@ -2006,7 +2009,6 @@ unsetparam_pm(Param pm, int altflag, int exp)
|
|||
pm->unsetfn(pm, exp);
|
||||
if ((pm->flags & PM_EXPORTED) && pm->env) {
|
||||
delenv(pm->env);
|
||||
zsfree(pm->env);
|
||||
pm->env = NULL;
|
||||
}
|
||||
|
||||
|
@ -2824,8 +2826,7 @@ pipestatsetfn(Param pm, char **x)
|
|||
void
|
||||
arrfixenv(char *s, char **t)
|
||||
{
|
||||
char **ep, *u;
|
||||
int len_s;
|
||||
char *u;
|
||||
Param pm;
|
||||
|
||||
pm = (Param) paramtab->getnode(paramtab, s);
|
||||
|
@ -2838,24 +2839,47 @@ arrfixenv(char *s, char **t)
|
|||
if (pm->flags & PM_HASHELEM)
|
||||
return;
|
||||
u = t ? zjoin(t, ':', 1) : "";
|
||||
len_s = strlen(s);
|
||||
for (ep = environ; *ep; ep++)
|
||||
if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') {
|
||||
pm->env = replenv(*ep, u, pm->flags);
|
||||
return;
|
||||
}
|
||||
if (findenv(s, 0)) {
|
||||
pm->env = replenv(s, u, pm->flags);
|
||||
return;
|
||||
}
|
||||
if (isset(ALLEXPORT))
|
||||
pm->flags |= PM_EXPORTED;
|
||||
if (pm->flags & PM_EXPORTED)
|
||||
pm->env = addenv(s, u, pm->flags);
|
||||
}
|
||||
|
||||
/* Given *name = "foo", it searchs the environment for string *
|
||||
* "foo=bar", and returns a pointer to the beginning of "bar" */
|
||||
#ifndef HAVE_PUTENV
|
||||
|
||||
/**/
|
||||
mod_export char *
|
||||
zgetenv(char *name)
|
||||
static int
|
||||
putenv(char *str)
|
||||
{
|
||||
char **ep;
|
||||
int num_env;
|
||||
|
||||
|
||||
/* First check if there is already an environment *
|
||||
* variable matching string `name'. */
|
||||
if (findenv (str, &num_env)) {
|
||||
environ[num_env] = str;
|
||||
} else {
|
||||
/* Else we have to make room and add it */
|
||||
num_env = arrlen(environ);
|
||||
environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2));
|
||||
|
||||
/* Now add it at the end */
|
||||
ep = environ + num_env;
|
||||
*ep = str;
|
||||
*(ep + 1) = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETENV
|
||||
|
||||
static char *
|
||||
getenv(char *name)
|
||||
{
|
||||
char **ep, *s, *t;
|
||||
|
||||
|
@ -2866,6 +2890,37 @@ zgetenv(char *name)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**/
|
||||
static int
|
||||
findenv (char *name, int *pos)
|
||||
{
|
||||
char **ep, *eq;
|
||||
int nlen;
|
||||
|
||||
|
||||
eq = strchr (name, '=');
|
||||
nlen = eq ? eq - name : strlen (name);
|
||||
for (ep = environ; *ep; ep++)
|
||||
if (!strncmp (*ep, name, nlen) && *((*ep)+nlen) == '=') {
|
||||
if (pos)
|
||||
*pos = ep - environ;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Given *name = "foo", it searchs the environment for string *
|
||||
* "foo=bar", and returns a pointer to the beginning of "bar" */
|
||||
|
||||
/**/
|
||||
mod_export char *
|
||||
zgetenv(char *name)
|
||||
{
|
||||
return getenv(name);
|
||||
}
|
||||
|
||||
/**/
|
||||
static void
|
||||
|
@ -2881,27 +2936,51 @@ copyenvstr(char *s, char *value, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
addenv_internal(char *name, char *value, int flags, int add)
|
||||
{
|
||||
char *oldenv = 0, *newenv = 0, *env = 0;
|
||||
int pos;
|
||||
|
||||
/* First check if there is already an environment *
|
||||
* variable matching string `name'. If not, and *
|
||||
* we are not requested to add new, return */
|
||||
if (findenv (name, &pos))
|
||||
oldenv = environ[pos];
|
||||
else if (!add)
|
||||
return NULL;
|
||||
|
||||
newenv = mkenvstr (name, value, flags);
|
||||
if (putenv (newenv)) {
|
||||
zsfree (newenv);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Under Cygwin we must use putenv() to maintain consistency.
|
||||
* Unfortunately, current version (1.1.2) copies argument and may
|
||||
* silently reuse exisiting environment string. This tries to
|
||||
* check for both cases
|
||||
*/
|
||||
if (findenv (name, &pos)) {
|
||||
env = environ[pos];
|
||||
if (env != oldenv)
|
||||
zsfree (oldenv);
|
||||
if (env != newenv)
|
||||
zsfree (newenv);
|
||||
return env;
|
||||
}
|
||||
|
||||
return NULL; /* Cannot happen */
|
||||
}
|
||||
|
||||
/* Change the value of an existing environment variable */
|
||||
|
||||
/**/
|
||||
char *
|
||||
replenv(char *e, char *value, int flags)
|
||||
replenv(char *name, char *value, int flags)
|
||||
{
|
||||
char **ep, *s;
|
||||
int len_value;
|
||||
|
||||
for (ep = environ; *ep; ep++)
|
||||
if (*ep == e) {
|
||||
for (len_value = 0, s = value;
|
||||
*s && (*s++ != Meta || *s++ != 32); len_value++);
|
||||
s = e;
|
||||
while (*s++ != '=');
|
||||
*ep = (char *) zrealloc(e, s - e + len_value + 1);
|
||||
s = s - e + *ep - 1;
|
||||
copyenvstr(s, value, flags);
|
||||
return *ep;
|
||||
}
|
||||
return NULL;
|
||||
return addenv_internal (name, value, flags, 0);
|
||||
}
|
||||
|
||||
/* Given strings *name = "foo", *value = "bar", *
|
||||
|
@ -2934,28 +3013,7 @@ mkenvstr(char *name, char *value, int flags)
|
|||
char *
|
||||
addenv(char *name, char *value, int flags)
|
||||
{
|
||||
char **ep, *s, *t;
|
||||
int num_env;
|
||||
|
||||
/* First check if there is already an environment *
|
||||
* variable matching string `name'. */
|
||||
for (ep = environ; *ep; ep++) {
|
||||
for (s = *ep, t = name; *s && *s == *t; s++, t++);
|
||||
if (*s == '=' && !*t) {
|
||||
zsfree(*ep);
|
||||
return *ep = mkenvstr(name, value, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Else we have to make room and add it */
|
||||
num_env = arrlen(environ);
|
||||
environ = (char **) zrealloc(environ, (sizeof(char *)) * (num_env + 2));
|
||||
|
||||
/* Now add it at the end */
|
||||
ep = environ + num_env;
|
||||
*ep = mkenvstr(name, value, flags);
|
||||
*(ep + 1) = NULL;
|
||||
return *ep;
|
||||
return addenv_internal (name, value, flags, 1);
|
||||
}
|
||||
|
||||
/* Delete a pointer from the list of pointers to environment *
|
||||
|
@ -2971,8 +3029,10 @@ delenv(char *x)
|
|||
if (*ep == x)
|
||||
break;
|
||||
}
|
||||
if (*ep)
|
||||
if (*ep) {
|
||||
for (; (ep[0] = ep[1]); ep++);
|
||||
}
|
||||
zsfree(x);
|
||||
}
|
||||
|
||||
/**/
|
||||
|
@ -3105,7 +3165,6 @@ scanendscope(HashNode hn, int flags)
|
|||
pm->ct = tpm->ct;
|
||||
if (pm->env) {
|
||||
delenv(pm->env);
|
||||
zsfree(pm->env);
|
||||
}
|
||||
pm->env = NULL;
|
||||
|
||||
|
|
|
@ -861,7 +861,9 @@ AC_CHECK_FUNCS(strftime difftime gettimeofday \
|
|||
getrlimit \
|
||||
setlocale \
|
||||
uname \
|
||||
signgam)
|
||||
signgam \
|
||||
putenv getenv \
|
||||
brk sbrk)
|
||||
AC_FUNC_STRCOLL
|
||||
|
||||
if test $ac_cv_func_setpgrp = yes; then
|
||||
|
|
Loading…
Reference in a new issue