diff options
62 files changed, 2763 insertions, 495 deletions
@@ -28,7 +28,7 @@ include Rules.mak -DIRS = misc pwd_grp stdio string termios unistd net signal stdlib sysdeps +DIRS = misc pwd_grp stdio string termios unistd net signal stdlib sysdeps extra all: libc.a @@ -58,7 +58,7 @@ headers: dummy tags: ctags -R - + clean: subdirs_clean rm -f libc.a rm -f include/asm include/net include/linux include/bits @@ -41,7 +41,7 @@ ifeq ($(DODEBUG),true) LDFLAGS = -nostdlib -Wl,-warn-common STRIPTOOL = /bin/true -Since_we_are_debugging else - CFLAGS += $(WARNINGS) #-fomit-frame-pointer + CFLAGS += -DNDEBUG $(WARNINGS) #-fomit-frame-pointer LDFLAGS = -s -nostdlib -Wl,-warn-common endif diff --git a/extra/Makefile b/extra/Makefile new file mode 100644 index 000000000..fa4b50b44 --- /dev/null +++ b/extra/Makefile @@ -0,0 +1,48 @@ +# 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 + + +DIRS = gcc-uClibc + +all: subdirs + +tags: + ctags -R + +clean: subdirs_clean + rm -f *.[oa] *~ core + +subdirs: $(patsubst %, _dir_%, $(DIRS)) +subdirs_clean: $(patsubst %, _dirclean_%, $(DIRS)) + +$(patsubst %, _dir_%, $(DIRS)) : dummy + $(MAKE) -C $(patsubst _dir_%, %, $@) + +$(patsubst %, _dirclean_%, $(DIRS)) : dummy + $(MAKE) -C $(patsubst _dirclean_%, %, $@) clean + +.PHONY: dummy + diff --git a/extra/gcc-uClibc/Makefile b/extra/gcc-uClibc/Makefile new file mode 100644 index 000000000..af9f836a1 --- /dev/null +++ b/extra/gcc-uClibc/Makefile @@ -0,0 +1,40 @@ + +TOPDIR = ../../ +include $(TOPDIR)Rules.mak + +UCLIBC_DIR = $(shell (cd ../.. ; /bin/pwd)) +GCC_BIN = $(CC) +GCC_LIB = $(shell $(CC) -print-libgcc-file-name ) +#GCCINCDIR inherited from Rules.mak + +NATIVE_ARCH = $(shell uname -m | sed -e 's/i.86/i386/' -e 's/sparc.*/sparc/' -e 's/arm.*/arm/g') +GCC_UCLIBC = gcc-uClibc-cross +ifeq ($(TARGET_ARCH), $(NATIVE_ARCH)) + GCC_UCLIBC = gcc-uClibc-native +endif + +all: $(GCC_UCLIBC) + +clean: + rm -f gcc-uClibc.h gcc-uClibc-* + +gcc-uClibc.h: clean + echo "/* this file is created by make */" > gcc-uClibc.h + echo "#define UCLIBC_DIR " \"$(UCLIBC_DIR)/\" >> gcc-uClibc.h + echo "#define GCC_BIN " \"$(GCC_BIN)\" >> gcc-uClibc.h + echo "#define GCC_LIB " \"$(GCC_LIB)\" >> gcc-uClibc.h + echo "#define GCC_INCDIR " \"-I$(GCCINCDIR)/\" >> gcc-uClibc.h + echo "#define TARGET_ARCH " \"$(TARGET_ARCH)\" >> gcc-uClibc.h + +gcc-uClibc-native: gcc-uClibc.h gcc-uClibc.c + # uClibc built for native environment, so why not use it ;-) + $(CC) $(CFLAGS) -nostdinc -I$(UCLIBC_DIR)/include -I$(GCC_INC) \ + -Wl,-static gcc-uClibc.c \ + $(UCLIBC_DIR)/sysdeps/linux/$(TARGET_ARCH)/_start.o \ + -nostdlib $(GCC_LIB) $(UCLIBC_DIR)/libc.a \ + -s -o gcc-uClibc-$(TARGET_ARCH) #-DDEBUG + +gcc-uClibc-cross: gcc-uClibc.h gcc-uClibc.c + # don't use CFLAGS since may not be appropriate + gcc -s gcc-uClibc.c -o gcc-uClibc-$(TARGET_ARCH) + diff --git a/extra/gcc-uClibc/gcc-uClibc.c b/extra/gcc-uClibc/gcc-uClibc.c new file mode 100644 index 000000000..f783cd7bd --- /dev/null +++ b/extra/gcc-uClibc/gcc-uClibc.c @@ -0,0 +1,129 @@ + +/* + * Copyright (C) 2000 Manuel Novoa III + * + * This is a crude wrapper to use uClibc with gcc. + * It was originally written to work around ./configure for ext2fs-utils. + * It certainly can be improved, but it works for me in the normal cases. + * + * TODO: + * Check/modify gcc-specific environment variables? + */ + +#ifdef DEBUG +#include <stdio.h> +#endif + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "gcc-uClibc.h" + +#define UCLIBC_START UCLIBC_DIR"sysdeps/linux/"TARGET_ARCH"/_start.o" +#define UCLIBC_START_G UCLIBC_START +#define UCLIBC_LIB UCLIBC_DIR"libc.a" +#if 1 +#define UCLIBC_LIB_G UCLIBC_LIB +#else +#define UCLIBC_LIB_G UCLIBC_DIR"libc.a-debug" +#endif +#define UCLIBC_INC "-I"UCLIBC_DIR"include/" + +static char nostdinc[] = "-nostdinc"; +static char nostartfiles[] = "-nostartfiles"; +static char nodefaultlibs[] = "-nodefaultlibs"; +static char nostdlib[] = "-nostdlib"; + +int main(int argc, char **argv) +{ + int debugging = 0, linking = 1; + int use_stdinc = 1, use_start = 1, use_stdlib = 1; + int i, j; + int source_count; + char ** gcc_argv; + + source_count = 0; + + for ( i = 1 ; i < argc ; i++ ) { + if (argv[i][0] == '-') { /* option */ + switch (argv[i][1]) { + case 'c': + case 'S': + case 'E': + case 'r': + if (argv[i][2] == 0) linking = 0; + break; + case 'g': + if (argv[i][2] == 0) debugging = 1; + break; + case 'n': + if (strcmp(nostdinc,argv[i]) == 0) { + use_stdinc = 0; + } else if (strcmp(nostartfiles,argv[i]) == 0) { + use_start = 0; + } else if (strcmp(nodefaultlibs,argv[i]) == 0) { + use_stdlib = 0; + } else if (strcmp(nostdlib,argv[i]) == 0) { + use_start = 0; + use_stdlib = 0; + } + + } + } else { /* assume it is an existing source file */ + ++source_count; + } + } + +#if 1 + gcc_argv = __builtin_alloca(sizeof(char*) * (argc + 20)); +#else + if (!(gcc_argv = malloc(sizeof(char) * (argc + 20)))) { + return EXIT_FAILURE; + } +#endif + + i = 0; + gcc_argv[i++] = GCC_BIN; + for ( j = 1 ; j < argc ; j++ ) { + gcc_argv[i++] = argv[j]; + } + if (use_stdinc) { + gcc_argv[i++] = nostdinc; + gcc_argv[i++] = UCLIBC_INC; + gcc_argv[i++] = GCC_INCDIR; + } + if (linking && source_count) { + gcc_argv[i++] = "-static"; + if (use_start) { + if (debugging) { + gcc_argv[i++] = UCLIBC_START_G; + } else { + gcc_argv[i++] = UCLIBC_START; + } + } + if (use_stdlib) { + gcc_argv[i++] = "-nostdlib"; + if (debugging) { + gcc_argv[i++] = UCLIBC_LIB_G; + } else { + gcc_argv[i++] = UCLIBC_LIB; + } + gcc_argv[i++] = GCC_LIB; + } + } + gcc_argv[i++] = NULL; + +#ifdef DEBUG + for ( j = 0 ; gcc_argv[j] ; j++ ) { + printf("arg[%2i] = %s\n", j, gcc_argv[j]); + } + return EXIT_SUCCESS; +#else + return execvp(GCC_BIN, gcc_argv); +#endif +} + + + + diff --git a/include/getopt.h b/include/getopt.h index a4cb95496..725d9cbd4 100644 --- a/include/getopt.h +++ b/include/getopt.h @@ -1,18 +1,109 @@ -/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> - * This file is part of the Linux-8086 C library and is distributed - * under the GNU Library General Public License. - */ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. -#ifndef __GETOPT_H -#define __GETOPT_H +This file is part of the GNU C Library. + +The GNU C 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. + +The GNU C 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 the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 #include <features.h> +#ifdef __cplusplus +extern "C" { +#endif + +/* 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. */ + extern char *optarg; + +/* 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. */ + extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + extern int opterr; + +/* Set to an option character which was unrecognized. */ + extern int optopt; +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ + const char *name; + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + extern int getopt __P((int argc, char *const *argv, const char *shortopts)); +extern int getopt_long __P((int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind)); +extern int getopt_long_only __P((int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind)); + +#ifdef __cplusplus +} +#endif -#endif /* __GETOPT_H */ +#endif /* _GETOPT_H */ diff --git a/include/stdio.h b/include/stdio.h index a7a468788..01f6667ef 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -105,16 +105,12 @@ typedef struct __stdio_file FILE; #include <bits/stdio_lim.h> #undef __need_FOPEN_MAX - -/* Standard streams. */ -extern FILE stdin[1]; /* Standard input stream. */ -extern FILE stdout[1]; /* Standard output stream. */ -extern FILE stderr[1]; /* Standard error output stream. */ +/* Standard streams (internal). */ +extern FILE _stdio_streams[3]; /* C89/C99 say they're macros. Make them happy. */ -#define stdin stdin -#define stdout stdout -#define stderr stderr - +#define stdin (_stdio_streams) +#define stdout (_stdio_streams+1) +#define stderr (_stdio_streams+2) /* Remove file FILENAME. */ extern int remove __P ((__const char *__filename)); diff --git a/include/sys/param.h b/include/sys/param.h index 511c2ae1e..c59222cd4 100644 --- a/include/sys/param.h +++ b/include/sys/param.h @@ -9,7 +9,7 @@ #include <features.h> #include <limits.h> #include <linux/limits.h> -#include <linux/param.h> +#include <asm/param.h> #include <sys/types.h> 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 */ diff --git a/test/string/Makefile b/test/string/Makefile index 7bcd6dc76..3277334ab 100644 --- a/test/string/Makefile +++ b/test/string/Makefile @@ -22,6 +22,7 @@ YLDFLAGS = -s --static TARGETS=string string_glibc TARGETS+=testcopy testcopy_glibc +TARGETS+=strerror strsignal all: $(TARGETS) @@ -78,6 +79,29 @@ testcopy_diff: testcopy testcopy_glibc -@ echo " " +strerror: ../../string/strerror.c + -@ echo "-------" + -@ echo " " + -@ echo "Compiling vs uClibc: " + -@ echo " " + $(CC) $(XCFLAGS) -DCHECK_BUF -c $< -o $@.o + $(CC) $(XLDFLAGS) $@.o -o $@ $(EXTRA_LIBS) + $(STRIPTOOL) -x -R .note -R .comment $@ + -./$@ + -@ echo " " + +strsignal: ../../string/strsignal.c + -@ echo "-------" + -@ echo " " + -@ echo "Compiling vs uClibc: " + -@ echo " " + $(CC) $(XCFLAGS) -DCHECK_BUF -c $< -o $@.o + $(CC) $(XLDFLAGS) $@.o -o $@ $(EXTRA_LIBS) + $(STRIPTOOL) -x -R .note -R .comment $@ + -./$@ + -@ echo " " + + clean: rm -f *.[oa] *~ core $(TARGETS) testcopy.gnu.out testcopy.out |