diff options
Diffstat (limited to 'libc')
53 files changed, 2415 insertions, 475 deletions
diff --git a/libc/inet/Makefile b/libc/inet/Makefile index de5d90d74..56e783ceb 100644 --- a/libc/inet/Makefile +++ b/libc/inet/Makefile @@ -66,8 +66,8 @@ $(MOBJ3): $(MSRC3)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: subdirs_clean diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 7abc9b506..18f366e87 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -455,6 +455,8 @@ int dns_lookup(const char *name, int type, int nscount, const char **nsip,  	extern int searchdomains;  	extern const char * searchdomain[MAX_SEARCH]; +	fd = -1; +  	if (!packet || !lookup || !nscount)  	    goto fail; @@ -462,8 +464,6 @@ int dns_lookup(const char *name, int type, int nscount, const char **nsip,  	ns %= nscount; -	fd = -1; -  	while (retries++ < MAX_RETRIES) {  		if (fd != -1) diff --git a/libc/inet/rpc/Makefile b/libc/inet/rpc/Makefile index 082c78a55..ade5d2422 100644 --- a/libc/inet/rpc/Makefile +++ b/libc/inet/rpc/Makefile @@ -39,8 +39,8 @@ COBJS=$(patsubst %.c,%.o, $(CSRC))  all: $(COBJS) $(LIBC) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  $(LIBC): $(COBJS) diff --git a/libc/misc/Makefile b/libc/misc/Makefile index 6a3275903..3f84a5065 100644 --- a/libc/misc/Makefile +++ b/libc/misc/Makefile @@ -39,7 +39,7 @@ libc.a: subdirs  tags:  	ctags -R -	 +  clean: subdirs_clean  	rm -f *.[oa] *~ core diff --git a/libc/misc/assert/Makefile b/libc/misc/assert/Makefile index abc2261ba..d6023490f 100644 --- a/libc/misc/assert/Makefile +++ b/libc/misc/assert/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/fnmatch/Makefile b/libc/misc/fnmatch/Makefile index 2a952881e..ce2ac2a47 100644 --- a/libc/misc/fnmatch/Makefile +++ b/libc/misc/fnmatch/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/glob/Makefile b/libc/misc/glob/Makefile index 557106488..8254381ea 100644 --- a/libc/misc/glob/Makefile +++ b/libc/misc/glob/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/internals/Makefile b/libc/misc/internals/Makefile index be19bbf7b..da693ce51 100644 --- a/libc/misc/internals/Makefile +++ b/libc/misc/internals/Makefile @@ -39,8 +39,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/lock/Makefile b/libc/misc/lock/Makefile index 6a925b882..041ca5404 100644 --- a/libc/misc/lock/Makefile +++ b/libc/misc/lock/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/lsearch/Makefile b/libc/misc/lsearch/Makefile index 82f70be97..5ea47e14d 100644 --- a/libc/misc/lsearch/Makefile +++ b/libc/misc/lsearch/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/mntent/Makefile b/libc/misc/mntent/Makefile index fc8cfb33a..ee163c182 100644 --- a/libc/misc/mntent/Makefile +++ b/libc/misc/mntent/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/regex/Makefile b/libc/misc/regex/Makefile index 66a585a63..89912aa74 100644 --- a/libc/misc/regex/Makefile +++ b/libc/misc/regex/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/syslog/Makefile b/libc/misc/syslog/Makefile index 6f4717f25..a52d413ed 100644 --- a/libc/misc/syslog/Makefile +++ b/libc/misc/syslog/Makefile @@ -35,8 +35,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/misc/time/Makefile b/libc/misc/time/Makefile index 27ebdad45..d225614cb 100644 --- a/libc/misc/time/Makefile +++ b/libc/misc/time/Makefile @@ -43,8 +43,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/pwd_grp/Makefile b/libc/pwd_grp/Makefile index 7ed905ad3..bdd3c9782 100644 --- a/libc/pwd_grp/Makefile +++ b/libc/pwd_grp/Makefile @@ -36,8 +36,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  $(OBJ): Makefile diff --git a/libc/signal/Makefile b/libc/signal/Makefile index 9dcdeab8b..e4fa6b7b4 100644 --- a/libc/signal/Makefile +++ b/libc/signal/Makefile @@ -37,8 +37,8 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile index 49408c95a..5314af07b 100644 --- a/libc/stdio/Makefile +++ b/libc/stdio/Makefile @@ -28,10 +28,11 @@ LIBC=$(TOPDIR)libc.a  MSRC=stdio.c  MOBJ=_stdio_init.o fputc.o fgetc.o fflush.o fgets.o gets.o fputs.o	\       puts.o fread.o fwrite.o fopen.o fclose.o fseek.o rewind.o ftell.o	\ -     setbuffer.o setvbuf.o ungetc.o +     setbuffer.o setvbuf.o ungetc.o _alloc_stdio_buffer.o _free_stdio_buffer.o  MSRC2=printf.c -MOBJ2=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o snprintf.o vsnprintf.o +MOBJ2=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o snprintf.o \ +     vsnprintf.o _sprintf_fake_file.o vfnprintf.o  MSRC3=scanf.c  MOBJ3=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o @@ -60,8 +61,8 @@ $(MOBJ3): $(MSRC3)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  $(OBJ): Makefile diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c index 634885e67..ffca106e4 100644 --- a/libc/stdio/printf.c +++ b/libc/stdio/printf.c @@ -8,7 +8,7 @@   *  "It's not reality that's important, but how you perceive things."   */ -/* Altered to use stdarg, made the core function vfprintf. +/* Altered to use stdarg, made the core function vfnprintf.   * Hooked into the stdio package using 'inside information'   * Altered sizeof() assumptions, now assumes all integers except chars   * will be either @@ -20,7 +20,7 @@  /*   *                    Manuel Novoa III   Dec 2000   * - * The previous vfprintf routine was almost completely rewritten with the + * The previous vfnprintf routine was almost completely rewritten with the   * goal of fixing some shortcomings and reducing object size.   *   * The summary of changes: @@ -52,6 +52,8 @@   * Converted to use my (un)signed long (long) to string routines, which are   * smaller than the previous functions and don't require static buffers.   * + * Other Modifications: + *   Modified sprintf, snprintf, vsprintf, vsnprintf to share on fake-file.   */  /*****************************************************************************/ @@ -122,6 +124,14 @@  extern int vfnprintf(FILE * op, size_t max_size,  					 register __const char *fmt, register va_list ap); +extern FILE __sprintf_fake_file[1]; + +#ifdef L__sprintf_fake_file +FILE __sprintf_fake_file[1] = { +	{0, 0, (char *) (unsigned) -1, 0, (char *) (unsigned) -1, -1, +	 _IOFBF | __MODE_WRITE} +}; +#endif  #ifdef L_printf  int printf(const char *fmt, ...) @@ -139,19 +149,14 @@ int printf(const char *fmt, ...)  #ifdef L_sprintf  int sprintf(char *sp, const char *fmt, ...)  { -	static FILE string[1] = { -		{0, 0, (char *) (unsigned) -1, 0, (char *) (unsigned) -1, -1, -		 _IOFBF | __MODE_WRITE} -	}; -  	va_list ptr;  	int rv;  	va_strt(ptr, fmt); -	string->bufpos = sp; -	rv = vfnprintf(string, -1, fmt, ptr); +	__sprintf_fake_file->bufpos = sp; +	rv = vfnprintf(__sprintf_fake_file, -1, fmt, ptr);  	va_end(ptr); -	*(string->bufpos) = 0; +	*(__sprintf_fake_file->bufpos) = 0;  	return rv;  }  #endif @@ -160,19 +165,14 @@ int sprintf(char *sp, const char *fmt, ...)  #ifdef L_snprintf  int snprintf(char *sp, size_t size, const char *fmt, ...)  { -	static FILE string[1] = { -		{0, 0, (char *) (unsigned) -1, 0, (char *) (unsigned) -1, -1, -		 _IOFBF | __MODE_WRITE} -	}; -  	va_list ptr;  	int rv;  	va_strt(ptr, fmt); -	string->bufpos = sp; -	rv = vfnprintf(string, size, fmt, ptr); +	__sprintf_fake_file->bufpos = sp; +	rv = vfnprintf(__sprintf_fake_file, size, fmt, ptr);  	va_end(ptr); -	*(string->bufpos) = 0; +	*(__sprintf_fake_file->bufpos) = 0;  	return rv;  }  #endif @@ -200,38 +200,28 @@ int vprintf(const char *fmt, va_list ap)  #ifdef L_vsprintf  int vsprintf(char *sp, __const char *fmt, va_list ap)  { -	static FILE string[1] = { -		{0, 0, (char *) (unsigned) -1, 0, (char *) (unsigned) -1, -1, -		 _IOFBF | __MODE_WRITE} -	}; -  	int rv; -	string->bufpos = sp; -	rv = vfnprintf(string, -1, fmt, ap); -	*(string->bufpos) = 0; +	__sprintf_fake_file->bufpos = sp; +	rv = vfnprintf(__sprintf_fake_file, -1, fmt, ap); +	*(__sprintf_fake_file->bufpos) = 0;  	return rv;  }  #endif -#ifdef L_vsprintf +#ifdef L_vsnprintf  int vsnprintf(char *sp, size_t size, __const char *fmt, va_list ap)  { -	static FILE string[1] = { -		{0, 0, (char *) (unsigned) -1, 0, (char *) (unsigned) -1, -1, -		 _IOFBF | __MODE_WRITE} -	}; -  	int rv; -	string->bufpos = sp; -	rv = vfnprintf(string, size, fmt, ap); -	*(string->bufpos) = 0; +	__sprintf_fake_file->bufpos = sp; +	rv = vfnprintf(__sprintf_fake_file, size, fmt, ap); +	*(__sprintf_fake_file->bufpos) = 0;  	return rv;  }  #endif -#ifdef L_vfprintf +#ifdef L_vfnprintf  extern char *__ultostr(char *buf, unsigned long uval, int base, int uppercase);  extern char *__ltostr(char *buf, long val, int base, int uppercase); @@ -591,6 +581,10 @@ int vfnprintf(FILE * op, size_t max_size, const char *fmt, va_list ap)  	return (cnt);  } +#endif + +#ifdef L_vfprintf +  int vfprintf(FILE * op, register __const char *fmt, register va_list ap)  {  	return (vfnprintf(op, -1, fmt, ap)); diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c index fbec9d5a9..32f4b925b 100644 --- a/libc/stdio/stdio.c +++ b/libc/stdio/stdio.c @@ -28,8 +28,6 @@  #undef STUB_FWRITE -void __init_stdio(void); -  extern FILE *__IO_list;			/* For fflush at exit */  #define FIXED_BUFFERS 2 @@ -38,47 +36,72 @@ struct fixed_buffer {  	int used;  }; -extern struct fixed_buffer _fixed_buffers[2]; +extern struct fixed_buffer _fixed_buffers[FIXED_BUFFERS]; -#ifdef L__stdio_init +extern unsigned char *_alloc_stdio_buffer(size_t size); +extern void _free_stdio_buffer(unsigned char *buf); -#define buferr (stderr->unbuf)		/* Stderr is unbuffered */ +#ifdef L__alloc_stdio_buffer -FILE *__IO_list = 0;			/* For fflush at exit */ +unsigned char *_alloc_stdio_buffer(size_t size) +{ +	if (size == BUFSIZ) { +		int i; -static char *bufin; -static char *bufout; -#ifndef buferr -static char *buferr; +		for (i = 0; i < FIXED_BUFFERS; i++) +			if (!_fixed_buffers[i].used) { +				_fixed_buffers[i].used = 1; +				return _fixed_buffers[i].data; +			} +	} +	return malloc(size); +}  #endif -FILE stdin[1] = { -#if 0 -	{bufin, bufin, bufin, bufin, bufin + BUFSIZ, -#else -	{0, 0, 0, 0, 0, +#ifdef L__free_stdio_buffer + +void _free_stdio_buffer(unsigned char *buf) +{ +	int i; + +	for (i = 0; i < FIXED_BUFFERS; i++) { +		if (buf == _fixed_buffers[i].data) { +			_fixed_buffers[i].used = 0; +			return; +		} +	} +	free(buf); +}  #endif -	 0, _IOFBF | __MODE_READ | __MODE_IOTRAN} -}; -FILE stdout[1] = { -#if 0 -	{bufout, bufout, bufout, bufout, bufout + BUFSIZ, -#else -	{0, 0, 0, 0, 0, +#ifdef L__stdio_init + +#if FIXED_BUFFERS < 2 +#error FIXED_BUFFERS must be >= 2  #endif -	 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN} -}; -FILE stderr[1] = { -#if 0 +#define bufin (_fixed_buffers[0].data) +#define bufout (_fixed_buffers[1].data) +#define buferr (_stdio_streams[3].unbuf)		/* Stderr is unbuffered */ + +struct fixed_buffer _fixed_buffers[FIXED_BUFFERS]; + +FILE _stdio_streams[3] = { +	{bufin, bufin, bufin, bufin, bufin + BUFSIZ, +	 0, _IOFBF | __MODE_READ | __MODE_IOTRAN | __MODE_FREEBUF}, +	{bufout, bufout, bufout, bufout, bufout + BUFSIZ, +	 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN | __MODE_FREEBUF},  	{buferr, buferr, buferr, buferr, buferr + sizeof(buferr), -#else -	{0, 0, 0, 0, 0, -#endif  	 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN}  }; +/* + * Note: the following forces lining of the __init_stdio function if + * any of the stdio functions are used (except perror) since they all + * call fflush directly or indirectly. + */ +FILE *__IO_list = 0;			/* For fflush at exit */ +  /* Call the stdio initiliser; it's main job it to call atexit */  void __stdio_close_all(void) @@ -96,52 +119,17 @@ void __stdio_close_all(void)  	}  } -static int first_time = 0; - -struct fixed_buffer _fixed_buffers[2]; - -  void __init_stdio(void)  { -	if (first_time) -		return; -	first_time = 1; - -	stdin->bufpos = bufin = _fixed_buffers[0].data; /*(char *)malloc(BUFSIZ) */ ; -	stdin->bufread = bufin; -	stdin->bufwrite = bufin; -	stdin->bufstart = bufin; -	stdin->bufend = bufin + sizeof(_fixed_buffers[0].data); -	stdin->fd = 0; -	stdin->mode = _IOFBF | __MODE_READ | __MODE_IOTRAN | __MODE_FREEBUF; -  	_fixed_buffers[0].used = 1; - -	stdout->bufpos = bufout = _fixed_buffers[1].data;	/*(char *)malloc(BUFSIZ); */ -	stdout->bufread = bufout; -	stdout->bufwrite = bufout; -	stdout->bufstart = bufout; -	stdout->bufend = bufout + sizeof(_fixed_buffers[1].data); -	stdout->fd = 1; -	stdout->mode = _IOFBF | __MODE_WRITE | __MODE_IOTRAN | __MODE_FREEBUF; -  	_fixed_buffers[1].used = 1; -#if 0 -	stderr->bufpos = buferr = (char *) malloc(BUFSIZ); -#else -	stderr->bufpos = buferr; -#endif -	stderr->bufread = buferr; -	stderr->bufwrite = buferr; -	stderr->bufstart = buferr; -	stderr->bufend = buferr + sizeof(buferr); -	stderr->fd = 2; -	stderr->mode = _IONBF | __MODE_WRITE | __MODE_IOTRAN; -  	if (isatty(1))  		stdout->mode |= _IOLBF; +#if 0 +	/* taken care of in _start.c and exit.c now*/  	atexit(__stdio_close_all); +#endif  }  #endif @@ -152,8 +140,6 @@ FILE *fp;  {  	register int v; -	__init_stdio(); -  	v = fp->mode;  	/* If last op was a read ... */  	if ((v & __MODE_READING) && fflush(fp)) @@ -199,8 +185,6 @@ FILE *fp;  {  	int ch; -	__init_stdio(); -  	if (fp->mode & __MODE_WRITING)  		fflush(fp); @@ -243,8 +227,6 @@ FILE *fp;  	int len, cc, rv = 0;  	char *bstart; -	__init_stdio(); -  	if (fp == NULL) {			/* On NULL flush the lot. */  		if (fflush(stdin))  			return EOF; @@ -406,8 +388,6 @@ FILE *fp;  	int len, v;  	unsigned bytes, got = 0; -	__init_stdio(); -  	v = fp->mode;  	/* Want to do this to bring the file pointer up to date */ @@ -611,8 +591,6 @@ const char *mode;  	int fopen_mode = 0;  	FILE *nfp = 0; -	__init_stdio(); -  	/* If we've got an fp close the old one (freopen) */  	if (fp) {  		/* Careful, don't de-allocate it */ @@ -684,8 +662,6 @@ const char *mode;  	/* If this isn't freopen create a (FILE) and buffer for it */  	if (fp == 0) { -		int i; -  		fp = nfp;  		fp->next = __IO_list;  		__IO_list = fp; @@ -700,15 +676,7 @@ const char *mode;  		} else  			fp->mode |= _IOFBF; -		for (i = 0; i < FIXED_BUFFERS; i++) -			if (!_fixed_buffers[i].used) { -				fp->bufstart = _fixed_buffers[i].data; -				_fixed_buffers[i].used = 1; -				break; -			} - -		if (i == FIXED_BUFFERS) -			fp->bufstart = malloc(BUFSIZ); +		fp->bufstart = _alloc_stdio_buffer(BUFSIZ);  		if (fp->bufstart == 0) {	/* Oops, no mem *//* Humm, full buffering with a two(!) byte  									   * buffer. */ @@ -733,8 +701,6 @@ FILE *fp;  {  	int rv = 0; -	__init_stdio(); -  	if (fp == 0) {  		errno = EINVAL;  		return EOF; @@ -747,15 +713,7 @@ FILE *fp;  	fp->fd = -1;  	if (fp->mode & __MODE_FREEBUF) { -		int i; - -		for (i = 0; i < FIXED_BUFFERS; i++) -			if (fp->bufstart == _fixed_buffers[i].data) { -				_fixed_buffers[i].used = 0; -				break; -			} -		if (i == FIXED_BUFFERS) -			free(fp->bufstart); +		_free_stdio_buffer(fp->bufstart);  		fp->mode &= ~__MODE_FREEBUF;  		fp->bufstart = fp->bufend = 0;  	} @@ -793,15 +751,7 @@ size_t size;  		return;  	if (fp->mode & __MODE_FREEBUF) { -		int i; - -		for (i = 0; i < FIXED_BUFFERS; i++) -			if (fp->bufstart == _fixed_buffers[i].data) { -				_fixed_buffers[i].used = 0; -				break; -			} -		if (i == FIXED_BUFFERS) -			free(fp->bufstart); +		_free_stdio_buffer(fp->bufstart);  	}  	fp->mode &= ~(__MODE_FREEBUF | __MODE_BUF); @@ -827,15 +777,7 @@ size_t size;  {  	fflush(fp);  	if (fp->mode & __MODE_FREEBUF) { -		int i; - -		for (i = 0; i < FIXED_BUFFERS; i++) -			if (fp->bufstart == _fixed_buffers[i].data) { -				_fixed_buffers[i].used = 0; -				break; -			} -		if (i == FIXED_BUFFERS) -			free(fp->bufstart); +		_free_stdio_buffer(fp->bufstart);  	}  	fp->mode &= ~(__MODE_FREEBUF | __MODE_BUF);  	fp->bufstart = fp->unbuf; @@ -847,23 +789,10 @@ size_t size;  			size = BUFSIZ;  		}  		if (buf == 0) { -			if (size == BUFSIZ) { -				int i; - -				for (i = 0; i < FIXED_BUFFERS; i++) -					if (!_fixed_buffers[i].used) { -						_fixed_buffers[i].used = 1; -						buf = _fixed_buffers[i].data; -						break; -					} -				if (i == FIXED_BUFFERS) -					buf = malloc(size); -			} else { -				buf = malloc(size); -			} +			buf = _alloc_stdio_buffer(size); +			if (buf == 0) +				return EOF;  		} -		if (buf == 0) -			return EOF;  		fp->bufstart = buf;  		fp->bufend = buf + size; diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile index 5d7c9405a..52d00f876 100644 --- a/libc/stdlib/Makefile +++ b/libc/stdlib/Makefile @@ -33,7 +33,7 @@ MSRC1=strto_ll.c  MOBJ1=strtoll.o strtoull.o strto_ll.o  MSRC2=atexit.c -MOBJ2=on_exit.o atexit.o __do_exit.o exit.o +MOBJ2=atexit.o exit.o  CSRC =	abort.c getenv.c mktemp.c qsort.c realpath.c abs.c bsearch.c \ @@ -65,8 +65,8 @@ $(MOBJ2): $(MSRC2)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  $(OBJ): Makefile diff --git a/libc/stdlib/atexit.c b/libc/stdlib/atexit.c index 1c164ff86..20195fa96 100644 --- a/libc/stdlib/atexit.c +++ b/libc/stdlib/atexit.c @@ -4,11 +4,12 @@   */  /* - * This deals with both the atexit and on_exit function calls - *  - * Note calls installed with atexit are called with the same args as on_exit - * fuctions; the void* is given the NULL value. - *  + * Manuel Novoa III       Dec 2000 + * + * Modifications: + *   Made atexit handling conform to standards... i.e. no args. + *   Removed on_exit since it did not match gnu libc definition. + *   Combined atexit and __do_exit into one object file.   */  #include <errno.h> @@ -16,93 +17,58 @@  /* ATEXIT.H */  #define MAXONEXIT 20			/* AIUI Posix requires 10 */ -typedef void (*vfuncp) (); +typedef void (*vfuncp) (void);  extern vfuncp __cleanup;  extern void __do_exit();  extern void _exit __P((int __status)) __attribute__ ((__noreturn__)); -extern struct exit_table { -	vfuncp called; -	void *argument; -} __on_exit_table[MAXONEXIT]; - -extern int __on_exit_count; +extern vfuncp __atexit_table[MAXONEXIT]; +extern int __atexit_count;  /* End ATEXIT.H */  #ifdef L_atexit -vfuncp __cleanup; - -int atexit(ptr) -vfuncp ptr; +int atexit(vfuncp ptr)  { -	if (__on_exit_count < 0 || __on_exit_count >= MAXONEXIT) { +	if ((__atexit_count < 0) || (__atexit_count >= MAXONEXIT)) {  		errno = ENOMEM;  		return -1;  	} -	__cleanup = __do_exit;  	if (ptr) { -		__on_exit_table[__on_exit_count].called = ptr; -		__on_exit_table[__on_exit_count].argument = 0; -		__on_exit_count++; +		__cleanup = __do_exit; +		__atexit_table[__atexit_count++] = ptr;  	}  	return 0;  } -#endif +vfuncp __atexit_table[MAXONEXIT]; +int __atexit_count = 0; -#ifdef L_on_exit -int on_exit(ptr, arg) -vfuncp ptr; -void *arg; +void __do_exit(int rv)  { -	if (__on_exit_count < 0 || __on_exit_count >= MAXONEXIT) { -		errno = ENOMEM; -		return -1; -	} -	__cleanup = __do_exit; -	if (ptr) { -		__on_exit_table[__on_exit_count].called = ptr; -		__on_exit_table[__on_exit_count].argument = arg; -		__on_exit_count++; -	} -	return 0; -} +	int count = __atexit_count - 1; -#endif - -#ifdef L___do_exit - -int __on_exit_count = 0; -struct exit_table __on_exit_table[MAXONEXIT]; - -void __do_exit(rv) -int rv; -{ -	register int count = __on_exit_count - 1; -	register vfuncp ptr; - -	__on_exit_count = -1;		/* ensure no more will be added */ +	__atexit_count = -1;		/* ensure no more will be added */  	__cleanup = 0;				/* Calling exit won't re-do this */  	/* In reverse order */  	for (; count >= 0; count--) { -		ptr = __on_exit_table[count].called; -		(*ptr) (rv, __on_exit_table[count].argument); +		(*__atexit_table[count])();  	}  } -  #endif  #ifdef L_exit +void __stdio_close_all(void);	/* note: see _start.S - could be faked */ -void exit(rv) -int rv; +vfuncp __cleanup = 0; + +void exit(int rv)  {  	if (__cleanup)  		__cleanup(); +	__stdio_close_all();  	_exit(rv);  } -  #endif diff --git a/libc/stdlib/malloc-930716/Makefile b/libc/stdlib/malloc-930716/Makefile new file mode 100644 index 000000000..a4ae21798 --- /dev/null +++ b/libc/stdlib/malloc-930716/Makefile @@ -0,0 +1,51 @@ +# Makefile for uClibc +# +# Copyright (C) 2000 by Lineo, inc. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU Library General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more +# details. +# +# You should have received a copy of the GNU Library General Public License +# along with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Derived in part from the Linux-8086 C library, the GNU C Library, and several +# other sundry sources.  Files within this library are copyright by their +# respective copyright holders. + +TOPDIR=../../ +include $(TOPDIR)Rules.mak +LIBC=$(TOPDIR)libc.a + +CSRC=calloc.c free.c malloc.c memalign.c morecore.c realloc.c valloc.c +COBJS=$(patsubst %.c,%.o, $(CSRC)) + +MSRC=../malloc/alloc.c +MOBJ=malloc_dbg.o free_dbg.o calloc_dbg.o +OBJS=$(COBJS) $(MOBJ) + +all: $(OBJS) $(LIBC) + +$(LIBC): ar-target + +ar-target: $(OBJS) +	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) + +$(MOBJ): $(MSRC) +	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o +	$(STRIPTOOL) -x -R .note -R .comment $*.o + +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@ +	$(STRIPTOOL) -x -R .note -R .comment $*.o + +clean: +	rm -f *.[oa] *~ core + diff --git a/libc/stdlib/malloc-930716/README b/libc/stdlib/malloc-930716/README new file mode 100644 index 000000000..39c048312 --- /dev/null +++ b/libc/stdlib/malloc-930716/README @@ -0,0 +1,40 @@ +This is a fast malloc implementation that I wrote several years ago. +I later used it as the basis of GNU malloc.  My version differs from +the GNU version in that it does not support debugging hooks, and does +not record statistics.  Therefore it is slightly faster. + +In order to safely link programs using this malloc with a C library +that provides a different malloc, you need to make sure that +malloc(), free(), and realloc() are defined in a single object file. +Otherwise when linking you might get a combination of this malloc() +with the library's free().  The Makefile builds such an object file, +alloc.o. + +If you are using this malloc as the allocator for a C library of your +own, and are not linking with another C library, then you don't need +alloc.o.  If you are building a C library, you should also write a +replacement for the file "morecore.c" that doesn't pollute the name +space. + +The header file "malloc.h" in this directory is NOT intended to be a +public header file; it is for internal use by malloc and its +friends.  Don't install malloc.h in a public include directory! + +When porting this allocator to a new machine or operating system, you +should inspect the definition of BLOCKSIZE in malloc.h to make sure +it is greater than or equal to your target machine's virtual memory +page size; otherwise valloc() won't work properly.  (If you don't +care about valloc() then BLOCKSIZE doesn't matter.) + +You will also need to provide a machine-dependent _default_morecore() +function; see morecore.c for a sample version that works on Unix. +Your morecore function should return a pointer to a newly allocated +region of the given size, aligned on the most pessimistic alignment +boundary for the machine.  Subsequent calls to morecore should return +contiguous memory, and calls to morecore with a negative argument +should return memory to the system.  If no memory is available +morecore should return NULL. + +Bug reports to Mike Haertel, mike@cs.uoregon.edu. +This version is dated March 26, 1993; include this +date with your bug report. diff --git a/libc/stdlib/malloc-930716/calloc.c b/libc/stdlib/malloc-930716/calloc.c new file mode 100644 index 000000000..152fe09c6 --- /dev/null +++ b/libc/stdlib/malloc-930716/calloc.c @@ -0,0 +1,25 @@ +/* calloc.c - C standard library routine. +   Copyright (c) 1989, 1993  Michael J. Haertel +   You may redistribute this library under the terms of the +   GNU Library General Public License (version 2 or any later +   version) as published by the Free Software Foundation. +   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED +   WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR +   WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +   SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <string.h> +#include "malloc.h" + +/* Allocate space for the given number of elements of the given +   size, initializing the whole region to binary zeroes. */ +void * +calloc(size_t nelem, size_t size) +{ +    void *result; + +    result = malloc(size * nelem); +    if (result) +	memset(result, 0, nelem * size); +    return result; +} diff --git a/libc/stdlib/malloc-930716/free.c b/libc/stdlib/malloc-930716/free.c new file mode 100644 index 000000000..fbc98b714 --- /dev/null +++ b/libc/stdlib/malloc-930716/free.c @@ -0,0 +1,156 @@ +/* free.c - C standard library routine. +   Copyright (c) 1989, 1993  Michael J. Haertel +   You may redistribute this library under the terms of the +   GNU Library General Public License (version 2 or any later +   version) as published by the Free Software Foundation. +   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED +   WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR +   WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +   SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include "malloc.h" + +/* Return memory to the heap. */ +void +_free_internal (void *ptr) +{ +    int block, blocks, i, type; +    struct list *prev, *next; + +    if (!ptr) +	return; + +    block = BLOCK(ptr); + +    switch (type = _heapinfo[block].busy.type) { +    case 0: +	/* Find the free cluster previous to this one in the free list. +	   Start searching at the last block referenced; this may benefit +	   programs with locality of allocation. */ +	i = _heapindex; +	if (i > block) +	    while (i > block) +		i = _heapinfo[i].free.prev; +	else { +	    do +		i = _heapinfo[i].free.next; +	    while (i > 0 && i < block); +	    i = _heapinfo[i].free.prev; +	} + +	/* Determine how to link this block into the free list. */ +	if (block == i + _heapinfo[i].free.size) { +	    /* Coalesce this block with its predecessor. */ +	    _heapinfo[i].free.size += _heapinfo[block].busy.info.size; +	    block = i; +	} else { +	    /* Really link this block back into the free list. */ +	    _heapinfo[block].free.size = _heapinfo[block].busy.info.size; +	    _heapinfo[block].free.next = _heapinfo[i].free.next; +	    _heapinfo[block].free.prev = i; +	    _heapinfo[i].free.next = block; +	    _heapinfo[_heapinfo[block].free.next].free.prev = block; +	} + +	/* Now that the block is linked in, see if we can coalesce it +	   with its successor (by deleting its successor from the list +	   and adding in its size). */ +	if (block + _heapinfo[block].free.size == _heapinfo[block].free.next) { +	    _heapinfo[block].free.size +		+= _heapinfo[_heapinfo[block].free.next].free.size; +	    _heapinfo[block].free.next +		= _heapinfo[_heapinfo[block].free.next].free.next; +	    _heapinfo[_heapinfo[block].free.next].free.prev = block; +	} + +	/* Now see if we can return stuff to the system. */ +	blocks = _heapinfo[block].free.size; +	if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit +	    && (*__morecore)(0) == ADDRESS(block + blocks)) { +	    _heaplimit -= blocks; +	    (*__morecore)(-blocks * BLOCKSIZE); +	    _heapinfo[_heapinfo[block].free.prev].free.next +		= _heapinfo[block].free.next; +	    _heapinfo[_heapinfo[block].free.next].free.prev +		= _heapinfo[block].free.prev; +	    block = _heapinfo[block].free.prev; +	} + +	/* Set the next search to begin at this block. */ +	_heapindex = block; +	break; + +    default: +	/* Get the address of the first free fragment in this block. */ +	prev = (struct list *) ((char *) ADDRESS(block) +				+ (_heapinfo[block].busy.info.frag.first +				   << type)); + +	if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1 +	&& _fragblocks[type] > 1) { +	    /* If all fragments of this block are free, remove them +	       from the fragment list and free the whole block. */ +	    --_fragblocks[type]; +	    for (next = prev, i = 1; i < BLOCKSIZE >> type; ++i) +		next = next->next; +	    prev->prev->next = next; +	    if (next) +		next->prev = prev->prev; +	    _heapinfo[block].busy.type = 0; +	    _heapinfo[block].busy.info.size = 1; +	    free(ADDRESS(block)); +	} else if (_heapinfo[block].busy.info.frag.nfree) { +	    /* If some fragments of this block are free, link this fragment +	       into the fragment list after the first free fragment of +	       this block. */ +	    next = ptr; +	    next->next = prev->next; +	    next->prev = prev; +	    prev->next = next; +	    if (next->next) +		next->next->prev = next; +	    ++_heapinfo[block].busy.info.frag.nfree; +	} else { +	    /* No fragments of this block are free, so link this fragment +	       into the fragment list and announce that it is the first +	       free fragment of this block. */ +	    prev = (struct list *) ptr; +	    _heapinfo[block].busy.info.frag.nfree = 1; +	    _heapinfo[block].busy.info.frag.first +		= (unsigned int) ((char *) ptr - (char *) NULL) % BLOCKSIZE +		  >> type; +	    prev->next = _fraghead[type].next; +	    prev->prev = &_fraghead[type]; +	    prev->prev->next = prev; +	    if (prev->next) +		prev->next->prev = prev; +	} +	break; +    } +} + +struct alignlist *_aligned_blocks = NULL; + +void +free (void *ptr) +{ +  register struct alignlist *l; +   +  if (ptr == NULL) +    return; +	  +  for (l = _aligned_blocks; l != NULL; l = l->next) +  { +    if (l->aligned == ptr) +    { +      l->aligned = NULL;	/* Mark the slot in the list as free.  */ +      ptr = l->exact; +      break; +    } +  } + +  _free_internal (ptr); +} diff --git a/libc/stdlib/malloc-930716/malloc.c b/libc/stdlib/malloc-930716/malloc.c new file mode 100644 index 000000000..e8f7c7004 --- /dev/null +++ b/libc/stdlib/malloc-930716/malloc.c @@ -0,0 +1,254 @@ +/* malloc.c - C standard library routine. +   Copyright (c) 1989, 1993  Michael J. Haertel +   You may redistribute this library under the terms of the +   GNU Library General Public License (version 2 or any later +   version) as published by the Free Software Foundation. +   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED +   WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR +   WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +   SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "malloc.h" + +/* How to really get more memory. */ +void *(*__morecore)(long) = __default_morecore_init; + +/* Pointer to the base of the first block. */ +char *_heapbase; + +/* Block information table. */ +union info *_heapinfo; + +/* Number of info entries. */ +static int heapsize; + +/* Search index in the info table. */ +int _heapindex; + +/* Limit of valid info table indices. */ +int _heaplimit; + +/* Count of large blocks allocated for each fragment size. */ +int _fragblocks[BLOCKLOG]; + +/* Free lists for each fragment size. */ +struct list _fraghead[BLOCKLOG]; + +/* Are we experienced? */ +static int initialized; + +/* Aligned allocation. */ +static void * +align(size_t size) +{ +    void *result; +    unsigned int adj; + +    result = (*__morecore)(size); +    adj = (unsigned int) ((char *) result - (char *) NULL) % BLOCKSIZE; +    if (adj != 0) { +	(*__morecore)(adj = BLOCKSIZE - adj); +	result = (char *) result + adj; +    } +    return result; +} + +/* Set everything up and remember that we have. */ +static int +initialize(void) +{ +    heapsize = HEAP / BLOCKSIZE; +    _heapinfo = align(heapsize * sizeof (union info)); +    if (!_heapinfo) +	return 0; +    memset(_heapinfo, 0, heapsize * sizeof (union info)); +    _heapinfo[0].free.size = 0; +    _heapinfo[0].free.next = _heapinfo[0].free.prev = 0; +    _heapindex = 0; +    _heapbase = (char *) _heapinfo; +    initialized = 1; +    return 1; +} + +/* Get neatly aligned memory, initializing or growing the +   heap info table as necessary. */ +static void * +morecore(size_t size) +{ +    void *result; +    union info *newinfo, *oldinfo; +    int newsize; + +    result = align(size); +    if (!result) +	return NULL; + +    /* Check if we need to grow the info table. */ +    if (BLOCK((char *) result + size) > heapsize) { +	newsize = heapsize; +	while (BLOCK((char *) result + size) > newsize) +	    newsize *= 2; +	newinfo = align(newsize * sizeof (union info)); +	if (!newinfo) { +	    (*__morecore)(-size); +	    return NULL; +	} +	memset(newinfo, 0, newsize * sizeof (union info)); +	memcpy(newinfo, _heapinfo, heapsize * sizeof (union info)); +	oldinfo = _heapinfo; +	newinfo[BLOCK(oldinfo)].busy.type = 0; +	newinfo[BLOCK(oldinfo)].busy.info.size +	    = BLOCKIFY(heapsize * sizeof (union info)); +	_heapinfo = newinfo; +#if 0 +	free(oldinfo); +#else +	_free_internal (oldinfo); +#endif +	heapsize = newsize; +    } + +    _heaplimit = BLOCK((char *) result + size); +    return result; +} + +/* Allocate memory from the heap. */ +void * +malloc (size_t size) +{ +    void *result; +    int log, block, blocks, i, lastblocks, start; +    struct list *next; + +    if (!initialized && !initialize()) +	return NULL; + +    /* Some programs will call malloc (0). We let them pass. */ +#if 0 +    if (size == 0) +	return NULL; +#endif + +    if (size < sizeof (struct list)) +	size = sizeof (struct list); + +    /* Determine the allocation policy based on the request size. */ +    if (size <= BLOCKSIZE / 2) { +	/* Small allocation to receive a fragment of a block. Determine +	   the logarithm to base two of the fragment size. */ +	--size; +	for (log = 1; (size >>= 1) != 0; ++log) +	    ; + +	/* Look in the fragment lists for a free fragment of the +	   desired size. */ +	if ((next = _fraghead[log].next) != 0) { +	    /* There are free fragments of this size.  Pop a fragment +	       out of the fragment list and return it.  Update the block's +	       nfree and first counters. */ +	    result = next; +	    next->prev->next = next->next; +	    if (next->next) +		next->next->prev = next->prev; +	    block = BLOCK(result); +	    if (--_heapinfo[block].busy.info.frag.nfree) +		_heapinfo[block].busy.info.frag.first +		    = (unsigned int) ((char *) next->next - (char *) NULL) +		      % BLOCKSIZE >> log; +	} else { +	    /* No free fragments of the desired size, so get a new block +	       and break it into fragments, returning the first. */ +	    result = malloc(BLOCKSIZE); +	    if (!result) +		return NULL; +	    ++_fragblocks[log]; + +	    /* Link all fragments but the first into the free list. */ +	    next = (struct list *) ((char *) result + (1 << log)); +	    next->next = 0; +	    next->prev = &_fraghead[log]; +	    _fraghead[log].next = next; + +	    for (i = 2; i < BLOCKSIZE >> log; ++i) { +		next = (struct list *) ((char *) result + (i << log)); +		next->next = _fraghead[log].next; +		next->prev = &_fraghead[log]; +		next->prev->next = next; +		next->next->prev = next; +	    } + +	    /* Initialize the nfree and first counters for this block. */ +	    block = BLOCK(result); +	    _heapinfo[block].busy.type = log; +	    _heapinfo[block].busy.info.frag.nfree = i - 1; +	    _heapinfo[block].busy.info.frag.first = i - 1; +	} +    } else { +	/* Large allocation to receive one or more blocks.  Search +	   the free list in a circle starting at the last place visited. +	   If we loop completely around without finding a large enough +	   space we will have to get more memory from the system. */ +	blocks = BLOCKIFY(size); +	start = block = _heapindex; +	while (_heapinfo[block].free.size < blocks) { +	    block = _heapinfo[block].free.next; +	    if (block == start) { +		/* Need to get more from the system.  Check to see if +		   the new core will be contiguous with the final free +		   block; if so we don't need to get as much. */ +		block = _heapinfo[0].free.prev; +		lastblocks = _heapinfo[block].free.size; +		if (_heaplimit && block + lastblocks == _heaplimit +		    && (*__morecore)(0) == ADDRESS(block + lastblocks) +		    && morecore((blocks - lastblocks) * BLOCKSIZE)) { +		    /* Note that morecore() can change the location of +		       the final block if it moves the info table and the +		       old one gets coalesced into the final block. */ +		    block = _heapinfo[0].free.prev; +		    _heapinfo[block].free.size += blocks - lastblocks; +		    continue; +		} +		result = morecore(blocks * BLOCKSIZE); +		if (!result) +		    return NULL; +		block = BLOCK(result); +		_heapinfo[block].busy.type = 0; +		_heapinfo[block].busy.info.size = blocks; +		return result; +	    } +	} + +	/* At this point we have found a suitable free list entry. +	   Figure out how to remove what we need from the list. */ +	result = ADDRESS(block); +	if (_heapinfo[block].free.size > blocks) { +	    /* The block we found has a bit left over, so relink the +	       tail end back into the free list. */ +	    _heapinfo[block + blocks].free.size +		= _heapinfo[block].free.size - blocks; +	    _heapinfo[block + blocks].free.next +		= _heapinfo[block].free.next; +	    _heapinfo[block + blocks].free.prev +		= _heapinfo[block].free.prev; +	    _heapinfo[_heapinfo[block].free.prev].free.next +		= _heapinfo[_heapinfo[block].free.next].free.prev +		    = _heapindex = block + blocks; +	} else { +	    /* The block exactly matches our requirements, so +	       just remove it from the list. */ +	    _heapinfo[_heapinfo[block].free.next].free.prev +		= _heapinfo[block].free.prev; +	    _heapinfo[_heapinfo[block].free.prev].free.next +		= _heapindex = _heapinfo[block].free.next; +	} + +	_heapinfo[block].busy.type = 0; +	_heapinfo[block].busy.info.size = blocks; +    } + +    return result; +} diff --git a/libc/stdlib/malloc-930716/malloc.h b/libc/stdlib/malloc-930716/malloc.h new file mode 100644 index 000000000..34458c062 --- /dev/null +++ b/libc/stdlib/malloc-930716/malloc.h @@ -0,0 +1,107 @@ +/* malloc.h - declarations for the allocator. +   Copyright (c) 1989, 1993  Michael J. Haertel +   You may redistribute this library under the terms of the +   GNU Library General Public License (version 2 or any later +   version) as published by the Free Software Foundation. +   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED +   WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR +   WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +   SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <sys/cdefs.h> + +/* Underlying allocation function; successive calls should return +   contiguous pieces of memory. */ +extern void *(*__morecore)(long); + +/* Default value of previous. */ +extern void *__default_morecore_init(long); +extern void *__default_morecore(long); + +/* The allocator divides the heap into blocks of fixed size; large +   requests receive one or more whole blocks, and small requests +   receive a fragment of a block.  Fragment sizes are powers of two, +   and all fragments of a block are the same size.  When all the +   fragments in a block have been freed, the block itself is freed. +   WARNING: BLOCKSIZE must be set greater than or equal to the +   machine's page size for valloc() to work correctly.  The default +   definition here is 4096 bytes. */ +#define INT_BIT (CHAR_BIT * sizeof (int)) +#define BLOCKLOG (INT_BIT > 16 ? 12 : 9) +#define BLOCKSIZE (1 << BLOCKLOG) +#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE) + +/* Determine the amount of memory spanned by the initial heap table +   (not an absolute limit). */ +#define HEAP (INT_BIT > 16 ? 4194304 : 65536) + +/* Number of contiguous free blocks allowed to build up at the end of +   memory before they will be returned to the system. */ +#define FINAL_FREE_BLOCKS 8 + +/* Data structure giving per-block information. */ +union info { +    struct { +	int type;		/* Zero for a large block, or positive +				   giving the logarithm to the base two +				   of the fragment size. */ +	union { +	    struct { +		int nfree;	/* Free fragments in a fragmented block. */ +		int first;	/* First free fragment of the block. */ +	    } frag; +	    int size;		/* Size (in blocks) of a large cluster. */ +	} info; +    } busy; +    struct { +	int size;		/* Size (in blocks) of a free cluster. */ +	int next;		/* Index of next free cluster. */ +	int prev;		/* Index of previous free cluster. */ +    } free; +}; + +/* Pointer to first block of the heap. */ +extern char *_heapbase; + +/* Table indexed by block number giving per-block information. */ +extern union info *_heapinfo; + +/* Address to block number and vice versa. */ +#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) +#define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + _heapbase)) + +/* Current search index for the heap table. */ +extern int _heapindex; + +/* Limit of valid info table indices. */ +extern int _heaplimit; + +/* Doubly linked lists of free fragments. */ +struct list { +    struct list *next; +    struct list *prev; +}; + +/* Count of blocks for each fragment size. */ +extern int _fragblocks[]; + +/* Free list headers for each fragment size. */ +extern struct list _fraghead[]; + +/* List of blocks allocated with `memalign' (or `valloc').  */ +struct alignlist +{  +  struct alignlist *next; +  __ptr_t aligned;	/* The address that memaligned returned.  */ +  __ptr_t exact;	/* The address that malloc returned.  */ +}; +extern struct alignlist *_aligned_blocks; + +extern void _free_internal __P ((__ptr_t __ptr)); + +extern void free (void *); +extern void * malloc (size_t); +extern void * calloc (size_t, size_t); +extern void * valloc (size_t); +extern void * memalign (size_t, size_t); +extern void * realloc (void *, size_t); diff --git a/libc/stdlib/malloc-930716/memalign.c b/libc/stdlib/malloc-930716/memalign.c new file mode 100644 index 000000000..1098f5890 --- /dev/null +++ b/libc/stdlib/malloc-930716/memalign.c @@ -0,0 +1,61 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB.  If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA.  */ + +#include <stdlib.h> +#include "malloc.h" + +__ptr_t +memalign (alignment, size) +     size_t alignment; +     size_t size; +{ +  __ptr_t result; +  unsigned long int adj; + +  result = malloc (size + alignment - 1); +  if (result == NULL) +    return NULL; +  adj = (unsigned long int) ((unsigned long int) ((char *) result - +						(char *) NULL)) % alignment; +  if (adj != 0) +    { +      struct alignlist *l; +      for (l = _aligned_blocks; l != NULL; l = l->next) +	if (l->aligned == NULL) +	  /* This slot is free.  Use it.  */ +	  break; +      if (l == NULL) +	{ +	  l = (struct alignlist *) malloc (sizeof (struct alignlist)); +	  if (l == NULL) +	    { +#if 1 +	      free (result); +#else +	      _free_internal (result); +#endif +	      return NULL; +	    } +	  l->next = _aligned_blocks; +	  _aligned_blocks = l; +	} +      l->exact = result; +      result = l->aligned = (char *) result + alignment - adj; +    } + +  return result; +} diff --git a/libc/stdlib/malloc-930716/morecore.c b/libc/stdlib/malloc-930716/morecore.c new file mode 100644 index 000000000..e2ad4464b --- /dev/null +++ b/libc/stdlib/malloc-930716/morecore.c @@ -0,0 +1,28 @@ +/* morecore.c - C library support routine for UNIX. +   Copyright (c) 1989, 1993  Michael J. Haertel +   You may redistribute this library under the terms of the +   GNU Library General Public License (version 2 or any later +   version) as published by the Free Software Foundation. +   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED +   WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR +   WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +   SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <limits.h> +#include <stddef.h> +#include "malloc.h" + +extern void *sbrk(int); + +/* Note that morecore has to take a signed argument so +   that negative values can return memory to the system. */ +void * +__default_morecore_init(long size) +{ +    void *result; + +    result = sbrk(size); +    if (result == (void *) -1) +	return NULL; +    return result; +} diff --git a/libc/stdlib/malloc-930716/realloc.c b/libc/stdlib/malloc-930716/realloc.c new file mode 100644 index 000000000..1453e813c --- /dev/null +++ b/libc/stdlib/malloc-930716/realloc.c @@ -0,0 +1,131 @@ +/* realloc.c - C standard library routine. +   Copyright (c) 1989, 1993  Michael J. Haertel +   You may redistribute this library under the terms of the +   GNU Library General Public License (version 2 or any later +   version) as published by the Free Software Foundation. +   THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED +   WARRANTY.  IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR +   WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS +   SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ + +#include <limits.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "malloc.h" + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) + +/* Resize the given region to the new size, returning a pointer +   to the (possibly moved) region.  This is optimized for speed; +   some benchmarks seem to indicate that greater compactness is +   achieved by unconditionally allocating and copying to a +   new region. */ +void * +realloc (void *ptr, size_t size) +{ +    void *result, *previous; +    int block, blocks, type; +    int oldlimit; + +    if (!ptr) +	return malloc(size); +    if (!size) { +	free(ptr); +	return malloc(0); +    } + +    block = BLOCK(ptr); + +    switch (type = _heapinfo[block].busy.type) { +    case 0: +	/* Maybe reallocate a large block to a small fragment. */ +	if (size <= BLOCKSIZE / 2) { +	    if ((result = malloc(size)) != NULL) { +	    	memcpy(result, ptr, size); +#if 1 +	    	free(ptr); +#else +	    	_free_internal(ptr); +#endif + +	    } +	    return result; +	} + +	/* The new size is a large allocation as well; see if +	   we can hold it in place. */ +	blocks = BLOCKIFY(size); +	if (blocks < _heapinfo[block].busy.info.size) { +	    /* The new size is smaller; return excess memory +	       to the free list. */ +	    _heapinfo[block + blocks].busy.type = 0; +	    _heapinfo[block + blocks].busy.info.size +		= _heapinfo[block].busy.info.size - blocks; +	    _heapinfo[block].busy.info.size = blocks; +#if 1 +	    free(ADDRESS(block + blocks)); +#else +	    _free_internal(ADDRESS(block + blocks)); +#endif +	    return ptr; +	} else if (blocks == _heapinfo[block].busy.info.size) +	    /* No size change necessary. */ +	    return ptr; +	else { +	    /* Won't fit, so allocate a new region that will.  Free +	       the old region first in case there is sufficient adjacent +	       free space to grow without moving. */ +	    blocks = _heapinfo[block].busy.info.size; +	    /* Prevent free from actually returning memory to the system. */ +	    oldlimit = _heaplimit; +	    _heaplimit = 0; +#if 1 +	    free(ptr); +#else +	    _free_internal(ptr); +#endif +	    _heaplimit = oldlimit; +	    result = malloc(size); +	    if (!result) { +		/* Now we're really in trouble.  We have to unfree +		   the thing we just freed.  Unfortunately it might +		   have been coalesced with its neighbors. */ +		if (_heapindex == block) +		    malloc(blocks * BLOCKSIZE); +		else { +		    previous = malloc((block - _heapindex) * BLOCKSIZE); +		    malloc(blocks * BLOCKSIZE); +#if 1 +		    free(previous); +#else +		    _free_internal(previous); +#endif +		}	     +		return NULL; +	    } +	    if (ptr != result) +		memmove(result, ptr, blocks * BLOCKSIZE); +	    return result; +	} +	break; + +    default: +	/* Old size is a fragment; type is logarithm to base two of +	   the fragment size. */ +	if ((size > 1 << (type - 1)) && (size <= 1 << type)) +	    /* New size is the same kind of fragment. */ +	    return ptr; +	else { +	    /* New size is different; allocate a new space, and copy +	       the lesser of the new size and the old. */ +	    result = malloc(size); +	    if (!result) +		return NULL; +	    memcpy(result, ptr, MIN(size, 1 << type)); +	    free(ptr); +	    return result; +	} +	break; +    } +} diff --git a/libc/stdlib/malloc-930716/valloc.c b/libc/stdlib/malloc-930716/valloc.c new file mode 100644 index 000000000..dad12a1d2 --- /dev/null +++ b/libc/stdlib/malloc-930716/valloc.c @@ -0,0 +1,62 @@ +/* Allocate memory on a page boundary. +   Copyright (C) 1991, 1992 Free Software Foundation, Inc. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; see the file COPYING.LIB.  If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + +   The author may be reached (Email) at the address mike@ai.mit.edu, +   or (US mail) as Mike Haertel c/o Free Software Foundation.  */ + +#include <stdlib.h> +#include "malloc.h" + +#ifdef	 emacs +#include "config.h" +#endif + +#ifdef	__GNU_LIBRARY__ +extern size_t __getpagesize __P ((void)); +#else +#ifndef	USG +extern size_t getpagesize __P ((void)); +#define	__getpagesize()	getpagesize() +#else +#include <sys/param.h> +#ifdef	EXEC_PAGESIZE +#define	__getpagesize()	EXEC_PAGESIZE +#else /* No EXEC_PAGESIZE.  */ +#ifdef	NBPG +#ifndef	CLSIZE +#define	CLSIZE	1 +#endif /* No CLSIZE.  */ +#define	__getpagesize()	(NBPG * CLSIZE) +#else /* No NBPG.  */ +#define	__getpagesize()	NBPC +#endif /* NBPG.  */ +#endif /* EXEC_PAGESIZE.  */ +#endif /* USG.  */ +#endif + +static size_t pagesize; + +__ptr_t +valloc (size) +     size_t size; +{ +  if (pagesize == 0) +    pagesize = __getpagesize (); + +  return memalign (pagesize, size); +} diff --git a/libc/stdlib/malloc-simple/Makefile b/libc/stdlib/malloc-simple/Makefile index 294902b97..cc2c132b2 100644 --- a/libc/stdlib/malloc-simple/Makefile +++ b/libc/stdlib/malloc-simple/Makefile @@ -40,8 +40,8 @@ $(MOBJ): $(MSRC)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/stdlib/malloc/Makefile b/libc/stdlib/malloc/Makefile index d7ae2732d..0128bc545 100644 --- a/libc/stdlib/malloc/Makefile +++ b/libc/stdlib/malloc/Makefile @@ -42,8 +42,8 @@ $(MOBJ): $(MSRC)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/stdlib/qsort.c b/libc/stdlib/qsort.c index 7cb1d8ab4..7390c3bd3 100644 --- a/libc/stdlib/qsort.c +++ b/libc/stdlib/qsort.c @@ -1,148 +1,72 @@ -/* - * This file lifted in toto from 'Dlibs' on the atari ST  (RdeBath) - * - *  - *    Dale Schumacher                         399 Beacon Ave. - *    (alias: Dalnefre')                      St. Paul, MN  55104 - *    dal@syntel.UUCP                         United States of America - *  "It's not reality that's important, but how you perceive things." - */ -#include <string.h> - -char *_qbuf = 0;				/* pointer to storage for qsort() */ - -#define	PIVOT			((i+j)>>1) -#define moveitem(dst,src,size)	if(dst != src) memcpy(dst, src, size) - -static void _wqsort(base, lo, hi, cmp) -register int *base; -register int lo; -register int hi; -register int (*cmp) (); -{ -	int k; -	register int i, j, t; -	register int *p = &k; - -	while (hi > lo) { -		i = lo; -		j = hi; -		t = PIVOT; -		*p = base[t]; -		base[t] = base[i]; -		base[i] = *p; -		while (i < j) { -			while (((*cmp) ((base + j), p)) > 0) -				--j; -			base[i] = base[j]; -			while ((i < j) && (((*cmp) ((base + i), p)) <= 0)) -				++i; -			base[j] = base[i]; -		} -		base[i] = *p; -		if ((i - lo) < (hi - i)) { -			_wqsort(base, lo, (i - 1), cmp); -			lo = i + 1; -		} else { -			_wqsort(base, (i + 1), hi, cmp); -			hi = i - 1; -		} -	} -} - -static void _lqsort(base, lo, hi, cmp) -register long *base; -register int lo; -register int hi; -register int (*cmp) (); -{ -	long k; -	register int i, j, t; -	register long *p = &k; - -	while (hi > lo) { -		i = lo; -		j = hi; -		t = PIVOT; -		*p = base[t]; -		base[t] = base[i]; -		base[i] = *p; -		while (i < j) { -			while (((*cmp) ((base + j), p)) > 0) -				--j; -			base[i] = base[j]; -			while ((i < j) && (((*cmp) ((base + i), p)) <= 0)) -				++i; -			base[j] = base[i]; -		} -		base[i] = *p; -		if ((i - lo) < (hi - i)) { -			_lqsort(base, lo, (i - 1), cmp); -			lo = i + 1; -		} else { -			_lqsort(base, (i + 1), hi, cmp); -			hi = i - 1; -		} -	} -} - -static void _nqsort(base, lo, hi, size, cmp) -register char *base; -register int lo; -register int hi; -register int size; -register int (*cmp) (); -{ -	register int i, j; -	register char *p = _qbuf; - -	while (hi > lo) { -		i = lo; -		j = hi; -		p = (base + size * PIVOT); -		moveitem(_qbuf, p, size); -		moveitem(p, (base + size * i), size); -		moveitem((base + size * i), _qbuf, size); -		p = _qbuf; -		while (i < j) { -			while (((*cmp) ((base + size * j), p)) > 0) -				--j; -			moveitem((base + size * i), (base + size * j), size); -			while ((i < j) && (((*cmp) ((base + size * i), p)) <= 0)) -				++i; -			moveitem((base + size * j), (base + size * i), size); -		} -		moveitem((base + size * i), p, size); -		if ((i - lo) < (hi - i)) { -			_nqsort(base, lo, (i - 1), size, cmp); -			lo = i + 1; -		} else { -			_nqsort(base, (i + 1), hi, size, cmp); -			hi = i - 1; -		} -	} -} - -extern int qsort(base, num, size, cmp) -char *base; -int num; -int size; -int (*cmp) (); -{ -	char _qtemp[128]; - -	if (_qbuf == 0) { -		if (size > sizeof(_qtemp))	/* records too large! */ -			return 1; -		_qbuf = _qtemp; -	} -	if (size == 2) -		_wqsort(base, 0, num - 1, cmp); -	else if (size == 4) -		_lqsort(base, 0, num - 1, cmp); -	else -		_nqsort(base, 0, num - 1, size, cmp); -	if (_qbuf == _qtemp) -		_qbuf = 0; -	return 0; -} +/* +++Date last modified: 05-Jul-1997 */
 +
 +/*
 +**  ssort()  --  Fast, small, qsort()-compatible Shell sort
 +**
 +**  by Ray Gardner,  public domain   5/90
 +*/
 +
 +/*
 + * Manuel Novoa III       Dec 2000
 + *
 + * There were several problems with the qsort code contained in uClibc.
 + * It assumed sizeof(int) was 2 and sizeof(long) was 4.  It then had three
 + * seperate quiicksort routines based on the width of the data passed: 2, 4,
 + * or anything else <= 128.  If the width was > 128, it returned -1 (although
 + * qsort should not return a value) and did no sorting.  On i386 with
 + * -Os -fomit-frame-pointer -ffunction-sections, the text segment of qsort.o
 + * was 1358 bytes, with an additional 4 bytes in bss.
 + *
 + * I decided to completely replace the existing code with a small
 + * implementation of a shell sort.  It is a drop-in replacement for the
 + * standard qsort and, with the same gcc flags as above, the text segment
 + * size on i386 is only 183 bytes.
 + *
 + * Grabbed original file rg_ssort.c from snippets.org.
 + * Modified original code to avoid possible overflow in wgap calculation.
 + * Modified wgap calculation in loop and eliminated variables gap and wnel.
 + */
 +
 +
 +#include <stdlib.h>
 +
 +void qsort (void  *base,
 +            size_t nel,
 +            size_t width,
 +            int (*comp)(const void *, const void *))
 +{
 +	size_t wgap, i, j, k;
 +	char *a, *b, tmp;
 +
 +#if 0
 +	/* Note: still conceivable that nel * width could overflow! */
 +	assert(width > 0);
 +#endif
 +
 +	if (nel > 1) {
 +		for (wgap = 0; ++wgap < (nel-1)/3 ; wgap *= 3) {}
 +		wgap *= width;
 +		nel *= width;			/* convert nel to 'wnel' */
 +		do {
 +			for (i = wgap; i < nel; i += width) {
 +				for (j = i - wgap; ;j -= wgap) {
 +					a = j + ((char *)base);
 +					b = a + wgap;
 +					if ( (*comp)(a, b) <= 0 ) {
 +						break;
 +					}
 +					k = width;
 +					do {
 +						tmp = *a;
 +						*a++ = *b;
 +						*b++ = tmp;
 +					} while ( --k );
 +					if (j < wgap) {
 +						break;
 +					}
 +				}
 +			}
 +			wgap = (wgap - width)/3;
 +		} while (wgap);
 +	}
 +}
 diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c index 061dbc914..5b279976c 100644 --- a/libc/stdlib/system.c +++ b/libc/stdlib/system.c @@ -35,7 +35,9 @@ char *command;  	signal(SIGQUIT, SIG_IGN);  	signal(SIGINT, SIG_IGN); +#if 0  	printf("Waiting for child %d\n", pid); +#endif  	if (wait4(pid, &wait_val, 0, 0) == -1)  		wait_val = -1; diff --git a/libc/string/Makefile b/libc/string/Makefile index b532ec4d2..1c8c6283a 100644 --- a/libc/string/Makefile +++ b/libc/string/Makefile @@ -53,8 +53,8 @@ $(MOBJ1): $(MSRC1)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/string/strerror.c b/libc/string/strerror.c index 3aa8b57e2..36c467ef4 100644 --- a/libc/string/strerror.c +++ b/libc/string/strerror.c @@ -23,13 +23,19 @@ Cambridge, MA 02139, USA.  */   * are smaller than the previous functions and don't require static buffers.   * Removed dependence on strcat in the process.   * - * Also appended a test routine ( -DSTRERROR_TEST ) to allow a quick check + * Also appended a test routine ( -DCHECK_BUF ) to allow a quick check   * on the buffer length when the sys_errorlist is modified. + * + * Added the option WANT_ERRORLIST for low-memory applications to omit the + * error message strings and only output the error number.   */ +#define WANT_ERRORLIST     1 +  #include <stdio.h>  #include <string.h>  #include <errno.h> +  #include <limits.h>  #if (INT_MAX >> 31) @@ -39,7 +45,11 @@ Cambridge, MA 02139, USA.  */  extern char *__ltostr(char *buf, long uval, int base, int uppercase); +#if WANT_ERRORLIST +static char retbuf[48]; +#else  static char retbuf[33];			/* 33 is sufficient for 32 bit ints */ +#endif  static const char unknown_error[] = "Unknown Error: errno"; /* = */  /* Return a string descibing the errno code in ERRNUM. @@ -49,10 +59,12 @@ char *strerror(int err)  {  	char *pos; +#if WANT_ERRORLIST  	if ((err >= 0) && (err < sys_nerr)) {  		strcpy(retbuf, sys_errlist[err]);  		return retbuf;  	} +#endif  	/* unknown error */  	pos = __ltostr(retbuf + sizeof(retbuf) + 1, err, 10, 0) @@ -62,24 +74,39 @@ char *strerror(int err)  	return pos;  } -#if STRERROR_TEST -/* quick way to check for sufficient buffer length */ +#ifdef CHECK_BUF +/* quick way to check buffer length */  #include <stdio.h>  #include <stdlib.h>  int main(void)  {  	int max = 0; -	int i, j; +	int j, retcode;  	char *p; +#if WANT_ERRORLIST +	int i; +#endif + +	retcode = EXIT_SUCCESS; + +#if WANT_ERRORLIST  	for ( i=0 ; i < sys_nerr ; i++ ) {  		j = strlen(sys_errlist[i])+1;  		if (j > max) max = j;  	} -	printf("max len = %i\n", j); +#endif  	p = strerror(INT_MIN); -	printf("<%s>  %d\n", p, strlen(p)+1); -	printf("current buffer length is %d\n", sizeof(retbuf)); -	return EXIT_SUCCESS; +	j = strlen(p)+1; +	if (j > max) max = j; +	printf("strerror.c - Test of INT_MIN: <%s>  %d\n", p, j); + +	if (sizeof(retbuf) != max) { +		printf("Error: strerror.c - dimension of retbuf should be = %d\n", max); +		retcode = EXIT_FAILURE; +	} +	printf("strerror.c - dimension of retbuf correct at %d\n", max); + +	return retcode;  }  #endif diff --git a/libc/string/strsignal.c b/libc/string/strsignal.c index 1a0a6ca47..60acc65b0 100644 --- a/libc/string/strsignal.c +++ b/libc/string/strsignal.c @@ -14,16 +14,31 @@   * Also fixed a bug in the signal name lookup code.  While the table is   * declared with dimension > 60, there are currently on 32 signals listed.   * - * Also appended a test routine ( -DSTRSIGNAL_TEST ) to allow a quick check - * on the buffer length when the sys_errorlist is modified. + * Also appended a test routine ( -DCHECK_BUF ) to allow a quick check + * on the buffer length and the number of known signals when the sys_errorlist + * is modified. + * + * Added the option WANT_SIGLIST for low-memory applications to omit the + * signal message strings and only output the signal number.   */ +#define WANT_SIGLIST       1 +  #include <string.h>  #include <malloc.h>  #include <signal.h> +#include <limits.h> + +#if (INT_MAX >> 31) +/* We're set up for 32 bit ints */ +#error need to check size allocation for static buffer 'retbuf' +#endif +  extern char *__ltostr(char *buf, long uval, int base, int uppercase); +#if WANT_SIGLIST +  const char *const sys_siglist[] = {  	"Unknown signal",  	"Hangup", @@ -60,26 +75,27 @@ const char *const sys_siglist[] = {  	NULL  }; -#include <limits.h> - -#if (INT_MAX >> 31) -/* We're set up for 32 bit ints */ -#error need to check size allocation for static buffer 'retbuf'  #endif +#define NUM_KNOWN_SIGNALS    32 +  /********************** Function strsignal ************************************/ +static char retbuf[28];			/* 28 is sufficient for 32 bit ints */ +static const char unknown_signal[] = "Unknown Signal:"; +  char *strsignal(int sig)  { -	static char retbuf[28];		/* 28 is sufficient for 32 bit ints */ -	static const char unknown_signal[] = "Unknown Signal:";  	char *pos; +#ifdef WANT_SIGLIST  	/* if ((sig >= 0) && (sig < _NSIG)) { */ -	if ((sig >= 0) && (sig < 32)) { /* WARNING!!! NOT ALL _NSIG DEFINED!!! */ +	/* WARNING!!! NOT ALL _NSIG DEFINED!!! */ +	if ((sig >= 0) && (sig < NUM_KNOWN_SIGNALS)) {  		strcpy(retbuf, sys_siglist[sig]);  		return retbuf;  	} +#endif  	pos = __ltostr(retbuf + sizeof(unknown_signal) + 1, sig, 10, 0)  		- sizeof(unknown_signal); @@ -90,33 +106,44 @@ char *strsignal(int sig)  /********************** THE END ********************************************/ -#if STRSIGNAL_TEST +#ifdef CHECK_BUF  /* quick way to check for sufficient buffer length */  #include <stdio.h>  #include <stdlib.h>  int main(void)  {  	int max = 0; -	int i, j; +	int j, retcode; +  	const char *p; +#if WANT_SIGLIST +	int i; +#endif +	retcode = EXIT_SUCCESS; +#if WANT_SIGLIST  	printf("_NSIG = %d  from headers\n", _NSIG); -	for ( i=0 ; i < _NSIG ; i++ ) { -		p = sys_siglist[i]; -		if (!p) { -			printf("Warning! I only count %d signals!\n", i); -			break; -		} +	for ( i=0 ; sys_siglist[i] ; i++ ) {  		j = strlen(sys_siglist[i])+1;  		if (j > max) max = j;  	} -	printf("max len = %i\n", j); +	if (i != NUM_KNOWN_SIGNALS) { +		printf("Error: strsignal.c - NUM_KNOWN_SIGNALS should be %d\n", i); +		retcode = EXIT_FAILURE; +	} +#endif  	p = strsignal(INT_MIN); -	printf("<%s>  %d\n", p, strlen(p)+1); +	j = strlen(p)+1; +	if (j > max) max = j; +	printf("strsignal.c - Test of INT_MIN: <%s>  %d\n", p, j); + +	if (sizeof(retbuf) != max) { +		printf("Error: strsignal.c - dimension of retbuf should be = %d\n", max); +		retcode = EXIT_FAILURE; +	} +	printf("strsignal.c - dimension of retbuf correct at %d\n", max); -	p = strsignal(i-1); -	printf("last signal %d is %s\n", i-1, p); -	return EXIT_SUCCESS; +	return retcode;  }  #endif diff --git a/libc/sysdeps/linux/arm/Makefile b/libc/sysdeps/linux/arm/Makefile index db3cf1966..7d901b769 100644 --- a/libc/sysdeps/linux/arm/Makefile +++ b/libc/sysdeps/linux/arm/Makefile @@ -41,12 +41,12 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(SOBJS): -	$(CC) $(CFLAGS) $< -c $*.S -o $*.o +$(SOBJS): %.o : %.S +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/sysdeps/linux/common/Makefile b/libc/sysdeps/linux/common/Makefile index 73190ac9c..3a66e4c2e 100644 --- a/libc/sysdeps/linux/common/Makefile +++ b/libc/sysdeps/linux/common/Makefile @@ -25,7 +25,6 @@ TOPDIR=../../../  include $(TOPDIR)Rules.mak  LIBC=$(TOPDIR)libc.a -  CSRC =closedir.c dirfd.c getdents.c getdnnm.c gethstnm.c getpagesize.c \  	isatty.c kernel_version.c mkfifo.c opendir.c readdir.c rewinddir.c \  	seekdir.c setegid.c seteuid.c setpgrp.c statfix.c tell.c telldir.c \ @@ -40,7 +39,16 @@ MOBJ=$(shell ./list_syscalls.sh)  OBJ=$(COBJS) $(NIOBJS) $(MOBJ) -all: $(OBJ) $(LIBC) +UNIFIED_SYSCALL_HEADER = /dev/null +STR_SYSCALLS = +ifeq ($(UNIFIED_SYSCALL),true) +	ifeq ($(TARGET_ARCH), i386) +		UNIFIED_SYSCALL_HEADER = unified_syscall_i386.h +		STR_SYSCALLS = str_syscalls +	endif +endif + +all: $(STR_SYSCALLS) unified_syscall.h $(OBJ) $(LIBC)  $(LIBC): ar-target @@ -51,14 +59,22 @@ $(MOBJ): $(MSRC)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  $(NIOBJS):  	$(CC) $(CFLAGS) $< -c $*.c -o $*.o -fno-inline  	$(STRIPTOOL) -x -R .note -R .comment $*.o +str_syscalls: +	./str_syscalls.sh > str_syscalls.c +	gcc str_syscalls.c -o str_syscalls +	./str_syscalls > str_syscalls.h + +unified_syscall.h: +	cat $(UNIFIED_SYSCALL_HEADER) > unified_syscall.h +  clean: -	rm -f *.[oa] *~ core +	rm -f *.[oa] *~ core unified_syscall.h str_syscalls.[ch] str_syscalls diff --git a/libc/sysdeps/linux/common/str_syscalls.sh b/libc/sysdeps/linux/common/str_syscalls.sh new file mode 100755 index 000000000..66ef6824d --- /dev/null +++ b/libc/sysdeps/linux/common/str_syscalls.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +echo "#include <stdio.h>" +echo "#include <stdlib.h>" +echo "#include \"../include/asm/unistd.h\"" +echo +echo "int main(void) {" +echo +echo "#define __NR__exit __NR_exit" +echo "#define __NR___open __NR_open" +echo "#define __NR__ioctl __NR_ioctl" +echo "#define __NR__fcntl __NR_fcntl" +echo "#define __NR__reboot __NR_reboot" +echo "#define __NR__mmap __NR_mmap" +echo "#define __NR__syslog __NR_syslog" +echo "#define __NR__stat __NR_stat" +echo "#define __NR__lstat __NR_lstat" +echo "#define __NR__fstat __NR_fstat" +echo "#define __NR__getdents __NR_getdents" +echo +sed -ne 's/^.*_syscall[0-9].*([^,]*, *\([^,)]*\).*/printf("#define __STR_NR_\1 \\\"%d\\\"\\n", __NR_\1);/gp' syscalls.c +echo +echo "printf(\"#define __STR_NR_exit     __STR_NR__exit\n\");" +echo "printf(\"#define __STR_NR_open    __STR_NR___open\n\");" +echo "printf(\"#define __STR_NR_ioctl    __STR_NR__ioctl\n\");" +echo "printf(\"#define __STR_NR_fcntl    __STR_NR__fcntl\n\");" +echo "printf(\"#define __STR_NR_reboot   __STR_NR__reboot\n\");" +echo "printf(\"#define __STR_NR_mmap     __STR_NR__mmap\n\");" +echo "printf(\"#define __STR_NR_syslog   __STR_NR__syslog\n\");" +echo "printf(\"#define __STR_NR_stat     __STR_NR__stat\n\");" +echo "printf(\"#define __STR_NR_lstat    __STR_NR__lstat\n\");" +echo "printf(\"#define __STR_NR_fstat    __STR_NR__fstat\n\");" +echo "printf(\"#define __STR_NR_getdents __STR_NR__getdents\n\");" +echo +echo "return EXIT_SUCCESS; }" diff --git a/libc/sysdeps/linux/common/syscalls.c b/libc/sysdeps/linux/common/syscalls.c index 2f9fb723d..e726ba7fc 100644 --- a/libc/sysdeps/linux/common/syscalls.c +++ b/libc/sysdeps/linux/common/syscalls.c @@ -26,13 +26,18 @@  #include <sys/types.h>  #include <sys/syscall.h> +#define uClibc_syscall_exit(void, _exit, int, status) \ +_syscall1(void, _exit, int, status) + + +#include "unified_syscall.h"  //#define __NR_exit             1  #ifdef L__exit  /* Do not include unistd.h, so gcc doesn't whine about    * _exit returning.  It really doesn't return... */  #define __NR__exit __NR_exit -_syscall1(void, _exit, int, status); +uClibc_syscall_exit(void, _exit, int, status);  #endif  //#define __NR_fork             2 @@ -347,6 +352,9 @@ _syscall2(int, umount2, const char *, special_file, int, flags);  #include <stdarg.h>  #include <sys/ioctl.h>  #define __NR__ioctl __NR_ioctl + +extern int _ioctl(int fd, int request, void *arg); +  _syscall3(int, _ioctl, int, fd, int, request, void *, arg);  int ioctl(int fd, unsigned long int request, ...) @@ -368,6 +376,9 @@ int ioctl(int fd, unsigned long int request, ...)  #include <stdarg.h>  #include <fcntl.h>  #define __NR__fcntl __NR_fcntl + +extern int _fcntl(int fd, int cmd, long arg); +  _syscall3(int, _fcntl, int, fd, int, cmd, long, arg);  int fcntl(int fd, int command, ...) @@ -558,6 +569,9 @@ _syscall2(int, swapon, const char *, path, int, swapflags);  //#define __NR_reboot           88  #ifdef L__reboot  #define __NR__reboot __NR_reboot + +extern int _reboot(int magic, int magic2, int flag); +  _syscall3(int, _reboot, int, magic, int, magic2, int, flag);  int reboot(int flag) @@ -574,6 +588,8 @@ int reboot(int flag)  #include <unistd.h>  #include <sys/mman.h> +extern __ptr_t _mmap(unsigned long *buffer); +  _syscall1(__ptr_t, _mmap, unsigned long *, buffer);  __ptr_t mmap(__ptr_t addr, size_t len, int prot, @@ -667,6 +683,9 @@ _syscall2(int, socketcall, int, call, unsigned long *, args);  #ifdef L__syslog  #include <unistd.h>  #define __NR__syslog		__NR_syslog + +extern int _syslog(int type, char *buf, int len); +  _syscall3(int, _syslog, int, type, char *, buf, int, len);  int klogctl(int type, char *buf, int len) @@ -694,6 +713,8 @@ _syscall2(int, getitimer, enum __itimer_which, which, struct itimerval *, value)  #define __NR__stat __NR_stat  #include <unistd.h>  #include "statfix.h" +extern int _stat(const char *file_name, struct kernel_stat *buf); +  _syscall2(int, _stat, const char *, file_name, struct kernel_stat *, buf);  int stat(const char * file_name, struct libc_stat * cstat) @@ -713,6 +734,8 @@ int stat(const char * file_name, struct libc_stat * cstat)  #define __NR__lstat __NR_lstat  #include <unistd.h>  #include "statfix.h" +extern int _lstat(const char *file_name, struct kernel_stat *buf); +  _syscall2(int, _lstat, const char *, file_name, struct kernel_stat *, buf);  int lstat(const char * file_name, struct libc_stat * cstat) @@ -732,6 +755,8 @@ int lstat(const char * file_name, struct libc_stat * cstat)  #define __NR__fstat __NR_fstat  #include <unistd.h>  #include "statfix.h" +extern int _fstat(int filedes, struct kernel_stat *buf); +  _syscall2(int, _fstat, int, filedes, struct kernel_stat *, buf);  int fstat(int fd, struct libc_stat *cstat)  @@ -878,6 +903,8 @@ SYSCALL__(setfsuid, 1)  #endif  //#define __NR__llseek          140  #ifdef L__llseek +extern int _llseek(int fd, off_t hoff, off_t loff, loff_t *res, int whence); +  _syscall5(int, _llseek, int, fd, off_t, hoff, off_t, loff, loff_t *, res,  		  int, whence); @@ -904,6 +931,9 @@ _syscall3(int, _getdents, int, fd, char *, dirp, size_t, count);  //#define __NR__newselect       142  #ifdef L__newselect  #include <unistd.h> +extern int _newselect(int n, fd_set *readfds, fd_set *writefds, +					  fd_set *exceptfds, struct timeval *timeout); +  _syscall5(int, _newselect, int, n, fd_set *, readfds, fd_set *, writefds,  		  fd_set *, exceptfds, struct timeval *, timeout); diff --git a/libc/sysdeps/linux/common/unified_syscall_i386.h b/libc/sysdeps/linux/common/unified_syscall_i386.h new file mode 100644 index 000000000..793337af7 --- /dev/null +++ b/libc/sysdeps/linux/common/unified_syscall_i386.h @@ -0,0 +1,41 @@ +#undef _syscall0 +#undef _syscall1 +#undef _syscall2 +#undef _syscall3 +#undef _syscall4 +#undef _syscall5 + +#include "str_syscalls.h" + +#undef uClibc_syscall_exit +#define uClibc_syscall_exit(type,name,type1,arg1) \ +__asm__ ( \ +".text\n.align 4\n.global "###name"\n"#name":;\npushl %ebp;\n" \ +"movl %esp,%ebp;\nsubl $4,%esp;\npushl %ebx;\nmovl 8(%ebp),%ebx;\n" \ +"jmp _start_exit" \ +) + +#define unified_syscall_body(name) \ +__asm__ ( \ +".text\n.align 4\n.global "###name"\n"#name":\nmovb $"__STR_NR_##name \ +",%al;\n jmp __uClibc_syscall" \ +) + +#define _syscall0(type,name) \ +unified_syscall_body(name) + +#define _syscall1(type,name,type1,arg1) \ +unified_syscall_body(name) + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +unified_syscall_body(name) + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +unified_syscall_body(name) + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +unified_syscall_body(name) + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +unified_syscall_body(name) + diff --git a/libc/sysdeps/linux/i386/Makefile b/libc/sysdeps/linux/i386/Makefile index f4520b4ac..9c487bfd1 100644 --- a/libc/sysdeps/linux/i386/Makefile +++ b/libc/sysdeps/linux/i386/Makefile @@ -26,9 +26,12 @@ LIBC=$(TOPDIR)libc.a  ASFLAGS=$(CFLAGS)  SSRC=_start.S longjmp.S setjmp.S #_start.S #clone.S +ifeq ($(UNIFIED_SYSCALL),true) +	SSRC += __uClibc_syscall.S +endif  SOBJS=$(patsubst %.S,%.o, $(SSRC)) -CSRC=fork.c vfork.c +CSRC=fork.c vfork.c __init_brk.c brk.c sbrk.c  COBJS=$(patsubst %.c,%.o, $(CSRC))  OBJS=$(SOBJS) $(COBJS) @@ -41,12 +44,12 @@ $(LIBC): ar-target  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(SOBJS):  -	$(CC) $(CFLAGS) $< -c $*.S -o $*.o +$(SOBJS): %.o : %.S +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/sysdeps/linux/i386/__init_brk.c b/libc/sysdeps/linux/i386/__init_brk.c new file mode 100644 index 000000000..c2ae482dd --- /dev/null +++ b/libc/sysdeps/linux/i386/__init_brk.c @@ -0,0 +1,33 @@ +/* From libc-5.3.12 */ + +#include <unistd.h> +#include <sys/syscall.h> +#include <errno.h> + +void * ___brk_addr = 0; + +int +__init_brk () +{ +    if (___brk_addr == 0) +    { +#if defined(__PIC__) || defined (__pic__) +	__asm__ volatile ("pushl %%ebx\n\t" +			  "movl $0,%%ebx\n\t" +			  "int $0x80\n\t" +			  "popl %%ebx" +		:"=a" (___brk_addr) +		:"0" (SYS_brk)); +#else +	__asm__ volatile ("int $0x80" +		:"=a" (___brk_addr) +		:"0" (SYS_brk),"b" (0)); +#endif +	if (___brk_addr == 0) +	{ +	  errno = ENOMEM; +	  return -1; +	} +    } +    return 0; +} diff --git a/libc/sysdeps/linux/i386/__uClibc_syscall.S b/libc/sysdeps/linux/i386/__uClibc_syscall.S new file mode 100644 index 000000000..ecf2d6350 --- /dev/null +++ b/libc/sysdeps/linux/i386/__uClibc_syscall.S @@ -0,0 +1,39 @@ +.globl __uClibc_syscall + +.text +	.align 4 +__uClibc_syscall: +	pushl %ebp +	movl %esp,%ebp +	subl $8,%esp +	pushl %edi +	pushl %esi +	pushl %ebx +	/* movl $21,%eax */ +	and $0xff,%eax +	movl 8(%ebp),%ebx +	movl 12(%ebp),%ecx +	movl 16(%ebp),%edx +	movl 20(%ebp),%esi +	movl 24(%ebp),%edi +#APP +	int $0x80 +#NO_APP +	movl %eax,-4(%ebp) +	.p2align 4,,7 +	cmpl $-126,-4(%ebp) +	jbe .L5 +	movl -4(%ebp),%eax +	negl %eax +	movl %eax,errno +	movl $-1,-4(%ebp) +.L5: +	movl -4(%ebp),%edx +	movl %edx,-8(%ebp) +	movl -8(%ebp),%eax +	leal -20(%ebp),%esp +	popl %ebx +	popl %esi +	popl %edi +	leave +	ret diff --git a/libc/sysdeps/linux/i386/brk.c b/libc/sysdeps/linux/i386/brk.c new file mode 100644 index 000000000..2a776bac1 --- /dev/null +++ b/libc/sysdeps/linux/i386/brk.c @@ -0,0 +1,32 @@ +/* From libc-5.3.12 */ + +#include <unistd.h> +#include <sys/syscall.h> +#include <errno.h> + +extern void * ___brk_addr; + +extern int __init_brk (); + +int brk(void * end_data_seg) +{ +    if (__init_brk () == 0) +    { +#if defined(__PIC__) || defined (__pic__) +	__asm__ volatile ("pushl %%ebx\n\t" +			  "movl %%ecx,%%ebx\n\t" +			  "int $0x80\n\t" +			  "popl %%ebx" +		:"=a" (___brk_addr) +		:"0" (SYS_brk),"c" (end_data_seg)); +#else +	__asm__ volatile ("int $0x80" +		:"=a" (___brk_addr) +		:"0" (SYS_brk),"b" (end_data_seg)); +#endif +	if (___brk_addr == end_data_seg) +		return 0; +	errno = ENOMEM; +    } +    return -1; +} diff --git a/libc/sysdeps/linux/i386/sbrk.c b/libc/sysdeps/linux/i386/sbrk.c new file mode 100644 index 000000000..f5099d7e8 --- /dev/null +++ b/libc/sysdeps/linux/i386/sbrk.c @@ -0,0 +1,35 @@ +/* From libc-5.3.12 */ + +#include <unistd.h> +#include <sys/syscall.h> +#include <errno.h> + +extern void * ___brk_addr; + +extern int __init_brk (void); + +void * +sbrk(ptrdiff_t increment) +{ +    if (__init_brk () == 0) +    { +	void * tmp = ___brk_addr+increment; +#if defined(__PIC__) || defined (__pic__) +	__asm__ volatile ("pushl %%ebx\n\t" +			  "movl %%ecx,%%ebx\n\t" +                          "int $0x80\n\t" +                          "popl %%ebx" +		:"=a" (___brk_addr) +		:"0" (SYS_brk),"c" (tmp)); +#else +	__asm__ volatile ("int $0x80" +		:"=a" (___brk_addr) +		:"0" (SYS_brk),"b" (tmp)); +#endif +	if (___brk_addr == tmp) +		return tmp-increment; +	errno = ENOMEM; +	return ((void *) -1); +    } +    return ((void *) -1); +} diff --git a/libc/termios/Makefile b/libc/termios/Makefile index cb4c2c6f8..f90c5922a 100644 --- a/libc/termios/Makefile +++ b/libc/termios/Makefile @@ -45,8 +45,8 @@ $(MOBJ): $(MSRC)  	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@  	$(STRIPTOOL) -x -R .note -R .comment $*.o  clean: diff --git a/libc/unistd/Makefile b/libc/unistd/Makefile index faebda604..c1ff28575 100644 --- a/libc/unistd/Makefile +++ b/libc/unistd/Makefile @@ -28,8 +28,13 @@ LIBC=$(TOPDIR)libc.a  CSRC=execl.c execlp.c execv.c execvep.c execvp.c getcwd.c getopt.c \  	sleep.c sysconf.c getpass.c  COBJS=$(patsubst %.c,%.o, $(CSRC)) -OBJS=$(COBJS) +MSRC=gnu_getopt.c +MOBJ=_gnu_getopt_internal.o gnu_getopt_long.o gnu_getopt_long_only.o + +# WARNING! MOBJ _must_ come after COBJS for link to pick getopt  +# over gnu_getopt when appropriate. +OBJS=$(COBJS) $(MOBJ)  all: $(OBJS) $(LIBC) @@ -38,8 +43,12 @@ $(LIBC): ar-target subdirs  ar-target: $(OBJS)  	$(AR) $(ARFLAGS) $(LIBC) $(OBJS) -$(COBJS): -	$(CC) $(CFLAGS) $< -c $*.c -o $*.o +$(COBJS): %.o : %.c +	$(CC) $(CFLAGS) -c $< -o $@ +	$(STRIPTOOL) -x -R .note -R .comment $*.o + +$(MOBJ): $(MSRC) +	$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o  	$(STRIPTOOL) -x -R .note -R .comment $*.o  $(OBJ): Makefile diff --git a/libc/unistd/getopt.c b/libc/unistd/getopt.c index 83a9ad69c..a850d9bde 100644 --- a/libc/unistd/getopt.c +++ b/libc/unistd/getopt.c @@ -13,13 +13,18 @@   * and ommision of whitespace between option and arg.   */ +/* + * Modified by Manuel Novoa III on 1/5/01 to use weak symbols. + * Programs needing long options will link gnu_getopt instead. + */ +  #include <stdio.h>  #include <string.h> -int opterr = 1;					/* error => print message */ -int optind = 1;					/* next argv[] index */ -int optopt = 1;					/* Set for unknown arguments */ -char *optarg = NULL;			/* option parameter if any */ +int opterr __attribute__ ((__weak__)) = 1; /* error => print message */ +int optind __attribute__ ((__weak__)) = 1; /* next argv[] index */ +int optopt __attribute__ ((__weak__)) = 1; /* Set for unknown arguments */ +char *optarg __attribute__ ((__weak__)) = NULL;	/* option parameter if any */  static int Err(name, mess, c) /* returns '?' */  char *name;						/* program name argv[0] */ @@ -34,6 +39,9 @@ int c;							/* defective option letter */  	return '?';					/* erroneous-option marker */  } +extern int getopt (int argc, char *const *argv, const char *optstring) +	 __attribute__ ((__weak__)); +  int getopt (int argc, char *const *argv, const char *optstring)  {  	static int sp = 1;			/* position within argument */ diff --git a/libc/unistd/getpass.c b/libc/unistd/getpass.c index 4fcc489c8..92d3565c8 100644 --- a/libc/unistd/getpass.c +++ b/libc/unistd/getpass.c @@ -17,6 +17,7 @@     Boston, MA 02111-1307, USA.  */  #include <stdio.h> +#include <string.h>  #include <termios.h>  #include <unistd.h>  #include <string.h> @@ -72,9 +73,9 @@ getpass (prompt)    /* Read the password.  */    fgets (buf, PWD_BUFFER_SIZE-1, in); -  nread = strlen(buf);    if (buf != NULL)      { +      nread = strlen(buf);        if (nread < 0)  	buf[0] = '\0';        else if (buf[nread - 1] == '\n') diff --git a/libc/unistd/gnu_getopt.c b/libc/unistd/gnu_getopt.c new file mode 100644 index 000000000..c5fa33913 --- /dev/null +++ b/libc/unistd/gnu_getopt.c @@ -0,0 +1,873 @@ +/* Getopt for GNU. +   NOTE: getopt is now part of the C library, so if you don't know what +   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu +   before changing it! + +   Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 +   	Free Software Foundation, Inc. + +   This program is free software; you can redistribute it and/or +   modify it under the terms of the GNU Library General Public License +   as published by the Free Software Foundation; either version 2, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Library General Public License for more details. + +   You should have received a copy of the GNU Library General Public License +   along with this program; if not, write to the Free Software +   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */ + +/* + * Modified for uClibc by Manuel Novoa III on 1/5/01. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +/* This version of `getopt' appears to the caller like standard Unix `getopt' +   but it behaves differently for the user, since it allows the user +   to intersperse the options with the other arguments. + +   As `getopt' works, it permutes the elements of ARGV so that, +   when it is done, all the options precede everything else.  Thus +   all application programs are extended to handle flexible argument order. + +   Setting the environment variable POSIXLY_CORRECT disables permutation. +   Then the behavior is completely standard. + +   GNU application programs can use a third alternative mode in which +   they can distinguish the relative order of options and other arguments.  */ + +#include <getopt.h> + +extern int _getopt_internal (int argc, char *const *argv,  +							 const char *optstring, +							 const struct option *longopts, +							 int *longind, int long_only); + + +#ifdef L__gnu_getopt_internal + +/* For communication from `getopt' to the caller. +   When `getopt' finds an option that takes an argument, +   the argument value is returned here. +   Also, when `ordering' is RETURN_IN_ORDER, +   each non-option ARGV-element is returned here.  */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. +   This is used for communication to and from the caller +   and for communication between successive calls to `getopt'. + +   On entry to `getopt', zero means this is the first call; initialize. + +   When `getopt' returns EOF, this is the index of the first of the +   non-option elements that the caller should itself scan. + +   Otherwise, `optind' communicates from one call to the next +   how much of ARGV has been scanned so far.  */ + +/* XXX 1003.2 says this must be 1 before any call.  */ +int optind = 0; + +/* The next char to be scanned in the option-element +   in which the last option character we returned was found. +   This allows us to pick up the scan where we left off. + +   If this is zero, or a null string, it means resume the scan +   by advancing to the next ARGV-element.  */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message +   for unrecognized options.  */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. +   This must be initialized on some systems to avoid linking in the +   system's own getopt implementation.  */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + +   If the caller did not specify anything, +   the default is REQUIRE_ORDER if the environment variable +   POSIXLY_CORRECT is defined, PERMUTE otherwise. + +   REQUIRE_ORDER means don't recognize them as options; +   stop option processing when the first non-option is seen. +   This is what Unix does. +   This mode of operation is selected by either setting the environment +   variable POSIXLY_CORRECT, or using `+' as the first character +   of the list of option characters. + +   PERMUTE is the default.  We permute the contents of ARGV as we scan, +   so that eventually all the non-options are at the end.  This allows options +   to be given in any order, even with programs that were not written to +   expect this. + +   RETURN_IN_ORDER is an option available to programs that were written +   to expect options and other ARGV-elements in any order and that care about +   the ordering of the two.  We describe each non-option ARGV-element +   as if it were the argument of an option with character code 1. +   Using `-' as the first character of the list of option characters +   selects this mode of operation. + +   The special argument `--' forces an end of option-scanning regardless +   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only +   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */ + +static enum +{ +  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +#include <string.h> +#define	my_index	strchr + +/* Handle permutation of arguments.  */ + +/* Describe the part of ARGV that contains non-options that have +   been skipped.  `first_nonopt' is the index in ARGV of the first of them; +   `last_nonopt' is the index after the last of them.  */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. +   One subsequence is elements [first_nonopt,last_nonopt) +   which contains all the non-options that have been skipped so far. +   The other is elements [last_nonopt,optind), which contains all +   the options processed since those non-options were skipped. + +   `first_nonopt' and `last_nonopt' are relocated so that they describe +   the new indices of the non-options in ARGV after they are moved.  */ + +static void +exchange (argv) +     char **argv; +{ +  int bottom = first_nonopt; +  int middle = last_nonopt; +  int top = optind; +  char *tem; + +  /* Exchange the shorter segment with the far end of the longer segment. +     That puts the shorter segment into the right place. +     It leaves the longer segment in the right place overall, +     but it consists of two parts that need to be swapped next.  */ + +  while (top > middle && middle > bottom) +    { +      if (top - middle > middle - bottom) +	{ +	  /* Bottom segment is the short one.  */ +	  int len = middle - bottom; +	  register int i; + +	  /* Swap it with the top part of the top segment.  */ +	  for (i = 0; i < len; i++) +	    { +	      tem = argv[bottom + i]; +	      argv[bottom + i] = argv[top - (middle - bottom) + i]; +	      argv[top - (middle - bottom) + i] = tem; +	    } +	  /* Exclude the moved bottom segment from further swapping.  */ +	  top -= len; +	} +      else +	{ +	  /* Top segment is the short one.  */ +	  int len = top - middle; +	  register int i; + +	  /* Swap it with the bottom part of the bottom segment.  */ +	  for (i = 0; i < len; i++) +	    { +	      tem = argv[bottom + i]; +	      argv[bottom + i] = argv[middle + i]; +	      argv[middle + i] = tem; +	    } +	  /* Exclude the moved top segment from further swapping.  */ +	  bottom += len; +	} +    } + +  /* Update records for the slots the non-options now occupy.  */ + +  first_nonopt += (optind - last_nonopt); +  last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made.  */ + +static const char * +_getopt_initialize (optstring) +     const char *optstring; +{ +  /* Start processing options with ARGV-element 1 (since ARGV-element 0 +     is the program name); the sequence of previously skipped +     non-option ARGV-elements is empty.  */ + +  first_nonopt = last_nonopt = optind = 1; + +  nextchar = NULL; + +  /* Determine how to handle the ordering of options and nonoptions.  */ + +  if (optstring[0] == '-') +    { +      ordering = RETURN_IN_ORDER; +      ++optstring; +    } +  else if (optstring[0] == '+') +    { +      ordering = REQUIRE_ORDER; +      ++optstring; +    } +  else if (getenv ("POSIXLY_CORRECT") != NULL) +    ordering = REQUIRE_ORDER; +  else +    ordering = PERMUTE; + +  return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters +   given in OPTSTRING. + +   If an element of ARGV starts with '-', and is not exactly "-" or "--", +   then it is an option element.  The characters of this element +   (aside from the initial '-') are option characters.  If `getopt' +   is called repeatedly, it returns successively each of the option characters +   from each of the option elements. + +   If `getopt' finds another option character, it returns that character, +   updating `optind' and `nextchar' so that the next call to `getopt' can +   resume the scan with the following option character or ARGV-element. + +   If there are no more option characters, `getopt' returns `EOF'. +   Then `optind' is the index in ARGV of the first ARGV-element +   that is not an option.  (The ARGV-elements have been permuted +   so that those that are not options now come last.) + +   OPTSTRING is a string containing the legitimate option characters. +   If an option character is seen that is not listed in OPTSTRING, +   return '?' after printing an error message.  If you set `opterr' to +   zero, the error message is suppressed but we still return '?'. + +   If a char in OPTSTRING is followed by a colon, that means it wants an arg, +   so the following text in the same ARGV-element, or the text of the following +   ARGV-element, is returned in `optarg'.  Two colons mean an option that +   wants an optional arg; if there is text in the current ARGV-element, +   it is returned in `optarg', otherwise `optarg' is set to zero. + +   If OPTSTRING starts with `-' or `+', it requests different methods of +   handling the non-option ARGV-elements. +   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + +   Long-named options begin with `--' instead of `-'. +   Their names may be abbreviated as long as the abbreviation is unique +   or is an exact match for some defined option.  If they have an +   argument, it follows the option name in the same ARGV-element, separated +   from the option name by a `=', or else the in next ARGV-element. +   When `getopt' finds a long-named option, it returns 0 if that option's +   `flag' field is nonzero, the value of the option's `val' field +   if the `flag' field is zero. + +   The elements of ARGV aren't really const, because we permute them. +   But we pretend they're const in the prototype to be compatible +   with other systems. + +   LONGOPTS is a vector of `struct option' terminated by an +   element containing a name which is zero. + +   LONGIND returns the index in LONGOPT of the long-named option found. +   It is only valid when a long-named option has been found by the most +   recent call. + +   If LONG_ONLY is nonzero, '-' as well as '--' can introduce +   long-named options.  */ + +#if NLS +#include "nl_types.h" +#endif + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) +     int argc; +     char *const *argv; +     const char *optstring; +     const struct option *longopts; +     int *longind; +     int long_only; +{ +  optarg = NULL; + +#if NLS +  libc_nls_init(); +#endif + +  if (optind == 0) +    optstring = _getopt_initialize (optstring); + +  if (nextchar == NULL || *nextchar == '\0') +    { +      /* Advance to the next ARGV-element.  */ + +      if (ordering == PERMUTE) +	{ +	  /* If we have just processed some options following some non-options, +	     exchange them so that the options come first.  */ + +	  if (first_nonopt != last_nonopt && last_nonopt != optind) +	    exchange ((char **) argv); +	  else if (last_nonopt != optind) +	    first_nonopt = optind; + +	  /* Skip any additional non-options +	     and extend the range of non-options previously skipped.  */ + +	  while (optind < argc +		 && (argv[optind][0] != '-' || argv[optind][1] == '\0')) +	    optind++; +	  last_nonopt = optind; +	} + +      /* The special ARGV-element `--' means premature end of options. +	 Skip it like a null option, +	 then exchange with previous non-options as if it were an option, +	 then skip everything else like a non-option.  */ + +      if (optind != argc && !strcmp (argv[optind], "--")) +	{ +	  optind++; + +	  if (first_nonopt != last_nonopt && last_nonopt != optind) +	    exchange ((char **) argv); +	  else if (first_nonopt == last_nonopt) +	    first_nonopt = optind; +	  last_nonopt = argc; + +	  optind = argc; +	} + +      /* If we have done all the ARGV-elements, stop the scan +	 and back over any non-options that we skipped and permuted.  */ + +      if (optind == argc) +	{ +	  /* Set the next-arg-index to point at the non-options +	     that we previously skipped, so the caller will digest them.  */ +	  if (first_nonopt != last_nonopt) +	    optind = first_nonopt; +	  return EOF; +	} + +      /* If we have come to a non-option and did not permute it, +	 either stop the scan or describe it to the caller and pass it by.  */ + +      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) +	{ +	  if (ordering == REQUIRE_ORDER) +	    return EOF; +	  optarg = argv[optind++]; +	  return 1; +	} + +      /* We have found another option-ARGV-element. +	 Skip the initial punctuation.  */ + +      nextchar = (argv[optind] + 1 +		  + (longopts != NULL && argv[optind][1] == '-')); +    } + +  /* Decode the current option-ARGV-element.  */ + +  /* Check whether the ARGV-element is a long option. + +     If long_only and the ARGV-element has the form "-f", where f is +     a valid short option, don't consider it an abbreviated form of +     a long option that starts with f.  Otherwise there would be no +     way to give the -f short option. + +     On the other hand, if there's a long option "fubar" and +     the ARGV-element is "-fu", do consider that an abbreviation of +     the long option, just like "--fu", and not "-f" with arg "u". + +     This distinction seems to be the most useful approach.  */ + +  if (longopts != NULL +      && (argv[optind][1] == '-' +	  || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) +    { +      char *nameend; +      const struct option *p; +      const struct option *pfound = NULL; +      int exact = 0; +      int ambig = 0; +      int indfound; +      int option_index; + +      for (nameend = nextchar; *nameend && *nameend != '='; nameend++) +	/* Do nothing.  */ ; + +      /* Test all long options for either exact match +	 or abbreviated matches.  */ +      for (p = longopts, option_index = 0; p->name; p++, option_index++) +	if (!strncmp (p->name, nextchar, nameend - nextchar)) +	  { +	    if (nameend - nextchar == strlen (p->name)) +	      { +		/* Exact match found.  */ +		pfound = p; +		indfound = option_index; +		exact = 1; +		break; +	      } +	    else if (pfound == NULL) +	      { +		/* First nonexact match found.  */ +		pfound = p; +		indfound = option_index; +	      } +	    else +	      /* Second or later nonexact match found.  */ +	      ambig = 1; +	  } + +      if (ambig && !exact) +	{ +	  if (opterr) +#if NLS +	    fprintf (stderr, +		     catgets(_libc_cat, GetoptSet, GetoptAmbiguous, +			     "%s: option `%s' is ambiguous\n"), +		     argv[0], argv[optind]); +#else +	    fprintf (stderr, "%s: option `%s' is ambiguous\n", +		     argv[0], argv[optind]); +#endif +	  nextchar += strlen (nextchar); +	  optind++; +	  return '?'; +	} + +      if (pfound != NULL) +	{ +	  option_index = indfound; +	  optind++; +	  if (*nameend) +	    { +	      /* Don't test has_arg with >, because some C compilers don't +		 allow it to be used on enums.  */ +	      if (pfound->has_arg) +		optarg = nameend + 1; +	      else +		{ +		  if (opterr) +		    { +		      if (argv[optind - 1][1] == '-') +			/* --option */ +#if NLS +			fprintf (stderr, +				 catgets(_libc_cat, GetoptSet, GetoptNoArgumentsAllowed1, +				 "%s: option `--%s' doesn't allow an argument\n"), +				 argv[0], pfound->name); +#else +			fprintf (stderr, +				 "%s: option `--%s' doesn't allow an argument\n", +				 argv[0], pfound->name); +#endif +		      else +			/* +option or -option */ +#if NLS +			fprintf (stderr, +			     catgets(_libc_cat, GetoptSet, GetoptNoArgumentsAllowed2, +			     "%s: option `%c%s' doesn't allow an argument\n"), +			     argv[0], argv[optind - 1][0], pfound->name); +#else +			fprintf (stderr, +			     "%s: option `%c%s' doesn't allow an argument\n", +			     argv[0], argv[optind - 1][0], pfound->name); +#endif +		    } +		  nextchar += strlen (nextchar); +		  return '?'; +		} +	    } +	  else if (pfound->has_arg == 1) +	    { +	      if (optind < argc) +		optarg = argv[optind++]; +	      else +		{ +		  if (opterr) +#if NLS +		    fprintf (stderr, +			     catgets(_libc_cat, GetoptSet, GetoptRequiresArgument1, +		             "%s: option `%s' requires an argument\n"), +			     argv[0], argv[optind - 1]); +#else +		    fprintf (stderr, "%s: option `%s' requires an argument\n", +			     argv[0], argv[optind - 1]); +#endif +		  nextchar += strlen (nextchar); +		  return optstring[0] == ':' ? ':' : '?'; +		} +	    } +	  nextchar += strlen (nextchar); +	  if (longind != NULL) +	    *longind = option_index; +	  if (pfound->flag) +	    { +	      *(pfound->flag) = pfound->val; +	      return 0; +	    } +	  return pfound->val; +	} + +      /* Can't find it as a long option.  If this is not getopt_long_only, +	 or the option starts with '--' or is not a valid short +	 option, then it's an error. +	 Otherwise interpret it as a short option.  */ +      if (!long_only || argv[optind][1] == '-' +	  || my_index (optstring, *nextchar) == NULL) +	{ +	  if (opterr) +	    { +	      if (argv[optind][1] == '-') +		/* --option */ +#if NLS +		fprintf (stderr, +			 catgets(_libc_cat, GetoptSet, GetoptUnrecognized1, +			 "%s: unrecognized option `--%s'\n"), +			 argv[0], nextchar); +#else +		fprintf (stderr, "%s: unrecognized option `--%s'\n", +			 argv[0], nextchar); +#endif +	      else +		/* +option or -option */ +#if NLS +		fprintf (stderr, +			 catgets(_libc_cat, GetoptSet, GetoptUnrecognized2, +			 "%s: unrecognized option `%c%s'\n"), +			 argv[0], argv[optind][0], nextchar); +#else +		fprintf (stderr, "%s: unrecognized option `%c%s'\n", +			 argv[0], argv[optind][0], nextchar); +#endif +	    } +	  nextchar = (char *) ""; +	  optind++; +	  return '?'; +	} +    } + +  /* Look at and handle the next short option-character.  */ + +  { +    char c = *nextchar++; +    char *temp = my_index (optstring, c); + +    /* Increment `optind' when we start to process its last character.  */ +    if (*nextchar == '\0') +      ++optind; + +    if (temp == NULL || c == ':') +      { +	if (opterr) +	  { +	    /* 1003.2 specifies the format of this message.  */ +#if NLS +	    fprintf (stderr, +		catgets(_libc_cat, GetoptSet, GetoptIllegal, +		"%s: illegal option -- %c\n"), +		argv[0], c); +#else +	    fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); +#endif +	  } +	optopt = c; +	return '?'; +      } +    if (temp[1] == ':') +      { +	if (temp[2] == ':') +	  { +	    /* This is an option that accepts an argument optionally.  */ +	    if (*nextchar != '\0') +	      { +		optarg = nextchar; +		optind++; +	      } +	    else +	      optarg = NULL; +	    nextchar = NULL; +	  } +	else +	  { +	    /* This is an option that requires an argument.  */ +	    if (*nextchar != '\0') +	      { +		optarg = nextchar; +		/* If we end this ARGV-element by taking the rest as an arg, +		   we must advance to the next element now.  */ +		optind++; +	      } +	    else if (optind == argc) +	      { +		if (opterr) +		  { +		    /* 1003.2 specifies the format of this message.  */ +#if NLS +		    fprintf (stderr, +			catgets(_libc_cat, GetoptSet, +			GetoptRequiresArgument2, +			"%s: option requires an argument -- %c\n"), +			argv[0], c); +#else +		    fprintf (stderr, "%s: option requires an argument -- %c\n", +			     argv[0], c); +#endif +		  } +		optopt = c; +		if (optstring[0] == ':') +		  c = ':'; +		else +		  c = '?'; +	      } +	    else +	      /* We already incremented `optind' once; +		 increment it again when taking next ARGV-elt as argument.  */ +	      optarg = argv[optind++]; +	    nextchar = NULL; +	  } +      } +    return c; +  } +} + +int +getopt (argc, argv, optstring) +     int argc; +     char *const *argv; +     const char *optstring; +{ +  return _getopt_internal (argc, argv, optstring, +			   (const struct option *) 0, +			   (int *) 0, +			   0); +} + +#endif /* L__gnu_getopt_internal */ + +#ifdef L_gnu_getopt_long + +int +getopt_long (argc, argv, options, long_options, opt_index) +     int argc; +     char *const *argv; +     const char *options; +     const struct option *long_options; +     int *opt_index; +{ +  return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +#endif /*  L_gnu_getopt_long */ + +#ifdef L_gnu_getopt_long_only + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. +   If an option that starts with '-' (not '--') doesn't match a long option, +   but does match a short option, it is parsed as a short option +   instead.  */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) +     int argc; +     char *const *argv; +     const char *options; +     const struct option *long_options; +     int *opt_index; +{ +  return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + +#endif /* L_gnu_getopt_long_only */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing +   the above definition of `getopt'.  */ + +int +main (argc, argv) +     int argc; +     char **argv; +{ +  int c; +  int digit_optind = 0; + +  while (1) +    { +      int this_option_optind = optind ? optind : 1; + +      c = getopt (argc, argv, "abc:d:0123456789"); +      if (c == EOF) +	break; + +      switch (c) +	{ +	case '0': +	case '1': +	case '2': +	case '3': +	case '4': +	case '5': +	case '6': +	case '7': +	case '8': +	case '9': +	  if (digit_optind != 0 && digit_optind != this_option_optind) +	    printf ("digits occur in two different argv-elements.\n"); +	  digit_optind = this_option_optind; +	  printf ("option %c\n", c); +	  break; + +	case 'a': +	  printf ("option a\n"); +	  break; + +	case 'b': +	  printf ("option b\n"); +	  break; + +	case 'c': +	  printf ("option c with value `%s'\n", optarg); +	  break; + +	case '?': +	  break; + +	default: +	  printf ("?? getopt returned character code 0%o ??\n", c); +	} +    } + +  if (optind < argc) +    { +      printf ("non-option ARGV-elements: "); +      while (optind < argc) +	printf ("%s ", argv[optind++]); +      printf ("\n"); +    } +  exit (0); +} + +#endif /* TEST */ + +  /* getopt_long testing */ +#ifdef TEST_LONG + +/* Compile with -DTEST_LONG to make an executable for use in testing +   the above definition of `getopt'.  */ + +int +main (argc, argv) +     int argc; +     char **argv; +{ +  int c; +  int digit_optind = 0; + +  while (1) +    { +      int this_option_optind = optind ? optind : 1; +      int option_index = 0; +      static struct option long_options[] = +      { +	{"add", 1, 0, 0}, +	{"append", 0, 0, 0}, +	{"delete", 1, 0, 0}, +	{"verbose", 0, 0, 0}, +	{"create", 0, 0, 0}, +	{"file", 1, 0, 0}, +	{0, 0, 0, 0} +      }; + +      c = getopt_long (argc, argv, "abc:d:0123456789", +		       long_options, &option_index); +      if (c == EOF) +	break; + +      switch (c) +	{ +	case 0: +	  printf ("option %s", long_options[option_index].name); +	  if (optarg) +	    printf (" with arg %s", optarg); +	  printf ("\n"); +	  break; + +	case '0': +	case '1': +	case '2': +	case '3': +	case '4': +	case '5': +	case '6': +	case '7': +	case '8': +	case '9': +	  if (digit_optind != 0 && digit_optind != this_option_optind) +	    printf ("digits occur in two different argv-elements.\n"); +	  digit_optind = this_option_optind; +	  printf ("option %c\n", c); +	  break; + +	case 'a': +	  printf ("option a\n"); +	  break; + +	case 'b': +	  printf ("option b\n"); +	  break; + +	case 'c': +	  printf ("option c with value `%s'\n", optarg); +	  break; + +	case 'd': +	  printf ("option d with value `%s'\n", optarg); +	  break; + +	case '?': +	  break; + +	default: +	  printf ("?? getopt returned character code 0%o ??\n", c); +	} +    } + +  if (optind < argc) +    { +      printf ("non-option ARGV-elements: "); +      while (optind < argc) +	printf ("%s ", argv[optind++]); +      printf ("\n"); +    } + +  exit (0); +} + +#endif /* TEST_LONG */  | 
