1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                  Common Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*            http://www.opensource.org/licenses/cpl1.0.txt             *
11*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                 Glenn Fowler <gsf@research.att.com>                  *
18*                  David Korn <dgk@research.att.com>                   *
19*                   Phong Vo <kpv@research.att.com>                    *
20*                                                                      *
21***********************************************************************/
22#if defined(_UWIN) && defined(_BLD_ast)
23
24void _STUB_malloc(){}
25
26#else
27
28#if _UWIN
29
30#define calloc		______calloc
31#define _ast_free	______free
32#define malloc		______malloc
33#define mallinfo	______mallinfo
34#define mallopt		______mallopt
35#define mstats		______mstats
36#define realloc		______realloc
37
38#define _STDLIB_H_	1
39
40extern int		atexit(void(*)(void));
41extern char*		getenv(const char*);
42
43#endif
44
45#include	"vmhdr.h"
46#include	<errno.h>
47
48#if _UWIN
49
50#include	<malloc.h>
51
52#define _map_malloc	1
53#define _mal_alloca	1
54
55#undef	calloc
56#define calloc		_ast_calloc
57#undef	_ast_free
58#define free		_ast_free
59#undef	malloc
60#define malloc		_ast_malloc
61#undef	mallinfo
62typedef struct ______mallinfo Mallinfo_t;
63#undef	mallopt
64#undef	mstats
65typedef struct ______mstats Mstats_t;
66#undef	realloc
67#define realloc		_ast_realloc
68
69#endif
70
71#if __STD_C
72#define F0(f,t0)		f(t0)
73#define F1(f,t1,a1)		f(t1 a1)
74#define F2(f,t1,a1,t2,a2)	f(t1 a1, t2 a2)
75#else
76#define F0(f,t0)		f()
77#define F1(f,t1,a1)		f(a1) t1 a1;
78#define F2(f,t1,a1,t2,a2)	f(a1, a2) t1 a1; t2 a2;
79#endif
80
81/*
82 * define _AST_std_malloc=1 to force the standard malloc
83 * if _map_malloc is also defined then _ast_malloc etc.
84 * will simply call malloc etc.
85 */
86
87#if !defined(_AST_std_malloc) && __CYGWIN__
88#define _AST_std_malloc	1
89#endif
90
91/*	malloc compatibility functions
92**
93**	These are aware of debugging/profiling and are driven by the
94**	VMALLOC_OPTIONS environment variable which is a space-separated
95**	list of [no]name[=value] options:
96**
97**	    abort	if Vmregion==Vmdebug then VM_DBABORT is set,
98**			otherwise _BLD_debug enabled assertions abort()
99**			on failure
100**	    check	if Vmregion==Vmbest then the region is checked every op
101**	    method=m	sets Vmregion=m if not defined, m (Vm prefix optional)
102**			may be one of { best debug last profile }
103**	    mmap	prefer mmap() over brk() for region allocation
104**	    period=n	sets Vmregion=Vmdebug if not defined, if
105**			Vmregion==Vmdebug the region is checked every n ops
106**	    profile=f	sets Vmregion=Vmprofile if not set, if
107**			Vmregion==Vmprofile then profile info printed to file f
108**	    region	if Vmregion==Vmbest then block free verifies
109**			that the block belongs to the region
110**	    start=n	sets Vmregion=Vmdebug if not defined, if
111**			Vmregion==Vmdebug region checking starts after n ops
112**	    trace=f	enables tracing to file f
113**	    warn=f	sets Vmregion=Vmdebug if not defined, if
114**			Vmregion==Vmdebug then warnings printed to file f
115**	    watch=a	sets Vmregion=Vmdebug if not defined, if
116**			Vmregion==Vmdebug then address a is watched
117**
118**	Output files are created if they don't exist. &n and /dev/fd/n name
119**	the file descriptor n which must be open for writing. The pattern %p
120**	in a file name is replaced by the process ID.
121**
122**	VMALLOC_OPTIONS combines the features of these previously used env vars:
123**	    { VMDEBUG VMETHOD VMPROFILE VMTRACE }
124**
125**	Written by Kiem-Phong Vo, kpv@research.att.com, 01/16/94.
126*/
127
128#if _sys_stat
129#include	<sys/stat.h>
130#endif
131#include	<fcntl.h>
132
133#ifdef S_IRUSR
134#define CREAT_MODE	(S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
135#else
136#define CREAT_MODE	0644
137#endif
138
139static Vmulong_t	_Vmdbstart = 0;
140static Vmulong_t	_Vmdbcheck = 0;
141static Vmulong_t	_Vmdbtime = 0;
142static int		_Vmpffd = -1;
143
144#if ( !_std_malloc || !_BLD_ast ) && !_AST_std_malloc
145
146#if !_map_malloc
147#undef calloc
148#undef cfree
149#undef free
150#undef mallinfo
151#undef malloc
152#undef mallopt
153#undef memalign
154#undef mstats
155#undef realloc
156#undef valloc
157#endif
158
159#if _WINIX
160
161#include <ast_windows.h>
162
163#if _UWIN
164
165#define VMRECORD(p)	_vmrecord(p)
166#define VMBLOCK		{ int _vmblock = _sigblock();
167#define VMUNBLOCK	_sigunblock(_vmblock); }
168
169extern int		_sigblock(void);
170extern void		_sigunblock(int);
171extern unsigned long	_record[2048];
172
173__inline Void_t* _vmrecord(Void_t* p)
174{
175	register unsigned long	v = ((unsigned long)p)>>16;
176
177	_record[v>>5] |= 1<<((v&0x1f));
178	return p;
179}
180
181#else
182
183#define getenv(s)	lcl_getenv(s)
184
185static char*
186lcl_getenv(const char* s)
187{
188	int		n;
189	static char	buf[512];
190
191	if (!(n = GetEnvironmentVariable(s, buf, sizeof(buf))) || n > sizeof(buf))
192		return 0;
193	return buf;
194}
195
196#endif /* _UWIN */
197
198#endif /* _WINIX */
199
200#ifndef VMRECORD
201#define VMRECORD(p)	(p)
202#define VMBLOCK
203#define VMUNBLOCK
204#endif
205
206#if defined(__EXPORT__)
207#define extern		extern __EXPORT__
208#endif
209
210static int		_Vmflinit = 0;
211#define VMFLINIT() \
212	{ if(!_Vmflinit)	vmflinit(); \
213	  if(_Vmdbcheck) \
214	  { if(_Vmdbtime < _Vmdbstart) _Vmdbtime += 1; \
215	    else if((_Vmdbtime += 1) < _Vmdbstart) _Vmdbtime = _Vmdbstart; \
216	    if(_Vmdbtime >= _Vmdbstart && (_Vmdbtime % _Vmdbcheck) == 0 && \
217	       Vmregion->meth.meth == VM_MTDEBUG) \
218		vmdbcheck(Vmregion); \
219	  } \
220	}
221
222#if __STD_C
223static int vmflinit(void)
224#else
225static int vmflinit()
226#endif
227{
228	char*		file;
229	int		line;
230	Void_t*		func;
231
232	/* this must be done now to avoid any inadvertent recursion (more below) */
233	_Vmflinit = 1;
234	VMFLF(Vmregion,file,line,func);
235
236	/* if getenv() calls malloc(), the options may not affect the eventual region */
237	VMOPTIONS();
238
239	/* reset file and line number to correct values for the call */
240	Vmregion->file = file;
241	Vmregion->line = line;
242	Vmregion->func = func;
243
244	return 0;
245}
246
247#if __STD_C
248extern Void_t* calloc(reg size_t n_obj, reg size_t s_obj)
249#else
250extern Void_t* calloc(n_obj, s_obj)
251reg size_t	n_obj;
252reg size_t	s_obj;
253#endif
254{
255	VMFLINIT();
256	return VMRECORD((*Vmregion->meth.resizef)(Vmregion,NIL(Void_t*),n_obj*s_obj,VM_RSZERO));
257}
258
259#if __STD_C
260extern Void_t* malloc(reg size_t size)
261#else
262extern Void_t* malloc(size)
263reg size_t	size;
264#endif
265{
266	VMFLINIT();
267	return VMRECORD((*Vmregion->meth.allocf)(Vmregion,size));
268}
269
270#if __STD_C
271extern Void_t* realloc(reg Void_t* data, reg size_t size)
272#else
273extern Void_t* realloc(data,size)
274reg Void_t*	data;	/* block to be reallocated	*/
275reg size_t	size;	/* new size			*/
276#endif
277{
278#if USE_NATIVE
279#undef	realloc
280#if __STD_C
281	extern Void_t*	realloc(Void_t*, size_t);
282#else
283	extern Void_t*	realloc();
284#endif
285#endif
286
287	VMFLINIT();
288
289#if _PACKAGE_ast
290	if(data && Vmregion->meth.meth != VM_MTDEBUG &&
291#if !USE_NATIVE
292	   !(Vmregion->data->mode&VM_TRUST) &&
293#endif
294	   (*Vmregion->meth.addrf)(Vmregion,data) != 0 )
295	{
296#if USE_NATIVE
297		return realloc(data, size);
298#else
299		Void_t*	newdata;
300		if((newdata = (*Vmregion->meth.allocf)(Vmregion,size)) )
301			memcpy(newdata,data,size);
302		return VMRECORD(newdata);
303#endif
304	}
305#endif
306
307#if USE_NATIVE
308	{	Void_t*	newdata;
309		if (newdata = (*Vmregion->meth.resizef)(Vmregion,data,size,VM_RSCOPY|VM_RSMOVE))
310			return newdata;
311		return VMRECORD(realloc(data, size));
312	}
313#else
314	return VMRECORD((*Vmregion->meth.resizef)(Vmregion,data,size,VM_RSCOPY|VM_RSMOVE));
315#endif
316}
317
318#if __STD_C
319extern void free(reg Void_t* data)
320#else
321extern void free(data)
322reg Void_t*	data;
323#endif
324{
325#if USE_NATIVE
326#undef	free
327#if __STD_C
328	extern void	free(Void_t*);
329#else
330	extern void	free();
331#endif
332#endif
333
334	VMFLINIT();
335
336#if _PACKAGE_ast
337	if(data && Vmregion->meth.meth != VM_MTDEBUG &&
338#if !USE_NATIVE
339	   !(Vmregion->data->mode&VM_TRUST) &&
340#endif
341	   (*Vmregion->meth.addrf)(Vmregion,data) != 0)
342	{
343#if USE_NATIVE
344		free(data);
345#endif
346		return;
347	}
348#endif
349
350#if USE_NATIVE
351	if ((*Vmregion->meth.freef)(Vmregion,data) != 0)
352		free(data);
353#else
354	(void)(*Vmregion->meth.freef)(Vmregion,data);
355#endif
356}
357
358#if __STD_C
359extern void cfree(reg Void_t* data)
360#else
361extern void cfree(data)
362reg Void_t*	data;
363#endif
364{
365	free(data);
366}
367
368#if __STD_C
369extern Void_t* memalign(reg size_t align, reg size_t size)
370#else
371extern Void_t* memalign(align, size)
372reg size_t	align;
373reg size_t	size;
374#endif
375{
376	Void_t*	addr;
377
378	VMFLINIT();
379	VMBLOCK
380	addr = VMRECORD((*Vmregion->meth.alignf)(Vmregion,size,align));
381	VMUNBLOCK
382	return addr;
383}
384
385#if __STD_C
386extern int posix_memalign(reg Void_t **memptr, reg size_t align, reg size_t size)
387#else
388extern int posix_memalign(memptr, align, size)
389reg Void_t**	memptr;
390reg size_t	align;
391reg size_t	size;
392#endif
393{
394	Void_t	*mem;
395
396	if(align == 0 || (align%sizeof(Void_t*)) != 0 || ((align-1)&align) != 0 )
397		return EINVAL;
398
399	if(!(mem = memalign(align, size)) )
400		return ENOMEM;
401
402	*memptr = mem;
403	return 0;
404}
405
406#if __STD_C
407extern Void_t* valloc(reg size_t size)
408#else
409extern Void_t* valloc(size)
410reg size_t	size;
411#endif
412{
413	VMFLINIT();
414	GETPAGESIZE(_Vmpagesize);
415	return VMRECORD((*Vmregion->meth.alignf)(Vmregion,size,_Vmpagesize));
416}
417
418#if __STD_C
419extern Void_t* pvalloc(reg size_t size)
420#else
421extern Void_t* pvalloc(size)
422reg size_t	size;
423#endif
424{
425	VMFLINIT();
426	GETPAGESIZE(_Vmpagesize);
427	return VMRECORD((*Vmregion->meth.alignf)(Vmregion,ROUND(size,_Vmpagesize),_Vmpagesize));
428}
429
430#if !_PACKAGE_ast
431#if __STD_C
432char* strdup(const char* s)
433#else
434char* strdup(s)
435char*	s;
436#endif
437{
438	char	*ns;
439	size_t	n;
440
441	if(!s)
442		return NIL(char*);
443	else
444	{	n = strlen(s);
445		if((ns = malloc(n+1)) )
446			memcpy(ns,s,n+1);
447		return ns;
448	}
449}
450#endif /* _PACKAGE_ast */
451
452#if !_lib_alloca || _mal_alloca
453#ifndef _stk_down
454#define _stk_down	0
455#endif
456typedef struct _alloca_s	Alloca_t;
457union _alloca_u
458{	struct
459	{	char*		addr;
460		Alloca_t*	next;
461	} head;
462	char	array[ALIGN];
463};
464struct _alloca_s
465{	union _alloca_u	head;
466	Vmuchar_t	data[1];
467};
468
469#if __STD_C
470extern Void_t* alloca(size_t size)
471#else
472extern Void_t* alloca(size)
473size_t	size;
474#endif
475{	char		array[ALIGN];
476	char*		file;
477	int		line;
478	Void_t*		func;
479	reg Alloca_t*	f;
480	static Alloca_t* Frame;
481
482	VMFLINIT();
483	VMFLF(Vmregion,file,line,func);
484	while(Frame)
485	{	if(( _stk_down && &array[0] > Frame->head.head.addr) ||
486		   (!_stk_down && &array[0] < Frame->head.head.addr) )
487		{	f = Frame;
488			Frame = f->head.head.next;
489			(void)(*Vmregion->meth.freef)(Vmregion,f);
490		}
491		else	break;
492	}
493
494	Vmregion->file = file;
495	Vmregion->line = line;
496	Vmregion->func = func;
497	f = (Alloca_t*)(*Vmregion->meth.allocf)(Vmregion,size+sizeof(Alloca_t)-1);
498
499	f->head.head.addr = &array[0];
500	f->head.head.next = Frame;
501	Frame = f;
502
503	return (Void_t*)f->data;
504}
505#endif /*!_lib_alloca || _mal_alloca*/
506
507#if _map_malloc
508
509/* not sure of all the implications -- 0 is conservative for now */
510#define USE_NATIVE	0	/* native free/realloc on non-vmalloc ptrs */
511
512#else
513
514/* intercept _* __* __libc_* variants */
515
516#if __lib__malloc
517extern Void_t*	F2(_calloc, size_t,n, size_t,m) { return calloc(n, m); }
518extern Void_t	F1(_cfree, Void_t*,p) { free(p); }
519extern Void_t	F1(_free, Void_t*,p) { free(p); }
520extern Void_t*	F1(_malloc, size_t,n) { return malloc(n); }
521#if _lib_memalign
522extern Void_t*	F2(_memalign, size_t,a, size_t,n) { return memalign(a, n); }
523#endif
524#if _lib_pvalloc
525extern Void_t*	F1(_pvalloc, size_t,n) { return pvalloc(n); }
526#endif
527extern Void_t*	F2(_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
528#if _lib_valloc
529extern Void_t*	F1(_valloc, size_t,n) { return valloc(n); }
530#endif
531#endif
532
533#if _lib___malloc
534extern Void_t*	F2(__calloc, size_t,n, size_t,m) { return calloc(n, m); }
535extern Void_t	F1(__cfree, Void_t*,p) { free(p); }
536extern Void_t	F1(__free, Void_t*,p) { free(p); }
537extern Void_t*	F1(__malloc, size_t,n) { return malloc(n); }
538#if _lib_memalign
539extern Void_t*	F2(__memalign, size_t,a, size_t,n) { return memalign(a, n); }
540#endif
541#if _lib_pvalloc
542extern Void_t*	F1(__pvalloc, size_t,n) { return pvalloc(n); }
543#endif
544extern Void_t*	F2(__realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
545#if _lib_valloc
546extern Void_t*	F1(__valloc, size_t,n) { return valloc(n); }
547#endif
548#endif
549
550#if _lib___libc_malloc
551extern Void_t*	F2(__libc_calloc, size_t,n, size_t,m) { return calloc(n, m); }
552extern Void_t	F1(__libc_cfree, Void_t*,p) { free(p); }
553extern Void_t	F1(__libc_free, Void_t*,p) { free(p); }
554extern Void_t*	F1(__libc_malloc, size_t,n) { return malloc(n); }
555#if _lib_memalign
556extern Void_t*	F2(__libc_memalign, size_t,a, size_t,n) { return memalign(a, n); }
557#endif
558#if _lib_pvalloc
559extern Void_t*	F1(__libc_pvalloc, size_t,n) { return pvalloc(n); }
560#endif
561extern Void_t*	F2(__libc_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
562#if _lib_valloc
563extern Void_t*	F1(__libc_valloc, size_t,n) { return valloc(n); }
564#endif
565#endif
566
567#endif /* _map_malloc */
568
569#undef	extern
570
571#if _hdr_malloc /* need the mallint interface for statistics, etc. */
572
573#undef	calloc
574#define calloc		______calloc
575#undef	cfree
576#define cfree		______cfree
577#undef	free
578#define free		______free
579#undef	malloc
580#define malloc		______malloc
581#undef	pvalloc
582#define pvalloc		______pvalloc
583#undef	realloc
584#define realloc		______realloc
585#undef	valloc
586#define valloc		______valloc
587
588#if !_UWIN
589
590#include	<malloc.h>
591
592typedef struct mallinfo Mallinfo_t;
593typedef struct mstats Mstats_t;
594
595#endif
596
597#if defined(__EXPORT__)
598#define extern		__EXPORT__
599#endif
600
601#if _lib_mallopt
602#if __STD_C
603extern int mallopt(int cmd, int value)
604#else
605extern int mallopt(cmd, value)
606int	cmd;
607int	value;
608#endif
609{
610	VMFLINIT();
611	return 0;
612}
613#endif /*_lib_mallopt*/
614
615#if _lib_mallinfo && _mem_arena_mallinfo
616#if __STD_C
617extern Mallinfo_t mallinfo(void)
618#else
619extern Mallinfo_t mallinfo()
620#endif
621{
622	Vmstat_t	sb;
623	Mallinfo_t	mi;
624
625	VMFLINIT();
626	memset(&mi,0,sizeof(mi));
627	if(vmstat(Vmregion,&sb) >= 0)
628	{	mi.arena = sb.extent;
629		mi.ordblks = sb.n_busy+sb.n_free;
630		mi.uordblks = sb.s_busy;
631		mi.fordblks = sb.s_free;
632	}
633	return mi;
634}
635#endif /* _lib_mallinfo */
636
637#if _lib_mstats && _mem_bytes_total_mstats
638#if __STD_C
639extern Mstats_t mstats(void)
640#else
641extern Mstats_t mstats()
642#endif
643{
644	Vmstat_t	sb;
645	Mstats_t	ms;
646
647	VMFLINIT();
648	memset(&ms,0,sizeof(ms));
649	if(vmstat(Vmregion,&sb) >= 0)
650	{	ms.bytes_total = sb.extent;
651		ms.chunks_used = sb.n_busy;
652		ms.bytes_used = sb.s_busy;
653		ms.chunks_free = sb.n_free;
654		ms.bytes_free = sb.s_free;
655	}
656	return ms;
657}
658#endif /*_lib_mstats*/
659
660#undef	extern
661
662#endif/*_hdr_malloc*/
663
664#else
665
666/*
667 * even though there is no malloc override, still provide
668 * _ast_* counterparts for object compatibility
669 */
670
671#undef	calloc
672extern Void_t*	calloc _ARG_((size_t, size_t));
673
674#undef	cfree
675extern void	cfree _ARG_((Void_t*));
676
677#undef	free
678extern void	free _ARG_((Void_t*));
679
680#undef	malloc
681extern Void_t*	malloc _ARG_((size_t));
682
683#if _lib_memalign
684#undef	memalign
685extern Void_t*	memalign _ARG_((size_t, size_t));
686#endif
687
688#if _lib_pvalloc
689#undef	pvalloc
690extern Void_t*	pvalloc _ARG_((size_t));
691#endif
692
693#undef	realloc
694extern Void_t*	realloc _ARG_((Void_t*, size_t));
695
696#if _lib_valloc
697#undef	valloc
698extern Void_t*	valloc _ARG_((size_t));
699#endif
700
701#if defined(__EXPORT__)
702#define extern		__EXPORT__
703#endif
704
705extern Void_t*	F2(_ast_calloc, size_t,n, size_t,m) { return calloc(n, m); }
706extern Void_t	F1(_ast_cfree, Void_t*,p) { free(p); }
707extern Void_t	F1(_ast_free, Void_t*,p) { free(p); }
708extern Void_t*	F1(_ast_malloc, size_t,n) { return malloc(n); }
709#if _lib_memalign
710extern Void_t*	F2(_ast_memalign, size_t,a, size_t,n) { return memalign(a, n); }
711#endif
712#if _lib_pvalloc
713extern Void_t*	F1(_ast_pvalloc, size_t,n) { return pvalloc(n); }
714#endif
715extern Void_t*	F2(_ast_realloc, Void_t*,p, size_t,n) { return realloc(p, n); }
716#if _lib_valloc
717extern Void_t*	F1(_ast_valloc, size_t,n) { return valloc(n); }
718#endif
719
720#undef	extern
721
722#if _hdr_malloc
723
724#undef	mallinfo
725#undef	mallopt
726#undef	mstats
727
728#define calloc		______calloc
729#define cfree		______cfree
730#define free		______free
731#define malloc		______malloc
732#define pvalloc		______pvalloc
733#define realloc		______realloc
734#define valloc		______valloc
735
736#if !_UWIN
737
738#include	<malloc.h>
739
740typedef struct mallinfo Mallinfo_t;
741typedef struct mstats Mstats_t;
742
743#endif
744
745#if defined(__EXPORT__)
746#define extern		__EXPORT__
747#endif
748
749#if _lib_mallopt
750extern int	F2(_ast_mallopt, int,cmd, int,value) { return mallopt(cmd, value); }
751#endif
752
753#if _lib_mallinfo && _mem_arena_mallinfo
754extern Mallinfo_t	F0(_ast_mallinfo, void) { return mallinfo(); }
755#endif
756
757#if _lib_mstats && _mem_bytes_total_mstats
758extern Mstats_t		F0(_ast_mstats, void) { return mstats(); }
759#endif
760
761#undef	extern
762
763#endif /*_hdr_malloc*/
764
765#endif /*!_std_malloc*/
766
767#if __STD_C
768static Vmulong_t atou(char** sp)
769#else
770static Vmulong_t atou(sp)
771char**	sp;
772#endif
773{
774	char*		s = *sp;
775	Vmulong_t	v = 0;
776
777	if(s[0] == '0' && (s[1] == 'x' || s[1] == 'X') )
778	{	for(s += 2; *s; ++s)
779		{	if(*s >= '0' && *s <= '9')
780				v = (v << 4) + (*s - '0');
781			else if(*s >= 'a' && *s <= 'f')
782				v = (v << 4) + (*s - 'a') + 10;
783			else if(*s >= 'A' && *s <= 'F')
784				v = (v << 4) + (*s - 'A') + 10;
785			else break;
786		}
787	}
788	else
789	{	for(; *s; ++s)
790		{	if(*s >= '0' && *s <= '9')
791				v = v*10 + (*s - '0');
792			else break;
793		}
794	}
795
796	*sp = s;
797	return v;
798}
799
800#if __STD_C
801static char* insertpid(char* begs, char* ends)
802#else
803static char* insertpid(begs,ends)
804char*	begs;
805char*	ends;
806#endif
807{	int	pid;
808	char*	s;
809
810	if((pid = getpid()) < 0)
811		return NIL(char*);
812
813	s = ends;
814	do
815	{	if(s == begs)
816			return NIL(char*);
817		*--s = '0' + pid%10;
818	} while((pid /= 10) > 0);
819	while(s < ends)
820		*begs++ = *s++;
821
822	return begs;
823}
824
825#if __STD_C
826static int createfile(char* file)
827#else
828static int createfile(file)
829char*	file;
830#endif
831{
832	char	buf[1024];
833	char	*next, *endb;
834	int	fd;
835
836	next = buf;
837	endb = buf + sizeof(buf);
838	while(*file)
839	{	if(*file == '%')
840		{	switch(file[1])
841			{
842			case 'p' :
843				if(!(next = insertpid(next,endb)) )
844					return -1;
845				file += 2;
846				break;
847			default :
848				goto copy;
849			}
850		}
851		else
852		{ copy:
853			*next++ = *file++;
854		}
855
856		if(next >= endb)
857			return -1;
858	}
859
860	*next = '\0';
861	file = buf;
862	if (*file == '&' && *(file += 1) || strncmp(file, "/dev/fd/", 8) == 0 && *(file += 8))
863		fd = dup((int)atou(&file));
864	else if (*file)
865#if _PACKAGE_ast
866		fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, CREAT_MODE);
867#else
868		fd = creat(file, CREAT_MODE);
869#endif
870	else
871		return -1;
872#if _PACKAGE_ast
873#ifdef FD_CLOEXEC
874	if (fd >= 0)
875		fcntl(fd, F_SETFD, FD_CLOEXEC);
876#endif
877#endif
878	return fd;
879}
880
881#if __STD_C
882static void pfprint(void)
883#else
884static void pfprint()
885#endif
886{
887	if(Vmregion->meth.meth == VM_MTPROFILE)
888		vmprofile(Vmregion,_Vmpffd);
889}
890
891/*
892 * initialize runtime options from the VMALLOC_OPTIONS env var
893 */
894
895#define COPY(t,e,f)	while ((*t = *f++) && t < e) t++
896
897#if __STD_C
898void _vmoptions(void)
899#else
900void _vmoptions()
901#endif
902{
903	Vmalloc_t*	vm = 0;
904	char*		trace = 0;
905	char*		s;
906	char*		t;
907	char*		v;
908	Vmulong_t	n;
909	int		fd;
910	char		buf[1024];
911
912	_Vmoptions = 1;
913	t = buf;
914	v = &buf[sizeof(buf)-1];
915	if (s = getenv("VMALLOC_OPTIONS"))
916		COPY(t, v, s);
917#if 1 /* backwards compatibility until 2011 */
918	else
919	{
920		char*	p;
921
922		if (s = getenv("VMDEBUG"))
923		{
924			switch (*s++)
925			{
926			case 0:
927				break;
928			case 'a':
929				p = " abort";
930				COPY(t, v, p);
931				break;
932			case 'w':
933				p = " warn";
934				COPY(t, v, p);
935				break;
936			case '0':
937				if (*s-- == 'x')
938				{
939					p = " watch=";
940					COPY(t, v, p);
941					COPY(t, v, s);
942					break;
943				}
944				/*FALLTHROUGH*/
945			default:
946				p = " period=";
947				COPY(t, v, p);
948				COPY(t, v, s);
949				break;
950			}
951		}
952		if ((s = getenv("VMETHOD")) && *s)
953		{
954			p = " method=";
955			COPY(t, v, p);
956			COPY(t, v, s);
957		}
958		if ((s = getenv("VMPROFILE")) && *s)
959		{
960			p = " profile=";
961			COPY(t, v, p);
962			COPY(t, v, s);
963		}
964		if ((s = getenv("VMTRACE")) && *s)
965		{
966			p = " trace=";
967			COPY(t, v, p);
968			COPY(t, v, s);
969		}
970	}
971#endif
972	if (t > buf)
973	{
974		*t = 0;
975		s = buf;
976		for (;;)
977		{
978			while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
979				s++;
980			if (!*(t = s))
981				break;
982			v = 0;
983			while (*s)
984				if (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
985				{
986					*s++ = 0;
987					break;
988				}
989				else if (!v && *s == '=')
990				{
991					*s++ = 0;
992					if (!*(v = s))
993						v = 0;
994				}
995				else
996					s++;
997			if (t[0] == 'n' && t[1] == 'o')
998				continue;
999			switch (t[0])
1000			{
1001			case 'a':		/* abort */
1002				if (!vm)
1003					vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1004				if (vm && vm->meth.meth == VM_MTDEBUG)
1005					vmset(vm, VM_DBABORT, 1);
1006				else
1007					_Vmassert |= VM_abort;
1008				break;
1009			case 'c':		/* check */
1010				_Vmassert |= VM_check;
1011				break;
1012			case 'm':
1013				switch (t[1])
1014				{
1015				case 'e':	/* method=<method> */
1016					if (v && !vm)
1017					{
1018						if ((v[0] == 'V' || v[0] == 'v') && (v[1] == 'M' || v[1] == 'm'))
1019							v += 2;
1020						if (strcmp(v, "debug") == 0)
1021							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1022						else if (strcmp(v, "profile") == 0)
1023							vm = vmopen(Vmdcsbrk, Vmprofile, 0);
1024						else if (strcmp(v, "last") == 0)
1025							vm = vmopen(Vmdcsbrk, Vmlast, 0);
1026						else if (strcmp(v, "best") == 0)
1027							vm = Vmheap;
1028					}
1029					break;
1030				case 'm':	/* mmap */
1031#if _mem_mmap_anon || _mem_mmap_zero
1032					_Vmassert |= VM_mmap;
1033#endif
1034					break;
1035				}
1036				break;
1037			case 'p':
1038				if (v)
1039					switch (t[1])
1040					{
1041					case 'e':	/* period=<count> */
1042						if (!vm)
1043							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1044						if (vm && vm->meth.meth == VM_MTDEBUG)
1045							_Vmdbcheck = atou(&v);
1046						break;
1047					case 'r':	/* profile=<path> */
1048						if (!vm)
1049							vm = vmopen(Vmdcsbrk, Vmprofile, 0);
1050						if (v && vm && vm->meth.meth == VM_MTPROFILE)
1051							_Vmpffd = createfile(v);
1052						break;
1053					}
1054				break;
1055			case 'r':		/* region */
1056				_Vmassert |= VM_region;
1057				break;
1058			case 's':		/* start=<count> */
1059				if (!vm)
1060					vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1061				if (v && vm && vm->meth.meth == VM_MTDEBUG)
1062					_Vmdbstart = atou(&v);
1063				break;
1064			case 't':		/* trace=<path> */
1065				trace = v;
1066				break;
1067			case 'w':
1068				if (t[1] == 'a')
1069					switch (t[2])
1070					{
1071					case 'r':	/* warn=<path> */
1072						if (!vm)
1073							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1074						if (v && vm && vm->meth.meth == VM_MTDEBUG && (fd = createfile(v)) >= 0)
1075							vmdebug(fd);
1076						break;
1077					case 't':	/* watch=<addr> */
1078						if (!vm)
1079							vm = vmopen(Vmdcsbrk, Vmdebug, 0);
1080						if (v && vm && vm->meth.meth == VM_MTDEBUG && (n = atou(&v)) >= 0)
1081							vmdbwatch((Void_t*)n);
1082						break;
1083					}
1084				break;
1085			}
1086		}
1087	}
1088
1089	/* slip in the new region now so that malloc() will work fine */
1090
1091	if (vm)
1092	{
1093		if (vm->meth.meth == VM_MTDEBUG)
1094			_Vmdbcheck = 1;
1095		Vmregion = vm;
1096	}
1097
1098	/* enable tracing */
1099
1100	if (trace && (fd = createfile(trace)) >= 0)
1101	{
1102		vmset(Vmregion, VM_TRACE, 1);
1103		vmtrace(fd);
1104	}
1105
1106	/* make sure that profile data is output upon exiting */
1107
1108	if (vm && vm->meth.meth == VM_MTPROFILE)
1109	{
1110		if (_Vmpffd < 0)
1111			_Vmpffd = 2;
1112		/* this may wind up calling malloc(), but region is ok now */
1113		atexit(pfprint);
1114	}
1115	else if (_Vmpffd >= 0)
1116	{
1117		close(_Vmpffd);
1118		_Vmpffd = -1;
1119	}
1120}
1121
1122#endif /*_UWIN*/
1123