12411, 12419: Andrej: environment handling with fewer assumptions

This commit is contained in:
Peter Stephenson 2000-07-28 09:10:35 +00:00
parent 19b4ca246a
commit 4a5882eeb3
5 changed files with 411 additions and 215 deletions

View file

@ -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

View file

@ -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
View file

@ -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

View file

@ -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;

View file

@ -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