summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
Diffstat (limited to 'libc')
-rw-r--r--libc/inet/Makefile4
-rw-r--r--libc/inet/resolv.c4
-rw-r--r--libc/inet/rpc/Makefile4
-rw-r--r--libc/misc/Makefile2
-rw-r--r--libc/misc/assert/Makefile4
-rw-r--r--libc/misc/fnmatch/Makefile4
-rw-r--r--libc/misc/glob/Makefile4
-rw-r--r--libc/misc/internals/Makefile4
-rw-r--r--libc/misc/lock/Makefile4
-rw-r--r--libc/misc/lsearch/Makefile4
-rw-r--r--libc/misc/mntent/Makefile4
-rw-r--r--libc/misc/regex/Makefile4
-rw-r--r--libc/misc/syslog/Makefile4
-rw-r--r--libc/misc/time/Makefile4
-rw-r--r--libc/pwd_grp/Makefile4
-rw-r--r--libc/signal/Makefile4
-rw-r--r--libc/stdio/Makefile9
-rw-r--r--libc/stdio/printf.c66
-rw-r--r--libc/stdio/stdio.c195
-rw-r--r--libc/stdlib/Makefile6
-rw-r--r--libc/stdlib/atexit.c82
-rw-r--r--libc/stdlib/malloc-930716/Makefile51
-rw-r--r--libc/stdlib/malloc-930716/README40
-rw-r--r--libc/stdlib/malloc-930716/calloc.c25
-rw-r--r--libc/stdlib/malloc-930716/free.c156
-rw-r--r--libc/stdlib/malloc-930716/malloc.c254
-rw-r--r--libc/stdlib/malloc-930716/malloc.h107
-rw-r--r--libc/stdlib/malloc-930716/memalign.c61
-rw-r--r--libc/stdlib/malloc-930716/morecore.c28
-rw-r--r--libc/stdlib/malloc-930716/realloc.c131
-rw-r--r--libc/stdlib/malloc-930716/valloc.c62
-rw-r--r--libc/stdlib/malloc-simple/Makefile4
-rw-r--r--libc/stdlib/malloc/Makefile4
-rw-r--r--libc/stdlib/qsort.c220
-rw-r--r--libc/stdlib/system.c2
-rw-r--r--libc/string/Makefile4
-rw-r--r--libc/string/strerror.c43
-rw-r--r--libc/string/strsignal.c73
-rw-r--r--libc/sysdeps/linux/arm/Makefile8
-rw-r--r--libc/sysdeps/linux/common/Makefile26
-rwxr-xr-xlibc/sysdeps/linux/common/str_syscalls.sh35
-rw-r--r--libc/sysdeps/linux/common/syscalls.c32
-rw-r--r--libc/sysdeps/linux/common/unified_syscall_i386.h41
-rw-r--r--libc/sysdeps/linux/i386/Makefile13
-rw-r--r--libc/sysdeps/linux/i386/__init_brk.c33
-rw-r--r--libc/sysdeps/linux/i386/__uClibc_syscall.S39
-rw-r--r--libc/sysdeps/linux/i386/brk.c32
-rw-r--r--libc/sysdeps/linux/i386/sbrk.c35
-rw-r--r--libc/termios/Makefile4
-rw-r--r--libc/unistd/Makefile15
-rw-r--r--libc/unistd/getopt.c16
-rw-r--r--libc/unistd/getpass.c3
-rw-r--r--libc/unistd/gnu_getopt.c873
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 */