URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/newlib-1.10.0/newlib/libc/stdlib
- from Rev 1010 to Rev 1765
- ↔ Reverse comparison
Rev 1010 → Rev 1765
/Makefile.in
0,0 → 1,580
# Makefile.in generated automatically by automake 1.4 from Makefile.am |
|
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. |
# This Makefile.in is free software; the Free Software Foundation |
# gives unlimited permission to copy and/or distribute it, |
# with or without modifications, as long as this notice is preserved. |
|
# This program is distributed in the hope that it will be useful, |
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without |
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
# PARTICULAR PURPOSE. |
|
|
|
SHELL = @SHELL@ |
|
srcdir = @srcdir@ |
top_srcdir = @top_srcdir@ |
VPATH = @srcdir@ |
prefix = @prefix@ |
exec_prefix = @exec_prefix@ |
|
bindir = @bindir@ |
sbindir = @sbindir@ |
libexecdir = @libexecdir@ |
datadir = @datadir@ |
sysconfdir = @sysconfdir@ |
sharedstatedir = @sharedstatedir@ |
localstatedir = @localstatedir@ |
libdir = @libdir@ |
infodir = @infodir@ |
mandir = @mandir@ |
includedir = @includedir@ |
oldincludedir = /usr/include |
|
DESTDIR = |
|
pkgdatadir = $(datadir)/@PACKAGE@ |
pkglibdir = $(libdir)/@PACKAGE@ |
pkgincludedir = $(includedir)/@PACKAGE@ |
|
top_builddir = .. |
|
ACLOCAL = @ACLOCAL@ |
AUTOCONF = @AUTOCONF@ |
AUTOMAKE = @AUTOMAKE@ |
AUTOHEADER = @AUTOHEADER@ |
|
INSTALL = @INSTALL@ |
INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) |
INSTALL_DATA = @INSTALL_DATA@ |
INSTALL_SCRIPT = @INSTALL_SCRIPT@ |
transform = @program_transform_name@ |
|
NORMAL_INSTALL = : |
PRE_INSTALL = : |
POST_INSTALL = : |
NORMAL_UNINSTALL = : |
PRE_UNINSTALL = : |
POST_UNINSTALL = : |
host_alias = @host_alias@ |
host_triplet = @host@ |
AR = @AR@ |
AS = @AS@ |
CC = @CC@ |
CPP = @CPP@ |
CRT0 = @CRT0@ |
DLLTOOL = @DLLTOOL@ |
EXEEXT = @EXEEXT@ |
LDFLAGS = @LDFLAGS@ |
LIBC_MACHINE_LIB = @LIBC_MACHINE_LIB@ |
LIBC_POSIX_LIB = @LIBC_POSIX_LIB@ |
LIBC_SIGNAL_DEF = @LIBC_SIGNAL_DEF@ |
LIBC_SIGNAL_LIB = @LIBC_SIGNAL_LIB@ |
LIBC_SYSCALL_LIB = @LIBC_SYSCALL_LIB@ |
LIBC_SYS_LIB = @LIBC_SYS_LIB@ |
LIBC_UNIX_LIB = @LIBC_UNIX_LIB@ |
LIBTOOL = @LIBTOOL@ |
LN_S = @LN_S@ |
MAINT = @MAINT@ |
MAKEINFO = @MAKEINFO@ |
NEWLIB_CFLAGS = @NEWLIB_CFLAGS@ |
OBJDUMP = @OBJDUMP@ |
PACKAGE = @PACKAGE@ |
RANLIB = @RANLIB@ |
VERSION = @VERSION@ |
aext = @aext@ |
libm_machine_dir = @libm_machine_dir@ |
machine_dir = @machine_dir@ |
newlib_basedir = @newlib_basedir@ |
oext = @oext@ |
sys_dir = @sys_dir@ |
|
AUTOMAKE_OPTIONS = cygnus |
|
INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) |
|
LIB_SOURCES = \ |
__adjust.c \ |
__exp10.c \ |
__ten_mu.c \ |
abort.c \ |
abs.c \ |
assert.c \ |
atexit.c \ |
atof.c \ |
atoff.c \ |
atoi.c \ |
atol.c \ |
bsearch.c \ |
calloc.c \ |
div.c \ |
drand48.c \ |
dtoa.c \ |
dtoastub.c \ |
ecvtbuf.c \ |
efgcvt.c \ |
environ.c \ |
envlock.c \ |
eprintf.c \ |
erand48.c \ |
exit.c \ |
getenv.c \ |
getenv_r.c \ |
getopt.c \ |
jrand48.c \ |
labs.c \ |
lcong48.c \ |
ldiv.c \ |
ldtoa.c \ |
lrand48.c \ |
malign.c \ |
malloc.c \ |
mblen.c \ |
mblen_r.c \ |
mbstowcs.c \ |
mbstowcs_r.c \ |
mbtowc.c \ |
mbtowc_r.c \ |
mlock.c \ |
mprec.c \ |
mrand48.c \ |
msize.c \ |
mstats.c \ |
mtrim.c \ |
nrand48.c \ |
putenv.c \ |
putenv_r.c \ |
qsort.c \ |
rand.c \ |
rand48.c \ |
rand_r.c \ |
realloc.c \ |
seed48.c \ |
setenv.c \ |
setenv_r.c \ |
srand48.c \ |
strdup.c \ |
strdup_r.c \ |
strtod.c \ |
strtol.c \ |
strtoll.c \ |
strtoll_r.c \ |
strtoul.c \ |
strtoull.c \ |
strtoull_r.c \ |
system.c \ |
valloc.c \ |
wcstombs.c \ |
wcstombs_r.c \ |
wctomb.c \ |
wctomb_r.c |
|
|
# Because of how libtool moves objects around, mallocr must be built last. |
LIBADD_OBJS = freer.$(oext) reallocr.$(oext) callocr.$(oext) cfreer.$(oext) malignr.$(oext) \ |
vallocr.$(oext) pvallocr.$(oext) mallinfor.$(oext) mallstatsr.$(oext) msizer.$(oext) malloptr.$(oext) mallocr.$(oext) |
|
|
libstdlib_la_LDFLAGS = -Xcompiler -nostdlib |
|
@USE_LIBTOOL_TRUE@noinst_LTLIBRARIES = @USE_LIBTOOL_TRUE@libstdlib.la |
@USE_LIBTOOL_TRUE@libstdlib_la_SOURCES = @USE_LIBTOOL_TRUE@$(LIB_SOURCES) |
@USE_LIBTOOL_TRUE@libstdlib_la_LIBADD = @USE_LIBTOOL_TRUE@$(LIBADD_OBJS) |
@USE_LIBTOOL_TRUE@LIB_COMPILE = @USE_LIBTOOL_TRUE@$(LTCOMPILE) |
@USE_LIBTOOL_FALSE@LIB_COMPILE = @USE_LIBTOOL_FALSE@$(COMPILE) |
@USE_LIBTOOL_TRUE@noinst_DATA = @USE_LIBTOOL_TRUE@objectlist.awk.in |
@USE_LIBTOOL_FALSE@noinst_DATA = |
@USE_LIBTOOL_FALSE@noinst_LIBRARIES = @USE_LIBTOOL_FALSE@lib.a |
@USE_LIBTOOL_FALSE@lib_a_SOURCES = @USE_LIBTOOL_FALSE@$(LIB_SOURCES) |
@USE_LIBTOOL_FALSE@lib_a_LIBADD = @USE_LIBTOOL_FALSE@$(LIBADD_OBJS) |
|
MALLOC_COMPILE = $(LIB_COMPILE) -DINTERNAL_NEWLIB |
|
CHEWOUT_FILES = \ |
abort.def \ |
abs.def \ |
assert.def \ |
atexit.def \ |
atof.def \ |
ecvtbuf.def \ |
atoi.def \ |
bsearch.def \ |
calloc.def \ |
div.def \ |
efgcvt.def \ |
envlock.def \ |
exit.def \ |
getenv.def \ |
labs.def \ |
ldiv.def \ |
malloc.def \ |
mallocr.def \ |
mblen.def \ |
mbstowcs.def \ |
mbtowc.def \ |
mlock.def \ |
mstats.def \ |
qsort.def \ |
rand.def \ |
rand48.def \ |
strtod.def \ |
strtol.def \ |
strtoll.def \ |
strtoul.def \ |
strtoull.def \ |
system.def \ |
wcstombs.def \ |
wctomb.def |
|
|
SUFFIXES = .def |
|
CHEW = ../../doc/makedoc -f $(srcdir)/../../doc/doc.str |
|
TARGETDOC = ../tmp.texi |
|
CLEANFILES = $(CHEWOUT_FILES) *.ref |
mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs |
CONFIG_CLEAN_FILES = |
LIBRARIES = $(noinst_LIBRARIES) |
|
|
DEFS = @DEFS@ -I. -I$(srcdir) |
CPPFLAGS = @CPPFLAGS@ |
LIBS = @LIBS@ |
@USE_LIBTOOL_FALSE@lib_a_DEPENDENCIES = freer.$(oext) reallocr.$(oext) \ |
@USE_LIBTOOL_FALSE@callocr.$(oext) cfreer.$(oext) malignr.$(oext) \ |
@USE_LIBTOOL_FALSE@vallocr.$(oext) pvallocr.$(oext) mallinfor.$(oext) \ |
@USE_LIBTOOL_FALSE@mallstatsr.$(oext) msizer.$(oext) malloptr.$(oext) \ |
@USE_LIBTOOL_FALSE@mallocr.$(oext) |
@USE_LIBTOOL_FALSE@lib_a_OBJECTS = __adjust.o __exp10.o __ten_mu.o \ |
@USE_LIBTOOL_FALSE@abort.o abs.o assert.o atexit.o atof.o atoff.o \ |
@USE_LIBTOOL_FALSE@atoi.o atol.o bsearch.o calloc.o div.o drand48.o \ |
@USE_LIBTOOL_FALSE@dtoa.o dtoastub.o ecvtbuf.o efgcvt.o environ.o \ |
@USE_LIBTOOL_FALSE@envlock.o eprintf.o erand48.o exit.o getenv.o \ |
@USE_LIBTOOL_FALSE@getenv_r.o getopt.o jrand48.o labs.o lcong48.o \ |
@USE_LIBTOOL_FALSE@ldiv.o ldtoa.o lrand48.o malign.o malloc.o mblen.o \ |
@USE_LIBTOOL_FALSE@mblen_r.o mbstowcs.o mbstowcs_r.o mbtowc.o \ |
@USE_LIBTOOL_FALSE@mbtowc_r.o mlock.o mprec.o mrand48.o msize.o \ |
@USE_LIBTOOL_FALSE@mstats.o mtrim.o nrand48.o putenv.o putenv_r.o \ |
@USE_LIBTOOL_FALSE@qsort.o rand.o rand48.o rand_r.o realloc.o seed48.o \ |
@USE_LIBTOOL_FALSE@setenv.o setenv_r.o srand48.o strdup.o strdup_r.o \ |
@USE_LIBTOOL_FALSE@strtod.o strtol.o strtoll.o strtoll_r.o strtoul.o \ |
@USE_LIBTOOL_FALSE@strtoull.o strtoull_r.o system.o valloc.o wcstombs.o \ |
@USE_LIBTOOL_FALSE@wcstombs_r.o wctomb.o wctomb_r.o |
LTLIBRARIES = $(noinst_LTLIBRARIES) |
|
@USE_LIBTOOL_TRUE@libstdlib_la_DEPENDENCIES = freer.$(oext) \ |
@USE_LIBTOOL_TRUE@reallocr.$(oext) callocr.$(oext) cfreer.$(oext) \ |
@USE_LIBTOOL_TRUE@malignr.$(oext) vallocr.$(oext) pvallocr.$(oext) \ |
@USE_LIBTOOL_TRUE@mallinfor.$(oext) mallstatsr.$(oext) msizer.$(oext) \ |
@USE_LIBTOOL_TRUE@malloptr.$(oext) mallocr.$(oext) |
@USE_LIBTOOL_TRUE@libstdlib_la_OBJECTS = __adjust.lo __exp10.lo \ |
@USE_LIBTOOL_TRUE@__ten_mu.lo abort.lo abs.lo assert.lo atexit.lo \ |
@USE_LIBTOOL_TRUE@atof.lo atoff.lo atoi.lo atol.lo bsearch.lo calloc.lo \ |
@USE_LIBTOOL_TRUE@div.lo drand48.lo dtoa.lo dtoastub.lo ecvtbuf.lo \ |
@USE_LIBTOOL_TRUE@efgcvt.lo environ.lo envlock.lo eprintf.lo erand48.lo \ |
@USE_LIBTOOL_TRUE@exit.lo getenv.lo getenv_r.lo getopt.lo jrand48.lo \ |
@USE_LIBTOOL_TRUE@labs.lo lcong48.lo ldiv.lo ldtoa.lo lrand48.lo \ |
@USE_LIBTOOL_TRUE@malign.lo malloc.lo mblen.lo mblen_r.lo mbstowcs.lo \ |
@USE_LIBTOOL_TRUE@mbstowcs_r.lo mbtowc.lo mbtowc_r.lo mlock.lo mprec.lo \ |
@USE_LIBTOOL_TRUE@mrand48.lo msize.lo mstats.lo mtrim.lo nrand48.lo \ |
@USE_LIBTOOL_TRUE@putenv.lo putenv_r.lo qsort.lo rand.lo rand48.lo \ |
@USE_LIBTOOL_TRUE@rand_r.lo realloc.lo seed48.lo setenv.lo setenv_r.lo \ |
@USE_LIBTOOL_TRUE@srand48.lo strdup.lo strdup_r.lo strtod.lo strtol.lo \ |
@USE_LIBTOOL_TRUE@strtoll.lo strtoll_r.lo strtoul.lo strtoull.lo \ |
@USE_LIBTOOL_TRUE@strtoull_r.lo system.lo valloc.lo wcstombs.lo \ |
@USE_LIBTOOL_TRUE@wcstombs_r.lo wctomb.lo wctomb_r.lo |
CFLAGS = @CFLAGS@ |
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) |
CCLD = $(CC) |
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ |
DATA = $(noinst_DATA) |
|
DIST_COMMON = Makefile.am Makefile.in |
|
|
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) |
|
TAR = gtar |
GZIP_ENV = --best |
SOURCES = $(lib_a_SOURCES) $(libstdlib_la_SOURCES) |
OBJECTS = $(lib_a_OBJECTS) $(libstdlib_la_OBJECTS) |
|
all: all-redirect |
.SUFFIXES: |
.SUFFIXES: .S .c .def .lo .o .s |
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) $(srcdir)/../../Makefile.shared |
cd $(top_srcdir) && $(AUTOMAKE) --cygnus stdlib/Makefile |
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status |
cd $(top_builddir) \ |
&& CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status |
|
|
mostlyclean-noinstLIBRARIES: |
|
clean-noinstLIBRARIES: |
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) |
|
distclean-noinstLIBRARIES: |
|
maintainer-clean-noinstLIBRARIES: |
|
.c.o: |
$(COMPILE) -c $< |
|
.s.o: |
$(COMPILE) -c $< |
|
.S.o: |
$(COMPILE) -c $< |
|
mostlyclean-compile: |
-rm -f *.o core *.core |
|
clean-compile: |
|
distclean-compile: |
-rm -f *.tab.c |
|
maintainer-clean-compile: |
|
.c.lo: |
$(LIBTOOL) --mode=compile $(COMPILE) -c $< |
|
.s.lo: |
$(LIBTOOL) --mode=compile $(COMPILE) -c $< |
|
.S.lo: |
$(LIBTOOL) --mode=compile $(COMPILE) -c $< |
|
mostlyclean-libtool: |
-rm -f *.lo |
|
clean-libtool: |
-rm -rf .libs _libs |
|
distclean-libtool: |
|
maintainer-clean-libtool: |
|
lib.a: $(lib_a_OBJECTS) $(lib_a_DEPENDENCIES) |
-rm -f lib.a |
$(AR) cru lib.a $(lib_a_OBJECTS) $(lib_a_LIBADD) |
$(RANLIB) lib.a |
|
mostlyclean-noinstLTLIBRARIES: |
|
clean-noinstLTLIBRARIES: |
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) |
|
distclean-noinstLTLIBRARIES: |
|
maintainer-clean-noinstLTLIBRARIES: |
|
libstdlib.la: $(libstdlib_la_OBJECTS) $(libstdlib_la_DEPENDENCIES) |
$(LINK) $(libstdlib_la_LDFLAGS) $(libstdlib_la_OBJECTS) $(libstdlib_la_LIBADD) $(LIBS) |
|
tags: TAGS |
|
ID: $(HEADERS) $(SOURCES) $(LISP) |
list='$(SOURCES) $(HEADERS)'; \ |
unique=`for i in $$list; do echo $$i; done | \ |
awk ' { files[$$0] = 1; } \ |
END { for (i in files) print i; }'`; \ |
here=`pwd` && cd $(srcdir) \ |
&& mkid -f$$here/ID $$unique $(LISP) |
|
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) |
tags=; \ |
here=`pwd`; \ |
list='$(SOURCES) $(HEADERS)'; \ |
unique=`for i in $$list; do echo $$i; done | \ |
awk ' { files[$$0] = 1; } \ |
END { for (i in files) print i; }'`; \ |
test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ |
|| (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) |
|
mostlyclean-tags: |
|
clean-tags: |
|
distclean-tags: |
-rm -f TAGS ID |
|
maintainer-clean-tags: |
|
distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) |
|
subdir = stdlib |
|
distdir: $(DISTFILES) |
@for file in $(DISTFILES); do \ |
if test -f $$file; then d=.; else d=$(srcdir); fi; \ |
if test -d $$d/$$file; then \ |
cp -pr $$d/$$file $(distdir)/$$file; \ |
else \ |
test -f $(distdir)/$$file \ |
|| ln $$d/$$file $(distdir)/$$file 2> /dev/null \ |
|| cp -p $$d/$$file $(distdir)/$$file || :; \ |
fi; \ |
done |
info-am: |
info: info-am |
dvi-am: |
dvi: dvi-am |
check-am: |
check: check-am |
installcheck-am: |
installcheck: installcheck-am |
install-info-am: |
install-info: install-info-am |
install-exec-am: |
install-exec: install-exec-am |
|
install-data-am: |
install-data: install-data-am |
|
install-am: all-am |
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am |
install: install-am |
uninstall-am: |
uninstall: uninstall-am |
all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(DATA) |
all-redirect: all-am |
install-strip: |
$(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install |
installdirs: |
|
|
mostlyclean-generic: |
|
clean-generic: |
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) |
|
distclean-generic: |
-rm -f Makefile $(CONFIG_CLEAN_FILES) |
-rm -f config.cache config.log stamp-h stamp-h[0-9]* |
|
maintainer-clean-generic: |
mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ |
mostlyclean-libtool mostlyclean-noinstLTLIBRARIES \ |
mostlyclean-tags mostlyclean-generic |
|
mostlyclean: mostlyclean-am |
|
clean-am: clean-noinstLIBRARIES clean-compile clean-libtool \ |
clean-noinstLTLIBRARIES clean-tags clean-generic \ |
mostlyclean-am |
|
clean: clean-am |
|
distclean-am: distclean-noinstLIBRARIES distclean-compile \ |
distclean-libtool distclean-noinstLTLIBRARIES \ |
distclean-tags distclean-generic clean-am |
-rm -f libtool |
|
distclean: distclean-am |
|
maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ |
maintainer-clean-compile maintainer-clean-libtool \ |
maintainer-clean-noinstLTLIBRARIES \ |
maintainer-clean-tags maintainer-clean-generic \ |
distclean-am |
@echo "This command is intended for maintainers to use;" |
@echo "it deletes files that may require special tools to rebuild." |
|
maintainer-clean: maintainer-clean-am |
|
.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ |
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ |
mostlyclean-compile distclean-compile clean-compile \ |
maintainer-clean-compile mostlyclean-libtool distclean-libtool \ |
clean-libtool maintainer-clean-libtool mostlyclean-noinstLTLIBRARIES \ |
distclean-noinstLTLIBRARIES clean-noinstLTLIBRARIES \ |
maintainer-clean-noinstLTLIBRARIES tags mostlyclean-tags distclean-tags \ |
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ |
check-am installcheck-am installcheck install-info-am install-info \ |
install-exec-am install-exec install-data-am install-data install-am \ |
install uninstall-am uninstall all-redirect all-am all installdirs \ |
mostlyclean-generic distclean-generic clean-generic \ |
maintainer-clean-generic clean mostlyclean distclean maintainer-clean |
|
|
objectlist.awk.in: $(noinst_LTLIBRARIES) |
-rm -f objectlist.awk.in |
for i in `ls *.lo` ; \ |
do \ |
echo $$i `pwd`/$$i >> objectlist.awk.in ; \ |
done |
|
mallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOC -c $(srcdir)/mallocr.c -o $@ |
|
freer.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_FREE -c $(srcdir)/mallocr.c -o $@ |
|
reallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_REALLOC -c $(srcdir)/mallocr.c -o $@ |
|
callocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_CALLOC -c $(srcdir)/mallocr.c -o $@ |
|
cfreer.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_CFREE -c $(srcdir)/mallocr.c -o $@ |
|
malignr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MEMALIGN -c $(srcdir)/mallocr.c -o $@ |
|
vallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_VALLOC -c $(srcdir)/mallocr.c -o $@ |
|
pvallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_PVALLOC -c $(srcdir)/mallocr.c -o $@ |
|
mallinfor.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLINFO -c $(srcdir)/mallocr.c -o $@ |
|
mallstatsr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOC_STATS -c $(srcdir)/mallocr.c -o $@ |
|
msizer.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOC_USABLE_SIZE -c $(srcdir)/mallocr.c -o $@ |
|
malloptr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/mallocr.c -o $@ |
|
.c.def: |
$(CHEW) < $< > $*.def 2> $*.ref |
touch stmp-def |
|
doc: $(CHEWOUT_FILES) |
cat $(srcdir)/stdlib.tex >> $(TARGETDOC) |
|
dtoa.$(oext): dtoa.c mprec.h |
ldtoa.$(oext): ldtoa.c mprec.h |
ecvtbuf.$(oext): ecvtbuf.c mprec.h |
mbtowc_r.$(oext): mbtowc_r.c mbctype.h |
$(LIB_COMPILE) -c -fshort-enums $(srcdir)/mbtowc_r.c -o $@ |
|
mprec.$(oext): mprec.c mprec.h |
strtod.$(oext): strtod.c mprec.h |
wctomb_r.$(oext): wctomb_r.c mbctype.h |
drand48.$(oext): drand48.c rand48.h |
erand48.$(oext): erand48.c rand48.h |
jrand48.$(oext): jrand48.c rand48.h |
lcong48.$(oext): lcong48.c rand48.h |
lrand48.$(oext): lrand48.c rand48.h |
mrand48.$(oext): mrand48.c rand48.h |
nrand48.$(oext): nrand48.c rand48.h |
rand48.$(oext): rand48.c rand48.h |
seed48.$(oext): seed48.c rand48.h |
srand48.$(oext): srand48.c rand48.h |
|
# Tell versions [3.59,3.63) of GNU make to not export all variables. |
# Otherwise a system limit (for SysV at least) may be exceeded. |
.NOEXPORT: |
/drand48.c
0,0 → 1,29
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
double |
_DEFUN (_drand48_r, (r), |
struct _reent *r) |
{ |
return _erand48_r(r, __rand48_seed); |
} |
|
#ifndef _REENT_ONLY |
double |
_DEFUN_VOID (drand48) |
{ |
return _drand48_r (_REENT); |
} |
#endif /* !_REENT_ONLY */ |
/setenv.c
0,0 → 1,54
/* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that: (1) source distributions retain this entire copyright |
* notice and comment, and (2) distributions including binaries display |
* the following acknowledgement: ``This product includes software |
* developed by the University of California, Berkeley and its contributors'' |
* in the documentation or other materials provided with the distribution |
* and in all advertising materials mentioning features or use of this |
* software. Neither the name of the University nor the names of its |
* contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stddef.h> |
#include <stdlib.h> |
#include <string.h> |
|
extern void _unsetenv_r _PARAMS ((struct _reent *, const char *)); |
|
/* |
* setenv -- |
* Set the value of the environmental variable "name" to be |
* "value". If rewrite is set, replace any current value. |
*/ |
|
int |
_DEFUN (setenv, (name, value, rewrite), |
_CONST char *name _AND |
_CONST char *value _AND |
int rewrite) |
{ |
return _setenv_r (_REENT, name, value, rewrite); |
} |
|
/* |
* unsetenv(name) -- |
* Delete environmental variable "name". |
*/ |
void |
_DEFUN (unsetenv, (name), |
_CONST char *name) |
{ |
_unsetenv_r (_REENT, name); |
} |
|
#endif /* !_REENT_ONLY */ |
/mlock.c
0,0 → 1,50
/* |
FUNCTION |
<<__malloc_lock>>, <<__malloc_unlock>>--lock malloc pool |
|
INDEX |
__malloc_lock |
INDEX |
__malloc_unlock |
|
ANSI_SYNOPSIS |
#include <malloc.h> |
void __malloc_lock (struct _reent *<[reent]>); |
void __malloc_unlock (struct _reent *<[reent]>); |
|
TRAD_SYNOPSIS |
void __malloc_lock(<[reent]>) |
struct _reent *<[reent]>; |
|
void __malloc_unlock(<[reent]>) |
struct _reent *<[reent]>; |
|
DESCRIPTION |
The <<malloc>> family of routines call these functions when they need |
to lock the memory pool. The version of these routines supplied in |
the library does not do anything. If multiple threads of execution |
can call <<malloc>>, or if <<malloc>> can be called reentrantly, then |
you need to define your own versions of these functions in order to |
safely lock the memory pool during a call. If you do not, the memory |
pool may become corrupted. |
|
A call to <<malloc>> may call <<__malloc_lock>> recursively; that is, |
the sequence of calls may go <<__malloc_lock>>, <<__malloc_lock>>, |
<<__malloc_unlock>>, <<__malloc_unlock>>. Any implementation of these |
routines must be careful to avoid causing a thread to wait for a lock |
that it already holds. |
*/ |
|
#include <malloc.h> |
|
void |
__malloc_lock (ptr) |
struct _reent *ptr; |
{ |
} |
|
void |
__malloc_unlock (ptr) |
struct _reent *ptr; |
{ |
} |
/abs.c
0,0 → 1,43
/* |
FUNCTION |
<<abs>>---integer absolute value (magnitude) |
|
INDEX |
abs |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int abs(int <[i]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int abs(<[i]>) |
int <[i]>; |
|
DESCRIPTION |
<<abs>> returns |
@tex |
$|x|$, |
@end tex |
the absolute value of <[i]> (also called the magnitude |
of <[i]>). That is, if <[i]> is negative, the result is the opposite |
of <[i]>, but if <[i]> is nonnegative the result is <[i]>. |
|
The similar function <<labs>> uses and returns <<long>> rather than <<int>> values. |
|
RETURNS |
The result is a nonnegative integer. |
|
PORTABILITY |
<<abs>> is ANSI. |
|
No supporting OS subroutines are required. |
*/ |
|
#include <stdlib.h> |
|
int |
_DEFUN (abs, (i), int i) |
{ |
return (i < 0) ? -i : i; |
} |
/erand48.c
0,0 → 1,34
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
double |
_DEFUN (_erand48_r, (r, xseed), |
struct _reent *r _AND |
unsigned short xseed[3]) |
{ |
__dorand48(r, xseed); |
return ldexp((double) xseed[0], -48) + |
ldexp((double) xseed[1], -32) + |
ldexp((double) xseed[2], -16); |
} |
|
#ifndef _REENT_ONLY |
double |
_DEFUN (erand48, (xseed), |
unsigned short xseed[3]) |
{ |
return _erand48_r (_REENT, xseed); |
} |
#endif /* !_REENT_ONLY */ |
/malign.c
0,0 → 1,18
/* malign.c -- a wrapper for memalign_r. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
|
#ifndef _REENT_ONLY |
|
_PTR |
_DEFUN (memalign, (align, nbytes), |
size_t align _AND |
size_t nbytes) |
{ |
return _memalign_r (_REENT, align, nbytes); |
} |
|
#endif |
/mbctype.h
0,0 → 1,20
#ifndef _MBCTYPE_H_ |
|
#define _MBCTYPE_H_ |
|
/* escape character used for JIS encoding */ |
#define ESC_CHAR 0x1b |
|
/* functions used to support SHIFT_JIS, EUC-JP, and JIS multibyte encodings */ |
|
int _EXFUN(_issjis1, (int c)); |
int _EXFUN(_issjis2, (int c)); |
int _EXFUN(_iseucjp, (int c)); |
int _EXFUN(_isjis, (int c)); |
|
#define _issjis1(c) (((c) >= 0x81 && (c) <= 0x9f) || ((c) >= 0xe0 && (c) <= 0xef)) |
#define _issjis2(c) (((c) >= 0x40 && (c) <= 0x7e) || ((c) >= 0x80 && (c) <= 0xfc)) |
#define _iseucjp(c) ((c) >= 0xa1 && (c) <= 0xfe) |
#define _isjis(c) ((c) >= 0x21 && (c) <= 0x7e) |
|
#endif /* _MBCTYPE_H_ */ |
/exit.c
0,0 → 1,73
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* %sccs.include.redist.c% |
*/ |
|
/* |
FUNCTION |
<<exit>>---end program execution |
|
INDEX |
exit |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
void exit(int <[code]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
void exit(<[code]>) |
int <[code]>; |
|
DESCRIPTION |
Use <<exit>> to return control from a program to the host operating |
environment. Use the argument <[code]> to pass an exit status to the |
operating environment: two particular values, <<EXIT_SUCCESS>> and |
<<EXIT_FAILURE>>, are defined in `<<stdlib.h>>' to indicate success or |
failure in a portable fashion. |
|
<<exit>> does two kinds of cleanup before ending execution of your |
program. First, it calls all application-defined cleanup functions |
you have enrolled with <<atexit>>. Second, files and streams are |
cleaned up: any pending output is delivered to the host system, each |
open file or stream is closed, and files created by <<tmpfile>> are |
deleted. |
|
RETURNS |
<<exit>> does not return to its caller. |
|
PORTABILITY |
ANSI C requires <<exit>>, and specifies that <<EXIT_SUCCESS>> and |
<<EXIT_FAILURE>> must be defined. |
|
Supporting OS subroutines required: <<_exit>>. |
*/ |
|
#include <stdlib.h> |
#include <unistd.h> /* for _exit() declaration */ |
#include <reent.h> |
|
#ifndef _REENT_ONLY |
|
/* |
* Exit, flushing stdio buffers if necessary. |
*/ |
|
void |
_DEFUN (exit, (code), |
int code) |
{ |
register struct _atexit *p; |
register int n; |
|
for (p = _REENT->_atexit; p; p = p->_next) |
for (n = p->_ind; --n >= 0;) |
(*p->_fns[n]) (); |
if (_REENT->__cleanup) |
(*_REENT->__cleanup) (_REENT); |
_exit (code); |
} |
|
#endif |
/strtoull_r.c
0,0 → 1,120
/* |
This code is based on strtoul.c which has the following copyright. |
It is used to convert a string into an unsigned long long. |
|
long long _strtoull_r (struct _reent *rptr, const char *s, |
char **ptr, int base); |
|
*/ |
|
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#ifdef __GNUC__ |
|
#define _GNU_SOURCE |
#include <_ansi.h> |
#include <limits.h> |
#include <ctype.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <reent.h> |
|
/* |
* Convert a string to an unsigned long long integer. |
* |
* Ignores `locale' stuff. Assumes that the upper and lower case |
* alphabets and digits are each contiguous. |
*/ |
unsigned long long |
_DEFUN (_strtoull_r, (rptr, nptr, endptr, base), |
struct _reent *rptr _AND |
_CONST char *nptr _AND |
char **endptr _AND |
int base) |
{ |
register const char *s = nptr; |
register unsigned long long acc; |
register int c; |
register unsigned long long cutoff; |
register int neg = 0, any, cutlim; |
|
/* |
* See strtol for comments as to the logic used. |
*/ |
do { |
c = *s++; |
} while (isspace(c)); |
if (c == '-') { |
neg = 1; |
c = *s++; |
} else if (c == '+') |
c = *s++; |
if ((base == 0 || base == 16) && |
c == '0' && (*s == 'x' || *s == 'X')) { |
c = s[1]; |
s += 2; |
base = 16; |
} |
if (base == 0) |
base = c == '0' ? 8 : 10; |
cutoff = (unsigned long long)ULONG_LONG_MAX / (unsigned long long)base; |
cutlim = (unsigned long long)ULONG_LONG_MAX % (unsigned long long)base; |
for (acc = 0, any = 0;; c = *s++) { |
if (isdigit(c)) |
c -= '0'; |
else if (isalpha(c)) |
c -= isupper(c) ? 'A' - 10 : 'a' - 10; |
else |
break; |
if (c >= base) |
break; |
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) |
any = -1; |
else { |
any = 1; |
acc *= base; |
acc += c; |
} |
} |
if (any < 0) { |
acc = ULONG_LONG_MAX; |
rptr->_errno = ERANGE; |
} else if (neg) |
acc = -acc; |
if (endptr != 0) |
*endptr = (char *) (any ? s - 1 : nptr); |
return (acc); |
} |
|
#endif /* __GNUC__ */ |
/jrand48.c
0,0 → 1,32
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
long |
_DEFUN (_jrand48_r, (r, xseed), |
struct _reent *r _AND |
unsigned short xseed[3]) |
{ |
__dorand48(r, xseed); |
return ((long) xseed[2] << 16) + (long) xseed[1]; |
} |
|
#ifndef _REENT_ONLY |
long |
_DEFUN (jrand48, (xseed), |
unsigned short xseed[3]) |
{ |
return _jrand48_r (_REENT, xseed); |
} |
#endif /* !_REENT_ONLY */ |
/mbtowc_r.c
0,0 → 1,208
#include <stdlib.h> |
#include <locale.h> |
#include "mbctype.h" |
|
#ifdef MB_CAPABLE |
typedef enum { ESCAPE, DOLLAR, BRACKET, AT, B, J, |
NUL, JIS_CHAR, OTHER, JIS_C_NUM } JIS_CHAR_TYPE; |
typedef enum { ASCII, A_ESC, A_ESC_DL, JIS, JIS_1, JIS_2, J_ESC, J_ESC_BR, |
J2_ESC, J2_ESC_BR, DONE, INV, JIS_S_NUM } JIS_STATE; |
typedef enum { COPY_A, COPY_J, COPY_J2, MAKE_A, MAKE_J, NOOP, EMPTY, ERROR } JIS_ACTION; |
|
/************************************************************************************** |
* state/action tables for processing JIS encoding |
* Where possible, switches to JIS are grouped with proceding JIS characters and switches |
* to ASCII are grouped with preceding JIS characters. Thus, maximum returned length |
* is 2 (switch to JIS) + 2 (JIS characters) + 2 (switch back to ASCII) = 6. |
*************************************************************************************/ |
|
static JIS_STATE JIS_state_table[JIS_S_NUM][JIS_C_NUM] = { |
/* ESCAPE DOLLAR BRACKET AT B J NUL JIS_CHAR OTHER */ |
/* ASCII */ { A_ESC, DONE, DONE, DONE, DONE, DONE, DONE, DONE, DONE }, |
/* A_ESC */ { DONE, A_ESC_DL, DONE, DONE, DONE, DONE, DONE, DONE, DONE }, |
/* A_ESC_DL */{ DONE, DONE, DONE, JIS, JIS, DONE, DONE, DONE, DONE }, |
/* JIS */ { J_ESC, JIS_1, JIS_1, JIS_1, JIS_1, JIS_1, INV, JIS_1, INV }, |
/* JIS_1 */ { INV, JIS_2, JIS_2, JIS_2, JIS_2, JIS_2, INV, JIS_2, INV }, |
/* JIS_2 */ { J2_ESC, DONE, DONE, DONE, DONE, DONE, INV, DONE, DONE }, |
/* J_ESC */ { INV, INV, J_ESC_BR, INV, INV, INV, INV, INV, INV }, |
/* J_ESC_BR */{ INV, INV, INV, INV, ASCII, ASCII, INV, INV, INV }, |
/* J2_ESC */ { INV, INV, J2_ESC_BR,INV, INV, INV, INV, INV, INV }, |
/* J2_ESC_BR*/{ INV, INV, INV, INV, DONE, DONE, INV, INV, INV }, |
}; |
|
static JIS_ACTION JIS_action_table[JIS_S_NUM][JIS_C_NUM] = { |
/* ESCAPE DOLLAR BRACKET AT B J NUL JIS_CHAR OTHER */ |
/* ASCII */ { NOOP, COPY_A, COPY_A, COPY_A, COPY_A, COPY_A, EMPTY, COPY_A, COPY_A}, |
/* A_ESC */ { COPY_A, NOOP, COPY_A, COPY_A, COPY_A, COPY_A, COPY_A, COPY_A, COPY_A}, |
/* A_ESC_DL */{ COPY_A, COPY_A, COPY_A, MAKE_J, MAKE_J, COPY_A, COPY_A, COPY_A, COPY_A}, |
/* JIS */ { NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, ERROR, NOOP, ERROR }, |
/* JIS_1 */ { ERROR, NOOP, NOOP, NOOP, NOOP, NOOP, ERROR, NOOP, ERROR }, |
/* JIS_2 */ { NOOP, COPY_J2, COPY_J2, COPY_J2, COPY_J2, COPY_J2, ERROR, COPY_J2, COPY_J2}, |
/* J_ESC */ { ERROR, ERROR, NOOP, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR }, |
/* J_ESC_BR */{ ERROR, ERROR, ERROR, ERROR, NOOP, NOOP, ERROR, ERROR, ERROR }, |
/* J2_ESC */ { ERROR, ERROR, NOOP, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR }, |
/* J2_ESC_BR*/{ ERROR, ERROR, ERROR, ERROR, COPY_J, COPY_J, ERROR, ERROR, ERROR }, |
}; |
#endif /* MB_CAPABLE */ |
|
int |
_DEFUN (_mbtowc_r, (r, pwc, s, n, state), |
struct _reent *r _AND |
wchar_t *pwc _AND |
const char *s _AND |
size_t n _AND |
int *state) |
{ |
wchar_t dummy; |
unsigned char *t = (unsigned char *)s; |
|
if (pwc == NULL) |
pwc = &dummy; |
|
if (s != NULL && n == 0) |
return -1; |
|
#ifdef MB_CAPABLE |
if (r->_current_locale == NULL || |
(strlen (r->_current_locale) <= 1)) |
{ /* fall-through */ } |
else if (!strcmp (r->_current_locale, "C-SJIS")) |
{ |
int char1; |
if (s == NULL) |
return 0; /* not state-dependent */ |
char1 = *t; |
if (_issjis1 (char1)) |
{ |
int char2 = t[1]; |
if (n <= 1) |
return -1; |
if (_issjis2 (char2)) |
{ |
*pwc = (((wchar_t)*t) << 8) + (wchar_t)(*(t+1)); |
return 2; |
} |
else |
return -1; |
} |
} |
else if (!strcmp (r->_current_locale, "C-EUCJP")) |
{ |
int char1; |
if (s == NULL) |
return 0; /* not state-dependent */ |
char1 = *t; |
if (_iseucjp (char1)) |
{ |
int char2 = t[1]; |
if (n <= 1) |
return -1; |
if (_iseucjp (char2)) |
{ |
*pwc = (((wchar_t)*t) << 8) + (wchar_t)(*(t+1)); |
return 2; |
} |
else |
return -1; |
} |
} |
else if (!strcmp (r->_current_locale, "C-JIS")) |
{ |
JIS_STATE curr_state; |
JIS_ACTION action; |
JIS_CHAR_TYPE ch; |
unsigned char *ptr; |
int i, curr_ch; |
|
if (s == NULL) |
{ |
*state = 0; |
return 1; /* state-dependent */ |
} |
|
curr_state = (*state == 0 ? ASCII : JIS); |
ptr = t; |
|
for (i = 0; i < n; ++i) |
{ |
curr_ch = t[i]; |
switch (curr_ch) |
{ |
case ESC_CHAR: |
ch = ESCAPE; |
break; |
case '$': |
ch = DOLLAR; |
break; |
case '@': |
ch = AT; |
break; |
case '(': |
ch = BRACKET; |
break; |
case 'B': |
ch = B; |
break; |
case 'J': |
ch = J; |
break; |
case '\0': |
ch = NUL; |
break; |
default: |
if (_isjis (curr_ch)) |
ch = JIS_CHAR; |
else |
ch = OTHER; |
} |
|
action = JIS_action_table[curr_state][ch]; |
curr_state = JIS_state_table[curr_state][ch]; |
|
switch (action) |
{ |
case NOOP: |
break; |
case EMPTY: |
*state = 0; |
*pwc = (wchar_t)0; |
return i; |
case COPY_A: |
*state = 0; |
*pwc = (wchar_t)*ptr; |
return (i + 1); |
case COPY_J: |
*state = 0; |
*pwc = (((wchar_t)*ptr) << 8) + (wchar_t)(*(ptr+1)); |
return (i + 1); |
case COPY_J2: |
*state = 1; |
*pwc = (((wchar_t)*ptr) << 8) + (wchar_t)(*(ptr+1)); |
return (ptr - t) + 2; |
case MAKE_A: |
case MAKE_J: |
ptr = (char *)(t + i + 1); |
break; |
case ERROR: |
default: |
return -1; |
} |
|
} |
|
return -1; /* n < bytes needed */ |
} |
#endif /* MB_CAPABLE */ |
|
/* otherwise this must be the "C" locale or unknown locale */ |
if (s == NULL) |
return 0; /* not state-dependent */ |
|
*pwc = (wchar_t)*t; |
|
if (*t == '\0') |
return 0; |
|
return 1; |
} |
|
/lrand48.c
0,0 → 1,31
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
long |
_DEFUN (_lrand48_r, (r), |
struct _reent *r) |
{ |
__dorand48(r, __rand48_seed); |
return (long)((unsigned long) __rand48_seed[2] << 15) + |
((unsigned long) __rand48_seed[1] >> 1); |
} |
|
#ifndef _REENT_ONLY |
long |
_DEFUN_VOID (lrand48) |
{ |
return _lrand48_r (_REENT); |
} |
#endif /* !_REENT_ONLY */ |
/wctomb_r.c
0,0 → 1,111
#include <stdlib.h> |
#include <string.h> |
#include <locale.h> |
#include "mbctype.h" |
|
int |
_DEFUN (_wctomb_r, (r, s, wchar, state), |
struct _reent *r _AND |
char *s _AND |
wchar_t wchar _AND |
int *state) |
{ |
if (strlen (r->_current_locale) <= 1) |
{ /* fall-through */ } |
else if (!strcmp (r->_current_locale, "C-SJIS")) |
{ |
unsigned char char2 = (unsigned char)wchar; |
unsigned char char1 = (unsigned char)(wchar >> 8); |
|
if (s == NULL) |
return 0; /* not state-dependent */ |
|
if (char1 != 0x00) |
{ |
/* first byte is non-zero..validate multi-byte char */ |
if (_issjis1(char1) && _issjis2(char2)) |
{ |
*s++ = (char)char1; |
*s = (char)char2; |
return 2; |
} |
else |
return -1; |
} |
} |
else if (!strcmp (r->_current_locale, "C-EUCJP")) |
{ |
unsigned char char2 = (unsigned char)wchar; |
unsigned char char1 = (unsigned char)(wchar >> 8); |
|
if (s == NULL) |
return 0; /* not state-dependent */ |
|
if (char1 != 0x00) |
{ |
/* first byte is non-zero..validate multi-byte char */ |
if (_iseucjp (char1) && _iseucjp (char2)) |
{ |
*s++ = (char)char1; |
*s = (char)char2; |
return 2; |
} |
else |
return -1; |
} |
} |
else if (!strcmp (r->_current_locale, "C-JIS")) |
{ |
int cnt = 0; |
unsigned char char2 = (unsigned char)wchar; |
unsigned char char1 = (unsigned char)(wchar >> 8); |
|
if (s == NULL) |
return 1; /* state-dependent */ |
|
if (char1 != 0x00) |
{ |
/* first byte is non-zero..validate multi-byte char */ |
if (_isjis (char1) && _isjis (char2)) |
{ |
if (*state == 0) |
{ |
/* must switch from ASCII to JIS state */ |
*state = 1; |
*s++ = ESC_CHAR; |
*s++ = '$'; |
*s++ = 'B'; |
cnt = 3; |
} |
*s++ = (char)char1; |
*s = (char)char2; |
return cnt + 2; |
} |
else |
return -1; |
} |
else |
{ |
if (*state != 0) |
{ |
/* must switch from JIS to ASCII state */ |
*state = 0; |
*s++ = ESC_CHAR; |
*s++ = '('; |
*s++ = 'B'; |
cnt = 3; |
} |
*s = (char)char2; |
return cnt + 1; |
} |
} |
|
if (s == NULL) |
return 0; |
|
/* otherwise we are dealing with a single byte character */ |
*s = (char) wchar; |
return 1; |
} |
|
|
/mrand48.c
0,0 → 1,30
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
long |
_DEFUN (_mrand48_r, (r), |
struct _reent *r) |
{ |
__dorand48(r, __rand48_seed); |
return ((long) __rand48_seed[2] << 16) + (long) __rand48_seed[1]; |
} |
|
#ifndef _REENT_ONLY |
long |
_DEFUN_VOID (mrand48) |
{ |
return _mrand48_r (_REENT); |
} |
#endif /* !_REENT_ONLY */ |
/nrand48.c
0,0 → 1,33
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
long |
_DEFUN (_nrand48_r, (r, xseed), |
struct _reent *r _AND |
unsigned short xseed[3]) |
{ |
__dorand48 (r, xseed); |
return (long)((unsigned long) xseed[2] << 15) + |
((unsigned long) xseed[1] >> 1); |
} |
|
#ifndef _REENT_ONLY |
long |
_DEFUN (nrand48, (xseed), |
unsigned short xseed[3]) |
{ |
return _nrand48_r (_REENT, xseed); |
} |
#endif /* !_REENT_ONLY */ |
/wcstombs_r.c
0,0 → 1,32
#include <stdlib.h> |
|
size_t |
_DEFUN (_wcstombs_r, (reent, s, pwcs, n, state), |
struct _reent *r _AND |
char *s _AND |
const wchar_t *pwcs _AND |
size_t n _AND |
int *state) |
{ |
char *ptr = s; |
size_t max = n; |
char buff[8]; |
int i, num_to_copy; |
|
while (n > 0) |
{ |
int bytes = _wctomb_r (r, buff, *pwcs, state); |
if (bytes == -1) |
return -1; |
num_to_copy = (n > bytes ? bytes : (int)n); |
for (i = 0; i < num_to_copy; ++i) |
*ptr++ = buff[i]; |
|
if (*pwcs == 0x00) |
return ptr - s - (n >= bytes); |
++pwcs; |
n -= num_to_copy; |
} |
|
return max; |
} |
/srand48.c
0,0 → 1,37
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
_VOID |
_DEFUN (_srand48_r, (r, seed), |
struct _reent *r _AND |
long seed) |
{ |
__rand48_seed[0] = _RAND48_SEED_0; |
__rand48_seed[1] = (unsigned short) seed; |
__rand48_seed[2] = (unsigned short) ((unsigned long)seed >> 16); |
__rand48_mult[0] = _RAND48_MULT_0; |
__rand48_mult[1] = _RAND48_MULT_1; |
__rand48_mult[2] = _RAND48_MULT_2; |
__rand48_add = _RAND48_ADD; |
} |
|
#ifndef _REENT_ONLY |
_VOID |
_DEFUN (srand48, (seed), |
long seed) |
{ |
_srand48_r (_REENT, seed); |
} |
#endif /* !_REENT_ONLY */ |
/__ten_mu.c
0,0 → 1,23
/* |
* [atw] multiply 64 bit accumulator by 10 and add digit. |
* The KA/CA way to do this should be to use |
* a 64-bit integer internally and use "adjust" to |
* convert it to float at the end of processing. |
*/ |
|
#include <_ansi.h> |
|
int |
_DEFUN (__ten_mul, (acc, digit), |
double *acc _AND |
int digit) |
{ |
/* |
* [atw] Crude, but effective (at least on a KB)... |
*/ |
|
*acc *= 10; |
*acc += digit; |
|
return 0; /* no overflow */ |
} |
/msize.c
0,0 → 1,17
/* msize.c -- a wrapper for malloc_usable_size. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
|
#ifndef _REENT_ONLY |
|
size_t |
_DEFUN (malloc_usable_size, (ptr), |
_PTR ptr) |
{ |
return _malloc_usable_size_r (_REENT, ptr); |
} |
|
#endif |
/mbtowc.c
0,0 → 1,81
/* |
FUNCTION |
<<mbtowc>>---minimal multibyte to wide char converter |
|
INDEX |
mbtowc |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int mbtowc(wchar_t *<[pwc]>, const char *<[s]>, size_t <[n]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int mbtowc(<[pwc]>, <[s]>, <[n]>) |
wchar_t *<[pwc]>; |
const char *<[s]>; |
size_t <[n]>; |
|
DESCRIPTION |
When MB_CAPABLE is not defined, this is a minimal ANSI-conforming |
implementation of <<mbtowc>>. In this case, |
only ``multi-byte character sequences'' recognized are single bytes, |
and they are ``converted'' to themselves. |
Each call to <<mbtowc>> copies one character from <<*<[s]>>> to |
<<*<[pwc]>>>, unless <[s]> is a null pointer. The argument n |
is ignored. |
|
When MB_CAPABLE is defined, this routine calls <<_mbtowc_r>> to perform |
the conversion, passing a state variable to allow state dependent |
decoding. The result is based on the locale setting which may |
be restricted to a defined set of locales. |
|
RETURNS |
This implementation of <<mbtowc>> returns <<0>> if |
<[s]> is <<NULL>> or is the empty string; |
it returns <<1>> if not MB_CAPABLE or |
the character is a single-byte character; it returns <<-1>> |
if n is <<0>> or the multi-byte character is invalid; |
otherwise it returns the number of bytes in the multibyte character. |
If the return value is -1, no changes are made to the <<pwc>> |
output string. If the input is the empty string, a wchar_t nul |
is placed in the output string and 0 is returned. If the input |
has a length of 0, no changes are made to the <<pwc>> output string. |
|
PORTABILITY |
<<mbtowc>> is required in the ANSI C standard. However, the precise |
effects vary with the locale. |
|
<<mbtowc>> requires no supporting OS subroutines. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
|
int |
_DEFUN (mbtowc, (pwc, s, n), |
wchar_t *pwc _AND |
const char *s _AND |
size_t n) |
{ |
#ifdef MB_CAPABLE |
static int state; |
|
return _mbtowc_r (_REENT, pwc, s, n, &state); |
#else /* not MB_CAPABLE */ |
if (s == NULL) |
return 0; |
if (n == 0) |
return -1; |
if (pwc) |
*pwc = (wchar_t) *s; |
return (*s != '\0'); |
#endif /* not MB_CAPABLE */ |
} |
|
#endif /* !_REENT_ONLY */ |
|
|
|
|
/wctomb.c
0,0 → 1,69
/* |
FUNCTION |
<<wctomb>>---minimal wide char to multibyte converter |
|
INDEX |
wctomb |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int wctomb(char *<[s]>, wchar_t <[wchar]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int wctomb(<[s]>, <[wchar]>) |
char *<[s]>; |
wchar_t <[wchar]>; |
|
DESCRIPTION |
When MB_CAPABLE is not defined, this is a minimal ANSI-conforming |
implementation of <<wctomb>>. The |
only ``wide characters'' recognized are single bytes, |
and they are ``converted'' to themselves. |
|
When MB_CAPABLE is defined, this routine calls <<_wctomb_r>> to perform |
the conversion, passing a state variable to allow state dependent |
decoding. The result is based on the locale setting which may |
be restricted to a defined set of locales. |
|
Each call to <<wctomb>> modifies <<*<[s]>>> unless <[s]> is a null |
pointer or MB_CAPABLE is defined and <[wchar]> is invalid. |
|
RETURNS |
This implementation of <<wctomb>> returns <<0>> if |
<[s]> is <<NULL>>; it returns <<-1>> if MB_CAPABLE is enabled |
and the wchar is not a valid multi-byte character, it returns <<1>> |
if MB_CAPABLE is not defined or the wchar is in reality a single |
byte character, otherwise it returns the number of bytes in the |
multi-byte character. |
|
PORTABILITY |
<<wctomb>> is required in the ANSI C standard. However, the precise |
effects vary with the locale. |
|
<<wctomb>> requires no supporting OS subroutines. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
|
int |
_DEFUN (wctomb, (s, wchar), |
char *s _AND |
wchar_t wchar) |
{ |
#ifdef MB_CAPABLE |
static int state; |
|
return _wctomb_r (_REENT, s, wchar, &state); |
#else /* not MB_CAPABLE */ |
if (s == NULL) |
return 0; |
|
*s = (char) wchar; |
return 1; |
#endif /* not MB_CAPABLE */ |
} |
|
#endif /* !_REENT_ONLY */ |
/local.h
0,0 → 1,8
/* Misc. local definitions for libc/stdlib */ |
|
#ifndef _LOCAL_H_ |
#define _LOCAL_H_ |
|
char * _EXFUN(_gcvt,(struct _reent *, double , int , char *, char, int)); |
|
#endif |
/std.h
0,0 → 1,33
#include <stdlib.h> |
#include <stdio.h> |
#include <errno.h> |
#include <limits.h> |
#include <math.h> |
#ifndef CYGNUS_NEC |
#include <ctype.h> |
#endif |
|
#define Ise(c) ((c == 'e') || (c == 'E') || (c == 'd') || (c == 'D')) |
#define Isdigit(c) ((c <= '9') && (c >= '0')) |
#define Isspace(c) ((c == ' ') || (c == '\t') || (c=='\n') || (c=='\v') \ |
|| (c == '\r') || (c == '\f')) |
#define Issign(c) ((c == '-') || (c == '+')) |
#define Val(c) ((c - '0')) |
|
#define MAXE 308 |
#define MINE (-308) |
|
/* flags */ |
#define SIGN 0x01 |
#define ESIGN 0x02 |
#define DECP 0x04 |
|
#ifdef _HAVE_STDC |
int __ten_mul(double *acc, int digit); |
double __adjust(struct _reent *ptr, double *acc, int dexp, int sign); |
const double __exp10(unsigned x); |
#else |
int __ten_mul(); |
double __adjust(); |
double __exp10(); |
#endif |
/rand48.c
0,0 → 1,178
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
/* |
FUNCTION |
<<rand48>>, <<drand48>>, <<erand48>>, <<lrand48>>, <<nrand48>>, <<mrand48>>, <<jrand48>>, <<srand48>>, <<seed48>>, <<lcong48>> ---pseudo random number generators and initialization routines |
|
INDEX |
rand48 |
INDEX |
drand48 |
INDEX |
erand48 |
INDEX |
lrand48 |
INDEX |
nrand48 |
INDEX |
mrand48 |
INDEX |
jrand48 |
INDEX |
srand48 |
INDEX |
seed48 |
INDEX |
lcong48 |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
double drand48(void); |
double erand48(unsigned short <[xseed]>[3]); |
long lrand48(void); |
long nrand48(unsigned short <[xseed]>[3]); |
long mrand48(void); |
long jrand48(unsigned short <[xseed]>[3]); |
void srand48(long <[seed]>); |
unsigned short *seed48(unsigned short <[xseed]>[3]); |
void lcong48(unsigned short <[p]>[7]); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
double drand48(); |
|
double erand48(<[xseed]>) |
unsigned short <[xseed]>[3]; |
|
long lrand48(); |
|
long nrand48(<[xseed]>) |
unsigned short <[xseed]>[3]; |
|
long mrand48(); |
|
long jrand48(<[xseed]>) |
unsigned short <[xseed]>[3]; |
|
void srand48(<[seed]>) |
long <[seed]>; |
|
unsigned short *seed48(<[xseed]>) |
unsigned short <[xseed]>[3]; |
|
void lcong48(<[p]>) |
unsigned short <[p]>[7]; |
|
DESCRIPTION |
The <<rand48>> family of functions generates pseudo-random numbers |
using a linear congruential algorithm working on integers 48 bits in size. |
The particular formula employed is |
r(n+1) = (a * r(n) + c) mod m |
where the default values are |
for the multiplicand a = 0xfdeece66d = 25214903917 and |
the addend c = 0xb = 11. The modulo is always fixed at m = 2 ** 48. |
r(n) is called the seed of the random number generator. |
|
For all the six generator routines described next, the first |
computational step is to perform a single iteration of the algorithm. |
|
<<drand48>> and <<erand48>> |
return values of type double. The full 48 bits of r(n+1) are |
loaded into the mantissa of the returned value, with the exponent set |
such that the values produced lie in the interval [0.0, 1.0]. |
|
<<lrand48>> and <<nrand48>> |
return values of type long in the range |
[0, 2**31-1]. The high-order (31) bits of |
r(n+1) are loaded into the lower bits of the returned value, with |
the topmost (sign) bit set to zero. |
|
<<mrand48>> and <<jrand48>> |
return values of type long in the range |
[-2**31, 2**31-1]. The high-order (32) bits of |
r(n+1) are loaded into the returned value. |
|
<<drand48>>, <<lrand48>>, and <<mrand48>> |
use an internal buffer to store r(n). For these functions |
the initial value of r(0) = 0x1234abcd330e = 20017429951246. |
|
On the other hand, <<erand48>>, <<nrand48>>, and <<jrand48>> |
use a user-supplied buffer to store the seed r(n), |
which consists of an array of 3 shorts, where the zeroth member |
holds the least significant bits. |
|
All functions share the same multiplicand and addend. |
|
<<srand48>> is used to initialize the internal buffer r(n) of |
<<drand48>>, <<lrand48>>, and <<mrand48>> |
such that the 32 bits of the seed value are copied into the upper 32 bits |
of r(n), with the lower 16 bits of r(n) arbitrarily being set to 0x330e. |
Additionally, the constant multiplicand and addend of the algorithm are |
reset to the default values given above. |
|
<<seed48>> also initializes the internal buffer r(n) of |
<<drand48>>, <<lrand48>>, and <<mrand48>>, |
but here all 48 bits of the seed can be specified in an array of 3 shorts, |
where the zeroth member specifies the lowest bits. Again, |
the constant multiplicand and addend of the algorithm are |
reset to the default values given above. |
<<seed48>> returns a pointer to an array of 3 shorts which contains |
the old seed. |
This array is statically allocated, thus its contents are lost after |
each new call to <<seed48>>. |
|
Finally, <<lcong48>> allows full control over the multiplicand and |
addend used in <<drand48>>, <<erand48>>, <<lrand48>>, <<nrand48>>, |
<<mrand48>>, and <<jrand48>>, |
and the seed used in <<drand48>>, <<lrand48>>, and <<mrand48>>. |
An array of 7 shorts is passed as parameter; the first three shorts are |
used to initialize the seed; the second three are used to initialize the |
multiplicand; and the last short is used to initialize the addend. |
It is thus not possible to use values greater than 0xffff as the addend. |
|
Note that all three methods of seeding the random number generator |
always also set the multiplicand and addend for any of the six |
generator calls. |
|
For a more powerful random number generator, see <<random>>. |
|
PORTABILITY |
SUS requires these functions. |
|
No supporting OS subroutines are required. |
*/ |
|
#include "rand48.h" |
|
void |
_DEFUN (__dorand48, (r, xseed), |
struct _reent *r _AND |
unsigned short xseed[3]) |
{ |
unsigned long accu; |
unsigned short temp[2]; |
|
accu = (unsigned long) __rand48_mult[0] * (unsigned long) xseed[0] + |
(unsigned long) __rand48_add; |
temp[0] = (unsigned short) accu; /* lower 16 bits */ |
accu >>= sizeof(unsigned short) * 8; |
accu += (unsigned long) __rand48_mult[0] * (unsigned long) xseed[1] + |
(unsigned long) __rand48_mult[1] * (unsigned long) xseed[0]; |
temp[1] = (unsigned short) accu; /* middle 16 bits */ |
accu >>= sizeof(unsigned short) * 8; |
accu += __rand48_mult[0] * xseed[2] + __rand48_mult[1] * xseed[1] + __rand48_mult[2] * xseed[0]; |
xseed[0] = temp[0]; |
xseed[1] = temp[1]; |
xseed[2] = (unsigned short) accu; |
} |
/assert.c
0,0 → 1,62
/* |
FUNCTION |
<<assert>>---Macro for Debugging Diagnostics |
|
INDEX |
assert |
|
ANSI_SYNOPSIS |
#include <assert.h> |
void assert(int <[expression]>); |
|
TRAD_SYNOPSIS |
#include <assert.h> |
assert(<[expression]>) |
int <[expression]>; |
|
DESCRIPTION |
Use this macro to embed debuggging diagnostic statements in |
your programs. The argument <[expression]> should be an |
expression which evaluates to true (nonzero) when your program |
is working as you intended. |
|
When <[expression]> evaluates to false (zero), <<assert>> |
calls <<abort>>, after first printing a message showing what |
failed and where: |
|
. Assertion failed: <[expression]>, file <[filename]>, line <[lineno]> |
|
The macro is defined to permit you to turn off all uses of |
<<assert>> at compile time by defining <<NDEBUG>> as a |
preprocessor variable. If you do this, the <<assert>> macro |
expands to |
|
. (void(0)) |
|
RETURNS |
<<assert>> does not return a value. |
|
PORTABILITY |
The <<assert>> macro is required by ANSI, as is the behavior |
when <<NDEBUG>> is defined. |
|
Supporting OS subroutines required (only if enabled): <<close>>, <<fstat>>, |
<<getpid>>, <<isatty>>, <<kill>>, <<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
#include <assert.h> |
#include <stdlib.h> |
#include <stdio.h> |
|
void |
_DEFUN (__assert, (file, line, failedexpr), |
const char *file _AND |
int line _AND |
const char *failedexpr) |
{ |
(void)fiprintf(stderr, |
"assertion \"%s\" failed: file \"%s\", line %d\n", |
failedexpr, file, line); |
abort(); |
/* NOTREACHED */ |
} |
/wcstombs.c
0,0 → 1,80
/* |
FUNCTION |
<<wcstombs>>---minimal wide char string to multibyte string converter |
|
INDEX |
wcstombs |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int wcstombs(const char *<[s]>, wchar_t *<[pwc]>, size_t <[n]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int wcstombs(<[s]>, <[pwc]>, <[n]>) |
const char *<[s]>; |
wchar_t *<[pwc]>; |
size_t <[n]>; |
|
DESCRIPTION |
When MB_CAPABLE is not defined, this is a minimal ANSI-conforming |
implementation of <<wcstombs>>. In this case, |
all wide-characters are expected to represent single bytes and so |
are converted simply by casting to char. |
|
When MB_CAPABLE is defined, this routine calls <<_wcstombs_r>> to perform |
the conversion, passing a state variable to allow state dependent |
decoding. The result is based on the locale setting which may |
be restricted to a defined set of locales. |
|
RETURNS |
This implementation of <<wcstombs>> returns <<0>> if |
<[s]> is <<NULL>> or is the empty string; |
it returns <<-1>> if MB_CAPABLE and one of the |
wide-char characters does not represent a valid multi-byte character; |
otherwise it returns the minimum of: <<n>> or the |
number of bytes that are transferred to <<s>>, not including the |
nul terminator. |
|
If the return value is -1, the state of the <<pwc>> string is |
indeterminate. If the input has a length of 0, the output |
string will be modified to contain a wchar_t nul terminator if |
<<n>> > 0. |
|
PORTABILITY |
<<wcstombs>> is required in the ANSI C standard. However, the precise |
effects vary with the locale. |
|
<<wcstombs>> requires no supporting OS subroutines. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
|
size_t |
_DEFUN (wcstombs, (s, pwcs, n), |
char *s _AND |
const wchar_t *pwcs _AND |
size_t n) |
{ |
#ifdef MB_CAPABLE |
int state = 0; |
|
return _wcstombs_r (_REENT, s, pwcs, n, &state); |
#else /* not MB_CAPABLE */ |
int count = 0; |
|
if (n != 0) { |
do { |
if ((*s++ = (char) *pwcs++) == 0) |
break; |
count++; |
} while (--n != 0); |
} |
|
return count; |
#endif /* not MB_CAPABLE */ |
} |
|
#endif /* !_REENT_ONLY */ |
/strdup_r.c
0,0 → 1,17
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
|
char * |
_DEFUN (_strdup_r, (reent_ptr, str), |
struct _reent *reent_ptr _AND |
_CONST char *str) |
{ |
size_t len = strlen (str) + 1; |
char *copy = _malloc_r (reent_ptr, len); |
if (copy) |
{ |
memcpy (copy, str, len); |
} |
return copy; |
} |
/rand_r.c
0,0 → 1,37
#include <stdlib.h> |
|
/* Pseudo-random generator based on Minimal Standard by |
Lewis, Goodman, and Miller in 1969. |
|
I[j+1] = a*I[j] (mod m) |
|
where a = 16807 |
m = 2147483647 |
|
Using Schrage's algorithm, a*I[j] (mod m) can be rewritten as: |
|
a*(I[j] mod q) - r*{I[j]/q} if >= 0 |
a*(I[j] mod q) - r*{I[j]/q} + m otherwise |
|
where: {} denotes integer division |
q = {m/a} = 127773 |
r = m (mod a) = 2836 |
|
note that the seed value of 0 cannot be used in the calculation as |
it results in 0 itself |
*/ |
|
int |
_DEFUN (rand_r, (seed), unsigned int *seed) |
{ |
long k; |
long s = (long)(*seed); |
if (s == 0) |
s = 0x12345987; |
k = s / 127773; |
s = 16807 * (s - k * 127773) - 2836 * k; |
if (s < 0) |
s += 2147483647; |
(*seed) = (unsigned int)s; |
return (int)(s & RAND_MAX); |
} |
/rand48.h
0,0 → 1,36
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#ifndef _RAND48_H_ |
#define _RAND48_H_ |
|
#include <math.h> |
#include <stdlib.h> |
|
extern void _EXFUN(__dorand48,(struct _reent *r, unsigned short[3])); |
#define __rand48_seed (r->_new._reent._r48._seed) |
#define __rand48_mult (r->_new._reent._r48._mult) |
#define __rand48_add (r->_new._reent._r48._add) |
|
#if 0 |
/* following values are defined in <sys/reent.h> */ |
#define RAND48_SEED_0 (0x330e) |
#define RAND48_SEED_1 (0xabcd) |
#define RAND48_SEED_2 (0x1234) |
#define RAND48_MULT_0 (0xe66d) |
#define RAND48_MULT_1 (0xdeec) |
#define RAND48_MULT_2 (0x0005) |
#define RAND48_ADD (0x000b) |
#endif |
|
#endif /* _RAND48_H_ */ |
/abort.c
0,0 → 1,67
/* NetWare can not use this implementation of abort. It provides its |
own version of abort in clib.nlm. If we can not use clib.nlm, then |
we must write abort in sys/netware. */ |
|
#ifdef ABORT_PROVIDED |
|
int _dummy_abort = 1; |
|
#else |
|
/* |
FUNCTION |
<<abort>>---abnormal termination of a program |
|
INDEX |
abort |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
void abort(void); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
void abort(); |
|
DESCRIPTION |
Use <<abort>> to signal that your program has detected a condition it |
cannot deal with. Normally, <<abort>> ends your program's execution. |
|
Before terminating your program, <<abort>> raises the exception <<SIGABRT>> |
(using `<<raise(SIGABRT)>>'). If you have used <<signal>> to register |
an exception handler for this condition, that handler has the |
opportunity to retain control, thereby avoiding program termination. |
|
In this implementation, <<abort>> does not perform any stream- or |
file-related cleanup (the host environment may do so; if not, you can |
arrange for your program to do its own cleanup with a <<SIGABRT>> |
exception handler). |
|
RETURNS |
<<abort>> does not return to its caller. |
|
PORTABILITY |
ANSI C requires <<abort>>. |
|
Supporting OS subroutines required: <<_exit>> and optionally, <<write>>. |
*/ |
|
#include <stdlib.h> |
#include <unistd.h> |
#include <signal.h> |
|
_VOID |
_DEFUN_VOID (abort) |
{ |
#ifdef ABORT_MESSAGE |
write (2, "Abort called\n", sizeof ("Abort called\n")-1); |
#endif |
|
while (1) |
{ |
raise (SIGABRT); |
_exit (1); |
} |
} |
|
#endif |
/getenv_r.c
0,0 → 1,133
/* |
FUNCTION |
<<_getenv_r>>---look up environment variable |
|
INDEX |
_getenv_r |
INDEX |
environ |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
char *_getenv_r(struct _reent *<[reent_ptr]>, const char *<[name]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
char *_getenv_r(<[reent_ptr]>, <[name]>) |
struct _reent *<[reent_ptr]>; |
char *<[name]>; |
|
DESCRIPTION |
<<_getenv_r>> searches the list of environment variable names and values |
(using the global pointer ``<<char **environ>>'') for a variable whose |
name matches the string at <[name]>. If a variable name matches, |
<<_getenv_r>> returns a pointer to the associated value. |
|
RETURNS |
A pointer to the (string) value of the environment variable, or |
<<NULL>> if there is no such environment variable. |
|
PORTABILITY |
<<_getenv_r>> is not ANSI; the rules for properly forming names of environment |
variables vary from one system to another. |
|
<<_getenv_r>> requires a global pointer <<environ>>. |
*/ |
|
/* This file may have been modified by DJ Delorie (Jan 1991). If so, |
** these modifications are Copyright (C) 1991 DJ Delorie |
*/ |
|
/* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that: (1) source distributions retain this entire copyright |
* notice and comment, and (2) distributions including binaries display |
* the following acknowledgement: ``This product includes software |
* developed by the University of California, Berkeley and its contributors'' |
* in the documentation or other materials provided with the distribution |
* and in all advertising materials mentioning features or use of this |
* software. Neither the name of the University nor the names of its |
* contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
#include <stdlib.h> |
#include <stddef.h> |
#include <string.h> |
#include "envlock.h" |
|
extern char **environ; |
|
/* Only deal with a pointer to environ, to work around subtle bugs with shared |
libraries and/or small data systems where the user declares his own |
'environ'. */ |
static char ***p_environ = &environ; |
|
/* |
* _findenv -- |
* Returns pointer to value associated with name, if any, else NULL. |
* Sets offset to be the offset of the name/value combination in the |
* environmental array, for use by setenv(3) and unsetenv(3). |
* Explicitly removes '=' in argument name. |
* |
* This routine *should* be a static; don't use it. |
*/ |
|
char * |
_DEFUN (_findenv_r, (reent_ptr, name, offset), |
struct _reent *reent_ptr _AND |
register _CONST char *name _AND |
int *offset) |
{ |
register int len; |
register char **p; |
_CONST char *c; |
|
ENV_LOCK; |
|
/* In some embedded systems, this does not get set. This protects |
newlib from dereferencing a bad pointer. */ |
if (!*p_environ) |
return NULL; |
|
c = name; |
len = 0; |
while (*c && *c != '=') |
{ |
c++; |
len++; |
} |
|
for (p = *p_environ; *p; ++p) |
if (!strncmp (*p, name, len)) |
if (*(c = *p + len) == '=') |
{ |
*offset = p - *p_environ; |
ENV_UNLOCK; |
return (char *) (++c); |
} |
ENV_UNLOCK; |
return NULL; |
} |
|
/* |
* _getenv_r -- |
* Returns ptr to value associated with name, if any, else NULL. |
*/ |
|
char * |
_DEFUN (_getenv_r, (reent_ptr, name), |
struct _reent *reent_ptr _AND |
_CONST char *name) |
{ |
int offset; |
char *_findenv_r (); |
|
return _findenv_r (reent_ptr, name, &offset); |
} |
/mblen_r.c
0,0 → 1,66
/* |
FUNCTION |
<<_mblen_r>>---reentrant minimal multibyte length function |
|
INDEX |
_mblen_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int _mblen_r(struct _reent *<[r]>, const char *<[s]>, size_t <[n]>, int *<[state]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int _mblen_r(<[r]>, <[s]>, <[n]>, <[state]>) |
struct _reent *<[r]>; |
const char *<[s]>; |
size_t <[n]>; |
int *<[state]>; |
|
DESCRIPTION |
When MB_CAPABLE is not defined, this is a minimal ANSI-conforming |
implementation of <<_mblen_r>>. In this case, the |
only ``multi-byte character sequences'' recognized are single bytes, |
and thus <<1>> is returned unless <[s]> is the null pointer or |
has a length of 0 or is the empty string. |
|
When MB_CAPABLE is defined, this routine calls <<_mbtowc_r>> to perform |
the conversion, passing a state variable to allow state dependent |
decoding. The result is based on the locale setting which may |
be restricted to a defined set of locales. |
|
RETURNS |
This implementation of <<_mblen_r>> returns <<0>> if |
<[s]> is <<NULL>> or the empty string; it returns <<1>> if not MB_CAPABLE or |
the character is a single-byte character; it returns <<-1>> |
if the multi-byte character is invalid; otherwise it returns |
the number of bytes in the multibyte character. |
|
PORTABILITY |
<<_mblen>> is required in the ANSI C standard. However, the precise |
effects vary with the locale. |
|
<<_mblen_r>> requires no supporting OS subroutines. |
*/ |
|
#include <stdlib.h> |
|
int |
_DEFUN (_mblen_r, (r, s, n, state), |
struct _reent *r _AND |
const char *s _AND |
size_t n _AND |
int *state) |
{ |
#ifdef MB_CAPABLE |
|
return _mbtowc_r (r, NULL, s, n, state); |
#else /* not MB_CAPABLE */ |
if (s == NULL || *s == '\0') |
return 0; |
if (n == 0) |
return -1; |
return 1; |
#endif /* not MB_CAPABLE */ |
} |
|
/valloc.c
0,0 → 1,24
/* valloc.c -- a wrapper for valloc_r and pvalloc_r. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
|
#ifndef _REENT_ONLY |
|
_PTR |
_DEFUN (valloc, (nbytes), |
size_t nbytes) |
{ |
return _valloc_r (_REENT, nbytes); |
} |
|
_PTR |
_DEFUN (pvalloc, (nbytes), |
size_t nbytes) |
{ |
return _pvalloc_r (_REENT, nbytes); |
} |
|
#endif |
/realloc.c
0,0 → 1,22
#ifdef MALLOC_PROVIDED |
int _dummy_calloc = 1; |
#else |
/* realloc.c -- a wrapper for realloc_r. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
|
#ifndef _REENT_ONLY |
|
_PTR |
_DEFUN (realloc, (ap, nbytes), |
_PTR ap _AND |
size_t nbytes) |
{ |
return _realloc_r (_REENT, ap, nbytes); |
} |
|
#endif |
#endif /* MALLOC_PROVIDED */ |
/strdup.c
0,0 → 1,13
#ifndef _REENT_ONLY |
|
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
|
char * |
_DEFUN (strdup, (str), _CONST char *str) |
{ |
return _strdup_r (_REENT, str); |
} |
|
#endif /* !_REENT_ONLY */ |
/mbstowcs_r.c
0,0 → 1,29
#include <stdlib.h> |
|
size_t |
_DEFUN (_mbstowcs_r, (reent, pwcs, s, n, state), |
struct _reent *r _AND |
wchar_t *pwcs _AND |
const char *s _AND |
size_t n _AND |
int *state) |
{ |
wchar_t *ptr = pwcs; |
size_t max = n; |
char *t = (char *)s; |
int bytes; |
|
while (n > 0) |
{ |
bytes = _mbtowc_r (r, ptr, t, MB_CUR_MAX, state); |
if (bytes == -1) |
return -1; |
else if (bytes == 0) |
return ptr - pwcs; |
t += bytes; |
++ptr; |
--n; |
} |
|
return max; |
} |
/setenv_r.c
0,0 → 1,143
/* This file may have been modified by DJ Delorie (Jan 1991). If so, |
** these modifications are Copyright (C) 1991 DJ Delorie |
*/ |
|
/* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that: (1) source distributions retain this entire copyright |
* notice and comment, and (2) distributions including binaries display |
* the following acknowledgement: ``This product includes software |
* developed by the University of California, Berkeley and its contributors'' |
* in the documentation or other materials provided with the distribution |
* and in all advertising materials mentioning features or use of this |
* software. Neither the name of the University nor the names of its |
* contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
#include <reent.h> |
|
#include <stddef.h> |
#include <stdlib.h> |
#include <string.h> |
#include "envlock.h" |
|
extern char **environ; |
|
/* Only deal with a pointer to environ, to work around subtle bugs with shared |
libraries and/or small data systems where the user declares his own |
'environ'. */ |
static char ***p_environ = &environ; |
|
/* _findenv_r is defined in getenv_r.c. */ |
extern char *_findenv_r _PARAMS ((struct _reent *, const char *, int *)); |
|
/* |
* _setenv_r -- |
* Set the value of the environmental variable "name" to be |
* "value". If rewrite is set, replace any current value. |
*/ |
|
int |
_DEFUN (_setenv_r, (reent_ptr, name, value, rewrite), |
struct _reent *reent_ptr _AND |
_CONST char *name _AND |
_CONST char *value _AND |
int rewrite) |
{ |
static int alloced; /* if allocated space before */ |
register char *C; |
int l_value, offset; |
|
ENV_LOCK; |
|
if (*value == '=') /* no `=' in value */ |
++value; |
l_value = strlen (value); |
if ((C = _findenv_r (reent_ptr, name, &offset))) |
{ /* find if already exists */ |
if (!rewrite) |
{ |
ENV_UNLOCK; |
return 0; |
} |
if (strlen (C) >= l_value) |
{ /* old larger; copy over */ |
while ((*C++ = *value++) != 0); |
ENV_UNLOCK; |
return 0; |
} |
} |
else |
{ /* create new slot */ |
register int cnt; |
register char **P; |
|
for (P = *p_environ, cnt = 0; *P; ++P, ++cnt); |
if (alloced) |
{ /* just increase size */ |
*p_environ = (char **) _realloc_r (reent_ptr, (char *) environ, |
(size_t) (sizeof (char *) * (cnt + 2))); |
if (!*p_environ) |
{ |
ENV_UNLOCK; |
return -1; |
} |
} |
else |
{ /* get new space */ |
alloced = 1; /* copy old entries into it */ |
P = (char **) _malloc_r (reent_ptr, (size_t) (sizeof (char *) * (cnt + 2))); |
if (!P) |
{ |
ENV_UNLOCK; |
return (-1); |
} |
bcopy ((char *) *p_environ, (char *) P, cnt * sizeof (char *)); |
*p_environ = P; |
} |
(*p_environ)[cnt + 1] = NULL; |
offset = cnt; |
} |
for (C = (char *) name; *C && *C != '='; ++C); /* no `=' in name */ |
if (!((*p_environ)[offset] = /* name + `=' + value */ |
_malloc_r (reent_ptr, (size_t) ((int) (C - name) + l_value + 2)))) |
{ |
ENV_UNLOCK; |
return -1; |
} |
for (C = (*p_environ)[offset]; (*C = *name++) && *C != '='; ++C); |
for (*C++ = '='; (*C++ = *value++) != 0;); |
|
ENV_UNLOCK; |
|
return 0; |
} |
|
/* |
* _unsetenv_r(name) -- |
* Delete environmental variable "name". |
*/ |
void |
_DEFUN (_unsetenv_r, (reent_ptr, name), |
struct _reent *reent_ptr _AND |
_CONST char *name) |
{ |
register char **P; |
int offset; |
|
ENV_LOCK; |
|
while (_findenv_r (reent_ptr, name, &offset)) /* if set multiple times */ |
for (P = &(*p_environ)[offset];; ++P) |
if (!(*P = *(P + 1))) |
break; |
|
ENV_UNLOCK; |
} |
/__adjust.c
0,0 → 1,44
/* |
* return (*acc) scaled by 10**dexp. |
*/ |
|
#include <_ansi.h> |
#include <reent.h> |
#include "std.h" |
|
#define abs(x) (((x) < 0) ? -(x) : (x)) |
|
double |
_DEFUN (__adjust, (ptr, acc, dexp, sign), |
struct _reent *ptr _AND |
double *acc _AND |
int dexp _AND |
int sign) |
/* *acc the 64 bit accumulator */ |
/* dexp decimal exponent */ |
/* sign sign flag */ |
{ |
double r; |
|
if (dexp > MAXE) |
{ |
ptr->_errno = ERANGE; |
return (sign) ? -HUGE_VAL : HUGE_VAL; |
} |
else if (dexp < MINE) |
{ |
ptr->_errno = ERANGE; |
return 0.0; |
} |
|
r = *acc; |
if (sign) |
r = -r; |
if (dexp == 0) |
return r; |
|
if (dexp < 0) |
return r / __exp10 (abs (dexp)); |
else |
return r * __exp10 (dexp); |
} |
/mallocr.c
0,0 → 1,3651
#ifdef MALLOC_PROVIDED |
int _dummy_mallocr = 1; |
#else |
/* ---------- To make a malloc.h, start cutting here ------------ */ |
|
/* |
A version of malloc/free/realloc written by Doug Lea and released to the |
public domain. Send questions/comments/complaints/performance data |
to dl@cs.oswego.edu |
|
* VERSION 2.6.4 Thu Nov 28 07:54:55 1996 Doug Lea (dl at gee) |
|
Note: There may be an updated version of this malloc obtainable at |
ftp://g.oswego.edu/pub/misc/malloc.c |
Check before installing! |
|
* Why use this malloc? |
|
This is not the fastest, most space-conserving, most portable, or |
most tunable malloc ever written. However it is among the fastest |
while also being among the most space-conserving, portable and tunable. |
Consistent balance across these factors results in a good general-purpose |
allocator. For a high-level description, see |
http://g.oswego.edu/dl/html/malloc.html |
|
* Synopsis of public routines |
|
(Much fuller descriptions are contained in the program documentation below.) |
|
malloc(size_t n); |
Return a pointer to a newly allocated chunk of at least n bytes, or null |
if no space is available. |
free(Void_t* p); |
Release the chunk of memory pointed to by p, or no effect if p is null. |
realloc(Void_t* p, size_t n); |
Return a pointer to a chunk of size n that contains the same data |
as does chunk p up to the minimum of (n, p's size) bytes, or null |
if no space is available. The returned pointer may or may not be |
the same as p. If p is null, equivalent to malloc. Unless the |
#define REALLOC_ZERO_BYTES_FREES below is set, realloc with a |
size argument of zero (re)allocates a minimum-sized chunk. |
memalign(size_t alignment, size_t n); |
Return a pointer to a newly allocated chunk of n bytes, aligned |
in accord with the alignment argument, which must be a power of |
two. |
valloc(size_t n); |
Equivalent to memalign(pagesize, n), where pagesize is the page |
size of the system (or as near to this as can be figured out from |
all the includes/defines below.) |
pvalloc(size_t n); |
Equivalent to valloc(minimum-page-that-holds(n)), that is, |
round up n to nearest pagesize. |
calloc(size_t unit, size_t quantity); |
Returns a pointer to quantity * unit bytes, with all locations |
set to zero. |
cfree(Void_t* p); |
Equivalent to free(p). |
malloc_trim(size_t pad); |
Release all but pad bytes of freed top-most memory back |
to the system. Return 1 if successful, else 0. |
malloc_usable_size(Void_t* p); |
Report the number usable allocated bytes associated with allocated |
chunk p. This may or may not report more bytes than were requested, |
due to alignment and minimum size constraints. |
malloc_stats(); |
Prints brief summary statistics on stderr. |
mallinfo() |
Returns (by copy) a struct containing various summary statistics. |
mallopt(int parameter_number, int parameter_value) |
Changes one of the tunable parameters described below. Returns |
1 if successful in changing the parameter, else 0. |
|
* Vital statistics: |
|
Alignment: 8-byte |
8 byte alignment is currently hardwired into the design. This |
seems to suffice for all current machines and C compilers. |
|
Assumed pointer representation: 4 or 8 bytes |
Code for 8-byte pointers is untested by me but has worked |
reliably by Wolfram Gloger, who contributed most of the |
changes supporting this. |
|
Assumed size_t representation: 4 or 8 bytes |
Note that size_t is allowed to be 4 bytes even if pointers are 8. |
|
Minimum overhead per allocated chunk: 4 or 8 bytes |
Each malloced chunk has a hidden overhead of 4 bytes holding size |
and status information. |
|
Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) |
8-byte ptrs: 24/32 bytes (including, 4/8 overhead) |
|
When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte |
ptrs but 4 byte size) or 24 (for 8/8) additional bytes are |
needed; 4 (8) for a trailing size field |
and 8 (16) bytes for free list pointers. Thus, the minimum |
allocatable size is 16/24/32 bytes. |
|
Even a request for zero bytes (i.e., malloc(0)) returns a |
pointer to something of the minimum allocatable size. |
|
Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes |
8-byte size_t: 2^63 - 16 bytes |
|
It is assumed that (possibly signed) size_t bit values suffice to |
represent chunk sizes. `Possibly signed' is due to the fact |
that `size_t' may be defined on a system as either a signed or |
an unsigned type. To be conservative, values that would appear |
as negative numbers are avoided. |
Requests for sizes with a negative sign bit will return a |
minimum-sized chunk. |
|
Maximum overhead wastage per allocated chunk: normally 15 bytes |
|
Alignnment demands, plus the minimum allocatable size restriction |
make the normal worst-case wastage 15 bytes (i.e., up to 15 |
more bytes will be allocated than were requested in malloc), with |
two exceptions: |
1. Because requests for zero bytes allocate non-zero space, |
the worst case wastage for a request of zero bytes is 24 bytes. |
2. For requests >= mmap_threshold that are serviced via |
mmap(), the worst case wastage is 8 bytes plus the remainder |
from a system page (the minimal mmap unit); typically 4096 bytes. |
|
* Limitations |
|
Here are some features that are NOT currently supported |
|
* No user-definable hooks for callbacks and the like. |
* No automated mechanism for fully checking that all accesses |
to malloced memory stay within their bounds. |
* No support for compaction. |
|
* Synopsis of compile-time options: |
|
People have reported using previous versions of this malloc on all |
versions of Unix, sometimes by tweaking some of the defines |
below. It has been tested most extensively on Solaris and |
Linux. It is also reported to work on WIN32 platforms. |
People have also reported adapting this malloc for use in |
stand-alone embedded systems. |
|
The implementation is in straight, hand-tuned ANSI C. Among other |
consequences, it uses a lot of macros. Because of this, to be at |
all usable, this code should be compiled using an optimizing compiler |
(for example gcc -O2) that can simplify expressions and control |
paths. |
|
__STD_C (default: derived from C compiler defines) |
Nonzero if using ANSI-standard C compiler, a C++ compiler, or |
a C compiler sufficiently close to ANSI to get away with it. |
DEBUG (default: NOT defined) |
Define to enable debugging. Adds fairly extensive assertion-based |
checking to help track down memory errors, but noticeably slows down |
execution. |
SEPARATE_OBJECTS (default: NOT defined) |
Define this to compile into separate .o files. You must then |
compile malloc.c several times, defining a DEFINE_* macro each |
time. The list of DEFINE_* macros appears below. |
MALLOC_LOCK (default: NOT defined) |
MALLOC_UNLOCK (default: NOT defined) |
Define these to C expressions which are run to lock and unlock |
the malloc data structures. Calls may be nested; that is, |
MALLOC_LOCK may be called more than once before the corresponding |
MALLOC_UNLOCK calls. MALLOC_LOCK must avoid waiting for a lock |
that it already holds. |
MALLOC_ALIGNMENT (default: NOT defined) |
Define this to 16 if you need 16 byte alignment instead of 8 byte alignment |
which is the normal default. |
SIZE_T_SMALLER_THAN_LONG (default: NOT defined) |
Define this when the platform you are compiling has sizeof(long) > sizeof(size_t). |
The option causes some extra code to be generated to handle operations |
that use size_t operands and have long results. |
REALLOC_ZERO_BYTES_FREES (default: NOT defined) |
Define this if you think that realloc(p, 0) should be equivalent |
to free(p). Otherwise, since malloc returns a unique pointer for |
malloc(0), so does realloc(p, 0). |
HAVE_MEMCPY (default: defined) |
Define if you are not otherwise using ANSI STD C, but still |
have memcpy and memset in your C library and want to use them. |
Otherwise, simple internal versions are supplied. |
USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) |
Define as 1 if you want the C library versions of memset and |
memcpy called in realloc and calloc (otherwise macro versions are used). |
At least on some platforms, the simple macro versions usually |
outperform libc versions. |
HAVE_MMAP (default: defined as 1) |
Define to non-zero to optionally make malloc() use mmap() to |
allocate very large blocks. |
HAVE_MREMAP (default: defined as 0 unless Linux libc set) |
Define to non-zero to optionally make realloc() use mremap() to |
reallocate very large blocks. |
malloc_getpagesize (default: derived from system #includes) |
Either a constant or routine call returning the system page size. |
HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) |
Optionally define if you are on a system with a /usr/include/malloc.h |
that declares struct mallinfo. It is not at all necessary to |
define this even if you do, but will ensure consistency. |
INTERNAL_SIZE_T (default: size_t) |
Define to a 32-bit type (probably `unsigned int') if you are on a |
64-bit machine, yet do not want or need to allow malloc requests of |
greater than 2^31 to be handled. This saves space, especially for |
very small chunks. |
INTERNAL_LINUX_C_LIB (default: NOT defined) |
Defined only when compiled as part of Linux libc. |
Also note that there is some odd internal name-mangling via defines |
(for example, internally, `malloc' is named `mALLOc') needed |
when compiling in this case. These look funny but don't otherwise |
affect anything. |
INTERNAL_NEWLIB (default: NOT defined) |
Defined only when compiled as part of the Cygnus newlib |
distribution. |
WIN32 (default: undefined) |
Define this on MS win (95, nt) platforms to compile in sbrk emulation. |
LACKS_UNISTD_H (default: undefined) |
Define this if your system does not have a <unistd.h>. |
MORECORE (default: sbrk) |
The name of the routine to call to obtain more memory from the system. |
MORECORE_FAILURE (default: -1) |
The value returned upon failure of MORECORE. |
MORECORE_CLEARS (default 1) |
True (1) if the routine mapped to MORECORE zeroes out memory (which |
holds for sbrk). |
DEFAULT_TRIM_THRESHOLD |
DEFAULT_TOP_PAD |
DEFAULT_MMAP_THRESHOLD |
DEFAULT_MMAP_MAX |
Default values of tunable parameters (described in detail below) |
controlling interaction with host system routines (sbrk, mmap, etc). |
These values may also be changed dynamically via mallopt(). The |
preset defaults are those that give best performance for typical |
programs/systems. |
|
|
*/ |
|
|
|
|
/* Preliminaries */ |
|
#ifndef __STD_C |
#ifdef __STDC__ |
#define __STD_C 1 |
#else |
#if __cplusplus |
#define __STD_C 1 |
#else |
#define __STD_C 0 |
#endif /*__cplusplus*/ |
#endif /*__STDC__*/ |
#endif /*__STD_C*/ |
|
#ifndef Void_t |
#if __STD_C |
#define Void_t void |
#else |
#define Void_t char |
#endif |
#endif /*Void_t*/ |
|
#if __STD_C |
#include <stddef.h> /* for size_t */ |
#else |
#include <sys/types.h> |
#endif |
|
#ifdef __cplusplus |
extern "C" { |
#endif |
|
#include <stdio.h> /* needed for malloc_stats */ |
|
|
/* |
Compile-time options |
*/ |
|
|
/* |
|
Special defines for Cygnus newlib distribution. |
|
*/ |
|
#ifdef INTERNAL_NEWLIB |
|
#include <sys/config.h> |
|
/* |
In newlib, all the publically visible routines take a reentrancy |
pointer. We don't currently do anything much with it, but we do |
pass it to the lock routine. |
*/ |
|
#include <reent.h> |
|
#define POINTER_UINT unsigned _POINTER_INT |
#define SEPARATE_OBJECTS |
#define HAVE_MMAP 0 |
#define MORECORE(size) _sbrk_r(reent_ptr, (size)) |
#define MORECORE_CLEARS 0 |
#define MALLOC_LOCK __malloc_lock(reent_ptr) |
#define MALLOC_UNLOCK __malloc_unlock(reent_ptr) |
|
#ifdef __CYGWIN__ |
# undef _WIN32 |
# undef WIN32 |
#endif |
|
#ifndef _WIN32 |
#ifdef SMALL_MEMORY |
#define malloc_getpagesize (128) |
#else |
#define malloc_getpagesize (4096) |
#endif |
#endif |
|
#if __STD_C |
extern void __malloc_lock(struct _reent *); |
extern void __malloc_unlock(struct _reent *); |
#else |
extern void __malloc_lock(); |
extern void __malloc_unlock(); |
#endif |
|
#if __STD_C |
#define RARG struct _reent *reent_ptr, |
#define RONEARG struct _reent *reent_ptr |
#else |
#define RARG reent_ptr |
#define RONEARG reent_ptr |
#define RDECL struct _reent *reent_ptr; |
#endif |
|
#define RCALL reent_ptr, |
#define RONECALL reent_ptr |
|
#else /* ! INTERNAL_NEWLIB */ |
|
#define POINTER_UINT unsigned long |
#define RARG |
#define RONEARG |
#define RDECL |
#define RCALL |
#define RONECALL |
|
#endif /* ! INTERNAL_NEWLIB */ |
|
/* |
Debugging: |
|
Because freed chunks may be overwritten with link fields, this |
malloc will often die when freed memory is overwritten by user |
programs. This can be very effective (albeit in an annoying way) |
in helping track down dangling pointers. |
|
If you compile with -DDEBUG, a number of assertion checks are |
enabled that will catch more memory errors. You probably won't be |
able to make much sense of the actual assertion errors, but they |
should help you locate incorrectly overwritten memory. The |
checking is fairly extensive, and will slow down execution |
noticeably. Calling malloc_stats or mallinfo with DEBUG set will |
attempt to check every non-mmapped allocated and free chunk in the |
course of computing the summmaries. (By nature, mmapped regions |
cannot be checked very much automatically.) |
|
Setting DEBUG may also be helpful if you are trying to modify |
this code. The assertions in the check routines spell out in more |
detail the assumptions and invariants underlying the algorithms. |
|
*/ |
|
#if DEBUG |
#include <assert.h> |
#else |
#define assert(x) ((void)0) |
#endif |
|
|
/* |
SEPARATE_OBJECTS should be defined if you want each function to go |
into a separate .o file. You must then compile malloc.c once per |
function, defining the appropriate DEFINE_ macro. See below for the |
list of macros. |
*/ |
|
#ifndef SEPARATE_OBJECTS |
#define DEFINE_MALLOC |
#define DEFINE_FREE |
#define DEFINE_REALLOC |
#define DEFINE_CALLOC |
#define DEFINE_CFREE |
#define DEFINE_MEMALIGN |
#define DEFINE_VALLOC |
#define DEFINE_PVALLOC |
#define DEFINE_MALLINFO |
#define DEFINE_MALLOC_STATS |
#define DEFINE_MALLOC_USABLE_SIZE |
#define DEFINE_MALLOPT |
|
#define STATIC static |
#else |
#define STATIC |
#endif |
|
/* |
Define MALLOC_LOCK and MALLOC_UNLOCK to C expressions to run to |
lock and unlock the malloc data structures. MALLOC_LOCK may be |
called recursively. |
*/ |
|
#ifndef MALLOC_LOCK |
#define MALLOC_LOCK |
#endif |
|
#ifndef MALLOC_UNLOCK |
#define MALLOC_UNLOCK |
#endif |
|
/* |
INTERNAL_SIZE_T is the word-size used for internal bookkeeping |
of chunk sizes. On a 64-bit machine, you can reduce malloc |
overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' |
at the expense of not being able to handle requests greater than |
2^31. This limitation is hardly ever a concern; you are encouraged |
to set this. However, the default version is the same as size_t. |
*/ |
|
#ifndef INTERNAL_SIZE_T |
#define INTERNAL_SIZE_T size_t |
#endif |
|
/* |
Following is needed on implementations whereby long > size_t. |
The problem is caused because the code performs subtractions of |
size_t values and stores the result in long values. In the case |
where long > size_t and the first value is actually less than |
the second value, the resultant value is positive. For example, |
(long)(x - y) where x = 0 and y is 1 ends up being 0x00000000FFFFFFFF |
which is 2*31 - 1 instead of 0xFFFFFFFFFFFFFFFF. This is due to the |
fact that assignment from unsigned to signed won't sign extend. |
*/ |
|
#ifdef SIZE_T_SMALLER_THAN_LONG |
#define long_sub_size_t(x, y) ( (x < y) ? -((long)(y - x)) : (x - y) ); |
#else |
#define long_sub_size_t(x, y) ( (long)(x - y) ) |
#endif |
|
/* |
REALLOC_ZERO_BYTES_FREES should be set if a call to |
realloc with zero bytes should be the same as a call to free. |
Some people think it should. Otherwise, since this malloc |
returns a unique pointer for malloc(0), so does realloc(p, 0). |
*/ |
|
|
/* #define REALLOC_ZERO_BYTES_FREES */ |
|
|
/* |
WIN32 causes an emulation of sbrk to be compiled in |
mmap-based options are not currently supported in WIN32. |
*/ |
|
/* #define WIN32 */ |
#ifdef WIN32 |
#define MORECORE wsbrk |
#define HAVE_MMAP 0 |
#endif |
|
|
/* |
HAVE_MEMCPY should be defined if you are not otherwise using |
ANSI STD C, but still have memcpy and memset in your C library |
and want to use them in calloc and realloc. Otherwise simple |
macro versions are defined here. |
|
USE_MEMCPY should be defined as 1 if you actually want to |
have memset and memcpy called. People report that the macro |
versions are often enough faster than libc versions on many |
systems that it is better to use them. |
|
*/ |
|
#define HAVE_MEMCPY |
|
#ifndef USE_MEMCPY |
#ifdef HAVE_MEMCPY |
#define USE_MEMCPY 1 |
#else |
#define USE_MEMCPY 0 |
#endif |
#endif |
|
#if (__STD_C || defined(HAVE_MEMCPY)) |
|
#if __STD_C |
void* memset(void*, int, size_t); |
void* memcpy(void*, const void*, size_t); |
#else |
Void_t* memset(); |
Void_t* memcpy(); |
#endif |
#endif |
|
#if USE_MEMCPY |
|
/* The following macros are only invoked with (2n+1)-multiples of |
INTERNAL_SIZE_T units, with a positive integer n. This is exploited |
for fast inline execution when n is small. */ |
|
#define MALLOC_ZERO(charp, nbytes) \ |
do { \ |
INTERNAL_SIZE_T mzsz = (nbytes); \ |
if(mzsz <= 9*sizeof(mzsz)) { \ |
INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ |
if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ |
*mz++ = 0; \ |
if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ |
*mz++ = 0; \ |
if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ |
*mz++ = 0; }}} \ |
*mz++ = 0; \ |
*mz++ = 0; \ |
*mz = 0; \ |
} else memset((charp), 0, mzsz); \ |
} while(0) |
|
#define MALLOC_COPY(dest,src,nbytes) \ |
do { \ |
INTERNAL_SIZE_T mcsz = (nbytes); \ |
if(mcsz <= 9*sizeof(mcsz)) { \ |
INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ |
INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ |
if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
*mcdst++ = *mcsrc++; \ |
if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
*mcdst++ = *mcsrc++; \ |
if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ |
*mcdst++ = *mcsrc++; }}} \ |
*mcdst++ = *mcsrc++; \ |
*mcdst++ = *mcsrc++; \ |
*mcdst = *mcsrc ; \ |
} else memcpy(dest, src, mcsz); \ |
} while(0) |
|
#else /* !USE_MEMCPY */ |
|
/* Use Duff's device for good zeroing/copying performance. */ |
|
#define MALLOC_ZERO(charp, nbytes) \ |
do { \ |
INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ |
long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ |
if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ |
switch (mctmp) { \ |
case 0: for(;;) { *mzp++ = 0; \ |
case 7: *mzp++ = 0; \ |
case 6: *mzp++ = 0; \ |
case 5: *mzp++ = 0; \ |
case 4: *mzp++ = 0; \ |
case 3: *mzp++ = 0; \ |
case 2: *mzp++ = 0; \ |
case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ |
} \ |
} while(0) |
|
#define MALLOC_COPY(dest,src,nbytes) \ |
do { \ |
INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ |
INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ |
long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ |
if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ |
switch (mctmp) { \ |
case 0: for(;;) { *mcdst++ = *mcsrc++; \ |
case 7: *mcdst++ = *mcsrc++; \ |
case 6: *mcdst++ = *mcsrc++; \ |
case 5: *mcdst++ = *mcsrc++; \ |
case 4: *mcdst++ = *mcsrc++; \ |
case 3: *mcdst++ = *mcsrc++; \ |
case 2: *mcdst++ = *mcsrc++; \ |
case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ |
} \ |
} while(0) |
|
#endif |
|
|
/* |
Define HAVE_MMAP to optionally make malloc() use mmap() to |
allocate very large blocks. These will be returned to the |
operating system immediately after a free(). |
*/ |
|
#ifndef HAVE_MMAP |
#define HAVE_MMAP 1 |
#endif |
|
/* |
Define HAVE_MREMAP to make realloc() use mremap() to re-allocate |
large blocks. This is currently only possible on Linux with |
kernel versions newer than 1.3.77. |
*/ |
|
#ifndef HAVE_MREMAP |
#ifdef INTERNAL_LINUX_C_LIB |
#define HAVE_MREMAP 1 |
#else |
#define HAVE_MREMAP 0 |
#endif |
#endif |
|
#if HAVE_MMAP |
|
#include <unistd.h> |
#include <fcntl.h> |
#include <sys/mman.h> |
|
#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
#define MAP_ANONYMOUS MAP_ANON |
#endif |
|
#endif /* HAVE_MMAP */ |
|
/* |
Access to system page size. To the extent possible, this malloc |
manages memory from the system in page-size units. |
|
The following mechanics for getpagesize were adapted from |
bsd/gnu getpagesize.h |
*/ |
|
#ifndef LACKS_UNISTD_H |
# include <unistd.h> |
#endif |
|
#ifndef malloc_getpagesize |
# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ |
# ifndef _SC_PAGE_SIZE |
# define _SC_PAGE_SIZE _SC_PAGESIZE |
# endif |
# endif |
# ifdef _SC_PAGE_SIZE |
# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) |
# else |
# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) |
extern size_t getpagesize(); |
# define malloc_getpagesize getpagesize() |
# else |
# include <sys/param.h> |
# ifdef EXEC_PAGESIZE |
# define malloc_getpagesize EXEC_PAGESIZE |
# else |
# ifdef NBPG |
# ifndef CLSIZE |
# define malloc_getpagesize NBPG |
# else |
# define malloc_getpagesize (NBPG * CLSIZE) |
# endif |
# else |
# ifdef NBPC |
# define malloc_getpagesize NBPC |
# else |
# ifdef PAGESIZE |
# define malloc_getpagesize PAGESIZE |
# else |
# define malloc_getpagesize (4096) /* just guess */ |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
#endif |
|
|
|
/* |
|
This version of malloc supports the standard SVID/XPG mallinfo |
routine that returns a struct containing the same kind of |
information you can get from malloc_stats. It should work on |
any SVID/XPG compliant system that has a /usr/include/malloc.h |
defining struct mallinfo. (If you'd like to install such a thing |
yourself, cut out the preliminary declarations as described above |
and below and save them in a malloc.h file. But there's no |
compelling reason to bother to do this.) |
|
The main declaration needed is the mallinfo struct that is returned |
(by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a |
bunch of fields, most of which are not even meaningful in this |
version of malloc. Some of these fields are are instead filled by |
mallinfo() with other numbers that might possibly be of interest. |
|
HAVE_USR_INCLUDE_MALLOC_H should be set if you have a |
/usr/include/malloc.h file that includes a declaration of struct |
mallinfo. If so, it is included; else an SVID2/XPG2 compliant |
version is declared below. These must be precisely the same for |
mallinfo() to work. |
|
*/ |
|
/* #define HAVE_USR_INCLUDE_MALLOC_H */ |
|
#if HAVE_USR_INCLUDE_MALLOC_H |
#include "/usr/include/malloc.h" |
#else |
|
/* SVID2/XPG mallinfo structure */ |
|
struct mallinfo { |
int arena; /* total space allocated from system */ |
int ordblks; /* number of non-inuse chunks */ |
int smblks; /* unused -- always zero */ |
int hblks; /* number of mmapped regions */ |
int hblkhd; /* total space in mmapped regions */ |
int usmblks; /* unused -- always zero */ |
int fsmblks; /* unused -- always zero */ |
int uordblks; /* total allocated space */ |
int fordblks; /* total non-inuse space */ |
int keepcost; /* top-most, releasable (via malloc_trim) space */ |
}; |
|
/* SVID2/XPG mallopt options */ |
|
#define M_MXFAST 1 /* UNUSED in this malloc */ |
#define M_NLBLKS 2 /* UNUSED in this malloc */ |
#define M_GRAIN 3 /* UNUSED in this malloc */ |
#define M_KEEP 4 /* UNUSED in this malloc */ |
|
#endif |
|
/* mallopt options that actually do something */ |
|
#define M_TRIM_THRESHOLD -1 |
#define M_TOP_PAD -2 |
#define M_MMAP_THRESHOLD -3 |
#define M_MMAP_MAX -4 |
|
|
|
#ifndef DEFAULT_TRIM_THRESHOLD |
#define DEFAULT_TRIM_THRESHOLD (128L * 1024L) |
#endif |
|
/* |
M_TRIM_THRESHOLD is the maximum amount of unused top-most memory |
to keep before releasing via malloc_trim in free(). |
|
Automatic trimming is mainly useful in long-lived programs. |
Because trimming via sbrk can be slow on some systems, and can |
sometimes be wasteful (in cases where programs immediately |
afterward allocate more large chunks) the value should be high |
enough so that your overall system performance would improve by |
releasing. |
|
The trim threshold and the mmap control parameters (see below) |
can be traded off with one another. Trimming and mmapping are |
two different ways of releasing unused memory back to the |
system. Between these two, it is often possible to keep |
system-level demands of a long-lived program down to a bare |
minimum. For example, in one test suite of sessions measuring |
the XF86 X server on Linux, using a trim threshold of 128K and a |
mmap threshold of 192K led to near-minimal long term resource |
consumption. |
|
If you are using this malloc in a long-lived program, it should |
pay to experiment with these values. As a rough guide, you |
might set to a value close to the average size of a process |
(program) running on your system. Releasing this much memory |
would allow such a process to run in memory. Generally, it's |
worth it to tune for trimming rather tham memory mapping when a |
program undergoes phases where several large chunks are |
allocated and released in ways that can reuse each other's |
storage, perhaps mixed with phases where there are no such |
chunks at all. And in well-behaved long-lived programs, |
controlling release of large blocks via trimming versus mapping |
is usually faster. |
|
However, in most programs, these parameters serve mainly as |
protection against the system-level effects of carrying around |
massive amounts of unneeded memory. Since frequent calls to |
sbrk, mmap, and munmap otherwise degrade performance, the default |
parameters are set to relatively high values that serve only as |
safeguards. |
|
The default trim value is high enough to cause trimming only in |
fairly extreme (by current memory consumption standards) cases. |
It must be greater than page size to have any useful effect. To |
disable trimming completely, you can set to (unsigned long)(-1); |
|
|
*/ |
|
|
#ifndef DEFAULT_TOP_PAD |
#define DEFAULT_TOP_PAD (0) |
#endif |
|
/* |
M_TOP_PAD is the amount of extra `padding' space to allocate or |
retain whenever sbrk is called. It is used in two ways internally: |
|
* When sbrk is called to extend the top of the arena to satisfy |
a new malloc request, this much padding is added to the sbrk |
request. |
|
* When malloc_trim is called automatically from free(), |
it is used as the `pad' argument. |
|
In both cases, the actual amount of padding is rounded |
so that the end of the arena is always a system page boundary. |
|
The main reason for using padding is to avoid calling sbrk so |
often. Having even a small pad greatly reduces the likelihood |
that nearly every malloc request during program start-up (or |
after trimming) will invoke sbrk, which needlessly wastes |
time. |
|
Automatic rounding-up to page-size units is normally sufficient |
to avoid measurable overhead, so the default is 0. However, in |
systems where sbrk is relatively slow, it can pay to increase |
this value, at the expense of carrying around more memory than |
the program needs. |
|
*/ |
|
|
#ifndef DEFAULT_MMAP_THRESHOLD |
#define DEFAULT_MMAP_THRESHOLD (128 * 1024) |
#endif |
|
/* |
|
M_MMAP_THRESHOLD is the request size threshold for using mmap() |
to service a request. Requests of at least this size that cannot |
be allocated using already-existing space will be serviced via mmap. |
(If enough normal freed space already exists it is used instead.) |
|
Using mmap segregates relatively large chunks of memory so that |
they can be individually obtained and released from the host |
system. A request serviced through mmap is never reused by any |
other request (at least not directly; the system may just so |
happen to remap successive requests to the same locations). |
|
Segregating space in this way has the benefit that mmapped space |
can ALWAYS be individually released back to the system, which |
helps keep the system level memory demands of a long-lived |
program low. Mapped memory can never become `locked' between |
other chunks, as can happen with normally allocated chunks, which |
menas that even trimming via malloc_trim would not release them. |
|
However, it has the disadvantages that: |
|
1. The space cannot be reclaimed, consolidated, and then |
used to service later requests, as happens with normal chunks. |
2. It can lead to more wastage because of mmap page alignment |
requirements |
3. It causes malloc performance to be more dependent on host |
system memory management support routines which may vary in |
implementation quality and may impose arbitrary |
limitations. Generally, servicing a request via normal |
malloc steps is faster than going through a system's mmap. |
|
All together, these considerations should lead you to use mmap |
only for relatively large requests. |
|
|
*/ |
|
|
|
#ifndef DEFAULT_MMAP_MAX |
#if HAVE_MMAP |
#define DEFAULT_MMAP_MAX (64) |
#else |
#define DEFAULT_MMAP_MAX (0) |
#endif |
#endif |
|
/* |
M_MMAP_MAX is the maximum number of requests to simultaneously |
service using mmap. This parameter exists because: |
|
1. Some systems have a limited number of internal tables for |
use by mmap. |
2. In most systems, overreliance on mmap can degrade overall |
performance. |
3. If a program allocates many large regions, it is probably |
better off using normal sbrk-based allocation routines that |
can reclaim and reallocate normal heap memory. Using a |
small value allows transition into this mode after the |
first few allocations. |
|
Setting to 0 disables all use of mmap. If HAVE_MMAP is not set, |
the default value is 0, and attempts to set it to non-zero values |
in mallopt will fail. |
*/ |
|
|
|
|
/* |
|
Special defines for linux libc |
|
Except when compiled using these special defines for Linux libc |
using weak aliases, this malloc is NOT designed to work in |
multithreaded applications. No semaphores or other concurrency |
control are provided to ensure that multiple malloc or free calls |
don't run at the same time, which could be disasterous. A single |
semaphore could be used across malloc, realloc, and free (which is |
essentially the effect of the linux weak alias approach). It would |
be hard to obtain finer granularity. |
|
*/ |
|
|
#ifdef INTERNAL_LINUX_C_LIB |
|
#if __STD_C |
|
Void_t * __default_morecore_init (ptrdiff_t); |
Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; |
|
#else |
|
Void_t * __default_morecore_init (); |
Void_t *(*__morecore)() = __default_morecore_init; |
|
#endif |
|
#define MORECORE (*__morecore) |
#define MORECORE_FAILURE 0 |
#define MORECORE_CLEARS 1 |
|
#else /* INTERNAL_LINUX_C_LIB */ |
|
#ifndef INTERNAL_NEWLIB |
#if __STD_C |
extern Void_t* sbrk(ptrdiff_t); |
#else |
extern Void_t* sbrk(); |
#endif |
#endif |
|
#ifndef MORECORE |
#define MORECORE sbrk |
#endif |
|
#ifndef MORECORE_FAILURE |
#define MORECORE_FAILURE -1 |
#endif |
|
#ifndef MORECORE_CLEARS |
#define MORECORE_CLEARS 1 |
#endif |
|
#endif /* INTERNAL_LINUX_C_LIB */ |
|
#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) |
|
#define cALLOc __libc_calloc |
#define fREe __libc_free |
#define mALLOc __libc_malloc |
#define mEMALIGn __libc_memalign |
#define rEALLOc __libc_realloc |
#define vALLOc __libc_valloc |
#define pvALLOc __libc_pvalloc |
#define mALLINFo __libc_mallinfo |
#define mALLOPt __libc_mallopt |
|
#pragma weak calloc = __libc_calloc |
#pragma weak free = __libc_free |
#pragma weak cfree = __libc_free |
#pragma weak malloc = __libc_malloc |
#pragma weak memalign = __libc_memalign |
#pragma weak realloc = __libc_realloc |
#pragma weak valloc = __libc_valloc |
#pragma weak pvalloc = __libc_pvalloc |
#pragma weak mallinfo = __libc_mallinfo |
#pragma weak mallopt = __libc_mallopt |
|
#else |
|
#ifdef INTERNAL_NEWLIB |
|
#define cALLOc _calloc_r |
#define fREe _free_r |
#define mALLOc _malloc_r |
#define mEMALIGn _memalign_r |
#define rEALLOc _realloc_r |
#define vALLOc _valloc_r |
#define pvALLOc _pvalloc_r |
#define mALLINFo _mallinfo_r |
#define mALLOPt _mallopt_r |
|
#define malloc_stats _malloc_stats_r |
#define malloc_trim _malloc_trim_r |
#define malloc_usable_size _malloc_usable_size_r |
|
#define malloc_update_mallinfo __malloc_update_mallinfo |
|
#define malloc_av_ __malloc_av_ |
#define malloc_current_mallinfo __malloc_current_mallinfo |
#define malloc_max_sbrked_mem __malloc_max_sbrked_mem |
#define malloc_max_total_mem __malloc_max_total_mem |
#define malloc_sbrk_base __malloc_sbrk_base |
#define malloc_top_pad __malloc_top_pad |
#define malloc_trim_threshold __malloc_trim_threshold |
|
#else /* ! INTERNAL_NEWLIB */ |
|
#define cALLOc calloc |
#define fREe free |
#define mALLOc malloc |
#define mEMALIGn memalign |
#define rEALLOc realloc |
#define vALLOc valloc |
#define pvALLOc pvalloc |
#define mALLINFo mallinfo |
#define mALLOPt mallopt |
|
#endif /* ! INTERNAL_NEWLIB */ |
#endif |
|
/* Public routines */ |
|
#if __STD_C |
|
Void_t* mALLOc(RARG size_t); |
void fREe(RARG Void_t*); |
Void_t* rEALLOc(RARG Void_t*, size_t); |
Void_t* mEMALIGn(RARG size_t, size_t); |
Void_t* vALLOc(RARG size_t); |
Void_t* pvALLOc(RARG size_t); |
Void_t* cALLOc(RARG size_t, size_t); |
void cfree(Void_t*); |
int malloc_trim(RARG size_t); |
size_t malloc_usable_size(RARG Void_t*); |
void malloc_stats(RONEARG); |
int mALLOPt(RARG int, int); |
struct mallinfo mALLINFo(RONEARG); |
#else |
Void_t* mALLOc(); |
void fREe(); |
Void_t* rEALLOc(); |
Void_t* mEMALIGn(); |
Void_t* vALLOc(); |
Void_t* pvALLOc(); |
Void_t* cALLOc(); |
void cfree(); |
int malloc_trim(); |
size_t malloc_usable_size(); |
void malloc_stats(); |
int mALLOPt(); |
struct mallinfo mALLINFo(); |
#endif |
|
|
#ifdef __cplusplus |
}; /* end of extern "C" */ |
#endif |
|
/* ---------- To make a malloc.h, end cutting here ------------ */ |
|
|
/* |
Emulation of sbrk for WIN32 |
All code within the ifdef WIN32 is untested by me. |
*/ |
|
|
#ifdef WIN32 |
|
#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & |
~(malloc_getpagesize-1)) |
|
/* resrve 64MB to insure large contiguous space */ |
#define RESERVED_SIZE (1024*1024*64) |
#define NEXT_SIZE (2048*1024) |
#define TOP_MEMORY ((unsigned long)2*1024*1024*1024) |
|
struct GmListElement; |
typedef struct GmListElement GmListElement; |
|
struct GmListElement |
{ |
GmListElement* next; |
void* base; |
}; |
|
static GmListElement* head = 0; |
static unsigned int gNextAddress = 0; |
static unsigned int gAddressBase = 0; |
static unsigned int gAllocatedSize = 0; |
|
static |
GmListElement* makeGmListElement (void* bas) |
{ |
GmListElement* this; |
this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement)); |
ASSERT (this); |
if (this) |
{ |
this->base = bas; |
this->next = head; |
head = this; |
} |
return this; |
} |
|
void gcleanup () |
{ |
BOOL rval; |
ASSERT ( (head == NULL) || (head->base == (void*)gAddressBase)); |
if (gAddressBase && (gNextAddress - gAddressBase)) |
{ |
rval = VirtualFree ((void*)gAddressBase, |
gNextAddress - gAddressBase, |
MEM_DECOMMIT); |
ASSERT (rval); |
} |
while (head) |
{ |
GmListElement* next = head->next; |
rval = VirtualFree (head->base, 0, MEM_RELEASE); |
ASSERT (rval); |
LocalFree (head); |
head = next; |
} |
} |
|
static |
void* findRegion (void* start_address, unsigned long size) |
{ |
MEMORY_BASIC_INFORMATION info; |
while ((unsigned long)start_address < TOP_MEMORY) |
{ |
VirtualQuery (start_address, &info, sizeof (info)); |
if (info.State != MEM_FREE) |
start_address = (char*)info.BaseAddress + info.RegionSize; |
else if (info.RegionSize >= size) |
return start_address; |
else |
start_address = (char*)info.BaseAddress + info.RegionSize; |
} |
return NULL; |
|
} |
|
|
void* wsbrk (long size) |
{ |
void* tmp; |
if (size > 0) |
{ |
if (gAddressBase == 0) |
{ |
gAllocatedSize = max (RESERVED_SIZE, AlignPage (size)); |
gNextAddress = gAddressBase = |
(unsigned int)VirtualAlloc (NULL, gAllocatedSize, |
MEM_RESERVE, PAGE_NOACCESS); |
} else if (AlignPage (gNextAddress + size) > (gAddressBase + |
gAllocatedSize)) |
{ |
long new_size = max (NEXT_SIZE, AlignPage (size)); |
void* new_address = (void*)(gAddressBase+gAllocatedSize); |
do |
{ |
new_address = findRegion (new_address, new_size); |
|
if (new_address == 0) |
return (void*)-1; |
|
gAddressBase = gNextAddress = |
(unsigned int)VirtualAlloc (new_address, new_size, |
MEM_RESERVE, PAGE_NOACCESS); |
// repeat in case of race condition |
// The region that we found has been snagged |
// by another thread |
} |
while (gAddressBase == 0); |
|
ASSERT (new_address == (void*)gAddressBase); |
|
gAllocatedSize = new_size; |
|
if (!makeGmListElement ((void*)gAddressBase)) |
return (void*)-1; |
} |
if ((size + gNextAddress) > AlignPage (gNextAddress)) |
{ |
void* res; |
res = VirtualAlloc ((void*)AlignPage (gNextAddress), |
(size + gNextAddress - |
AlignPage (gNextAddress)), |
MEM_COMMIT, PAGE_READWRITE); |
if (res == 0) |
return (void*)-1; |
} |
tmp = (void*)gNextAddress; |
gNextAddress = (unsigned int)tmp + size; |
return tmp; |
} |
else if (size < 0) |
{ |
unsigned int alignedGoal = AlignPage (gNextAddress + size); |
/* Trim by releasing the virtual memory */ |
if (alignedGoal >= gAddressBase) |
{ |
VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal, |
MEM_DECOMMIT); |
gNextAddress = gNextAddress + size; |
return (void*)gNextAddress; |
} |
else |
{ |
VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase, |
MEM_DECOMMIT); |
gNextAddress = gAddressBase; |
return (void*)-1; |
} |
} |
else |
{ |
return (void*)gNextAddress; |
} |
} |
|
#endif |
|
|
|
/* |
Type declarations |
*/ |
|
|
struct malloc_chunk |
{ |
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ |
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ |
struct malloc_chunk* fd; /* double links -- used only if free. */ |
struct malloc_chunk* bk; |
}; |
|
typedef struct malloc_chunk* mchunkptr; |
|
/* |
|
malloc_chunk details: |
|
(The following includes lightly edited explanations by Colin Plumb.) |
|
Chunks of memory are maintained using a `boundary tag' method as |
described in e.g., Knuth or Standish. (See the paper by Paul |
Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a |
survey of such techniques.) Sizes of free chunks are stored both |
in the front of each chunk and at the end. This makes |
consolidating fragmented chunks into bigger chunks very fast. The |
size fields also hold bits representing whether chunks are free or |
in use. |
|
An allocated chunk looks like this: |
|
|
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk, if allocated | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of chunk, in bytes |P| |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| User data starts here... . |
. . |
. (malloc_usable_space() bytes) . |
. | |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
|
Where "chunk" is the front of the chunk for the purpose of most of |
the malloc code, but "mem" is the pointer that is returned to the |
user. "Nextchunk" is the beginning of the next contiguous chunk. |
|
Chunks always begin on even word boundries, so the mem portion |
(which is returned to the user) is also on an even word boundary, and |
thus double-word aligned. |
|
Free chunks are stored in circular doubly-linked lists, and look like this: |
|
chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Size of previous chunk | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`head:' | Size of chunk, in bytes |P| |
mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Forward pointer to next chunk in list | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Back pointer to previous chunk in list | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| Unused space (may be 0 bytes long) . |
. . |
. | |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
`foot:' | Size of chunk, in bytes | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|
The P (PREV_INUSE) bit, stored in the unused low-order bit of the |
chunk size (which is always a multiple of two words), is an in-use |
bit for the *previous* chunk. If that bit is *clear*, then the |
word before the current chunk size contains the previous chunk |
size, and can be used to find the front of the previous chunk. |
(The very first chunk allocated always has this bit set, |
preventing access to non-existent (or non-owned) memory.) |
|
Note that the `foot' of the current chunk is actually represented |
as the prev_size of the NEXT chunk. (This makes it easier to |
deal with alignments etc). |
|
The two exceptions to all this are |
|
1. The special chunk `top', which doesn't bother using the |
trailing size field since there is no |
next contiguous chunk that would have to index off it. (After |
initialization, `top' is forced to always exist. If it would |
become less than MINSIZE bytes long, it is replenished via |
malloc_extend_top.) |
|
2. Chunks allocated via mmap, which have the second-lowest-order |
bit (IS_MMAPPED) set in their size fields. Because they are |
never merged or traversed from any other chunk, they have no |
foot size or inuse information. |
|
Available chunks are kept in any of several places (all declared below): |
|
* `av': An array of chunks serving as bin headers for consolidated |
chunks. Each bin is doubly linked. The bins are approximately |
proportionally (log) spaced. There are a lot of these bins |
(128). This may look excessive, but works very well in |
practice. All procedures maintain the invariant that no |
consolidated chunk physically borders another one. Chunks in |
bins are kept in size order, with ties going to the |
approximately least recently used chunk. |
|
The chunks in each bin are maintained in decreasing sorted order by |
size. This is irrelevant for the small bins, which all contain |
the same-sized chunks, but facilitates best-fit allocation for |
larger chunks. (These lists are just sequential. Keeping them in |
order almost never requires enough traversal to warrant using |
fancier ordered data structures.) Chunks of the same size are |
linked with the most recently freed at the front, and allocations |
are taken from the back. This results in LRU or FIFO allocation |
order, which tends to give each chunk an equal opportunity to be |
consolidated with adjacent freed chunks, resulting in larger free |
chunks and less fragmentation. |
|
* `top': The top-most available chunk (i.e., the one bordering the |
end of available memory) is treated specially. It is never |
included in any bin, is used only if no other chunk is |
available, and is released back to the system if it is very |
large (see M_TRIM_THRESHOLD). |
|
* `last_remainder': A bin holding only the remainder of the |
most recently split (non-top) chunk. This bin is checked |
before other non-fitting chunks, so as to provide better |
locality for runs of sequentially allocated chunks. |
|
* Implicitly, through the host system's memory mapping tables. |
If supported, requests greater than a threshold are usually |
serviced via calls to mmap, and then later released via munmap. |
|
*/ |
|
|
|
|
|
|
/* sizes, alignments */ |
|
#define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) |
#ifndef MALLOC_ALIGNMENT |
#define MALLOC_ALIGN 8 |
#define MALLOC_ALIGNMENT (SIZE_SZ < 4 ? 8 : (SIZE_SZ + SIZE_SZ)) |
#else |
#define MALLOC_ALIGN MALLOC_ALIGNMENT |
#endif |
#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) |
#define MINSIZE (sizeof(struct malloc_chunk)) |
|
/* conversion from malloc headers to user pointers, and back */ |
|
#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) |
#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) |
|
/* pad request bytes into a usable size */ |
|
#define request2size(req) \ |
(((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \ |
(long)(MINSIZE + MALLOC_ALIGN_MASK)) ? ((MINSIZE + MALLOC_ALIGN_MASK) & ~(MALLOC_ALIGN_MASK)) : \ |
(((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK))) |
|
/* Check if m has acceptable alignment */ |
|
#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) |
|
|
|
|
/* |
Physical chunk operations |
*/ |
|
|
/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ |
|
#define PREV_INUSE 0x1 |
|
/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ |
|
#define IS_MMAPPED 0x2 |
|
/* Bits to mask off when extracting size */ |
|
#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) |
|
|
/* Ptr to next physical malloc_chunk. */ |
|
#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) |
|
/* Ptr to previous physical malloc_chunk */ |
|
#define prev_chunk(p)\ |
((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) |
|
|
/* Treat space at ptr + offset as a chunk */ |
|
#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) |
|
|
|
|
/* |
Dealing with use bits |
*/ |
|
/* extract p's inuse bit */ |
|
#define inuse(p)\ |
((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) |
|
/* extract inuse bit of previous chunk */ |
|
#define prev_inuse(p) ((p)->size & PREV_INUSE) |
|
/* check for mmap()'ed chunk */ |
|
#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) |
|
/* set/clear chunk as in use without otherwise disturbing */ |
|
#define set_inuse(p)\ |
((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE |
|
#define clear_inuse(p)\ |
((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) |
|
/* check/set/clear inuse bits in known places */ |
|
#define inuse_bit_at_offset(p, s)\ |
(((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) |
|
#define set_inuse_bit_at_offset(p, s)\ |
(((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) |
|
#define clear_inuse_bit_at_offset(p, s)\ |
(((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) |
|
|
|
|
/* |
Dealing with size fields |
*/ |
|
/* Get size, ignoring use bits */ |
|
#define chunksize(p) ((p)->size & ~(SIZE_BITS)) |
|
/* Set size at head, without disturbing its use bit */ |
|
#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) |
|
/* Set size/use ignoring previous bits in header */ |
|
#define set_head(p, s) ((p)->size = (s)) |
|
/* Set size at footer (only when chunk is not in use) */ |
|
#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) |
|
|
|
|
|
/* |
Bins |
|
The bins, `av_' are an array of pairs of pointers serving as the |
heads of (initially empty) doubly-linked lists of chunks, laid out |
in a way so that each pair can be treated as if it were in a |
malloc_chunk. (This way, the fd/bk offsets for linking bin heads |
and chunks are the same). |
|
Bins for sizes < 512 bytes contain chunks of all the same size, spaced |
8 bytes apart. Larger bins are approximately logarithmically |
spaced. (See the table below.) The `av_' array is never mentioned |
directly in the code, but instead via bin access macros. |
|
Bin layout: |
|
64 bins of size 8 |
32 bins of size 64 |
16 bins of size 512 |
8 bins of size 4096 |
4 bins of size 32768 |
2 bins of size 262144 |
1 bin of size what's left |
|
There is actually a little bit of slop in the numbers in bin_index |
for the sake of speed. This makes no difference elsewhere. |
|
The special chunks `top' and `last_remainder' get their own bins, |
(this is implemented via yet more trickery with the av_ array), |
although `top' is never properly linked to its bin since it is |
always handled specially. |
|
*/ |
|
#ifdef SEPARATE_OBJECTS |
#define av_ malloc_av_ |
#endif |
|
#define NAV 128 /* number of bins */ |
|
typedef struct malloc_chunk* mbinptr; |
|
/* access macros */ |
|
#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ)) |
#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr))) |
#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr))) |
|
/* |
The first 2 bins are never indexed. The corresponding av_ cells are instead |
used for bookkeeping. This is not to save space, but to simplify |
indexing, maintain locality, and avoid some initialization tests. |
*/ |
|
#define top (bin_at(0)->fd) /* The topmost chunk */ |
#define last_remainder (bin_at(1)) /* remainder from last split */ |
|
|
/* |
Because top initially points to its own bin with initial |
zero size, thus forcing extension on the first malloc request, |
we avoid having any special code in malloc to check whether |
it even exists yet. But we still need to in malloc_extend_top. |
*/ |
|
#define initial_top ((mchunkptr)(bin_at(0))) |
|
/* Helper macro to initialize bins */ |
|
#define IAV(i) bin_at(i), bin_at(i) |
|
#ifdef DEFINE_MALLOC |
STATIC mbinptr av_[NAV * 2 + 2] = { |
0, 0, |
IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), |
IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), |
IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23), |
IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31), |
IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39), |
IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47), |
IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55), |
IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63), |
IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71), |
IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79), |
IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87), |
IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95), |
IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103), |
IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), |
IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), |
IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) |
}; |
#else |
extern mbinptr av_[NAV * 2 + 2]; |
#endif |
|
|
|
/* field-extraction macros */ |
|
#define first(b) ((b)->fd) |
#define last(b) ((b)->bk) |
|
/* |
Indexing into bins |
*/ |
|
#define bin_index(sz) \ |
(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \ |
((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \ |
((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \ |
((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \ |
((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \ |
((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \ |
126) |
/* |
bins for chunks < 512 are all spaced SMALLBIN_WIDTH bytes apart, and hold |
identically sized chunks. This is exploited in malloc. |
*/ |
|
#define MAX_SMALLBIN_SIZE 512 |
#define SMALLBIN_WIDTH 8 |
#define SMALLBIN_WIDTH_BITS 3 |
#define MAX_SMALLBIN (MAX_SMALLBIN_SIZE / SMALLBIN_WIDTH) - 1 |
|
#define smallbin_index(sz) (((unsigned long)(sz)) >> SMALLBIN_WIDTH_BITS) |
|
/* |
Requests are `small' if both the corresponding and the next bin are small |
*/ |
|
#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH) |
|
|
|
/* |
To help compensate for the large number of bins, a one-level index |
structure is used for bin-by-bin searching. `binblocks' is a |
one-word bitvector recording whether groups of BINBLOCKWIDTH bins |
have any (possibly) non-empty bins, so they can be skipped over |
all at once during during traversals. The bits are NOT always |
cleared as soon as all bins in a block are empty, but instead only |
when all are noticed to be empty during traversal in malloc. |
*/ |
|
#define BINBLOCKWIDTH 4 /* bins per block */ |
|
#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */ |
|
/* bin<->block macros */ |
|
#define idx2binblock(ix) ((unsigned long)1 << (ix / BINBLOCKWIDTH)) |
#define mark_binblock(ii) (binblocks |= idx2binblock(ii)) |
#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii))) |
|
|
|
|
|
/* Other static bookkeeping data */ |
|
#ifdef SEPARATE_OBJECTS |
#define trim_threshold malloc_trim_threshold |
#define top_pad malloc_top_pad |
#define n_mmaps_max malloc_n_mmaps_max |
#define mmap_threshold malloc_mmap_threshold |
#define sbrk_base malloc_sbrk_base |
#define max_sbrked_mem malloc_max_sbrked_mem |
#define max_total_mem malloc_max_total_mem |
#define current_mallinfo malloc_current_mallinfo |
#define n_mmaps malloc_n_mmaps |
#define max_n_mmaps malloc_max_n_mmaps |
#define mmapped_mem malloc_mmapped_mem |
#define max_mmapped_mem malloc_max_mmapped_mem |
#endif |
|
/* variables holding tunable values */ |
|
#ifdef DEFINE_MALLOC |
|
STATIC unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD; |
STATIC unsigned long top_pad = DEFAULT_TOP_PAD; |
#if HAVE_MMAP |
STATIC unsigned int n_mmaps_max = DEFAULT_MMAP_MAX; |
STATIC unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD; |
#endif |
|
/* The first value returned from sbrk */ |
STATIC char* sbrk_base = (char*)(-1); |
|
/* The maximum memory obtained from system via sbrk */ |
STATIC unsigned long max_sbrked_mem = 0; |
|
/* The maximum via either sbrk or mmap */ |
STATIC unsigned long max_total_mem = 0; |
|
/* internal working copy of mallinfo */ |
STATIC struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; |
|
#if HAVE_MMAP |
|
/* Tracking mmaps */ |
|
STATIC unsigned int n_mmaps = 0; |
STATIC unsigned int max_n_mmaps = 0; |
STATIC unsigned long mmapped_mem = 0; |
STATIC unsigned long max_mmapped_mem = 0; |
|
#endif |
|
#else /* ! DEFINE_MALLOC */ |
|
extern unsigned long trim_threshold; |
extern unsigned long top_pad; |
#if HAVE_MMAP |
extern unsigned int n_mmaps_max; |
extern unsigned long mmap_threshold; |
#endif |
extern char* sbrk_base; |
extern unsigned long max_sbrked_mem; |
extern unsigned long max_total_mem; |
extern struct mallinfo current_mallinfo; |
#if HAVE_MMAP |
extern unsigned int n_mmaps; |
extern unsigned int max_n_mmaps; |
extern unsigned long mmapped_mem; |
extern unsigned long max_mmapped_mem; |
#endif |
|
#endif /* ! DEFINE_MALLOC */ |
|
/* The total memory obtained from system via sbrk */ |
#define sbrked_mem (current_mallinfo.arena) |
|
|
|
/* |
Debugging support |
*/ |
|
#if DEBUG |
|
|
/* |
These routines make a number of assertions about the states |
of data structures that should be true at all times. If any |
are not true, it's very likely that a user program has somehow |
trashed memory. (It's also possible that there is a coding error |
in malloc. In which case, please report it!) |
*/ |
|
#if __STD_C |
static void do_check_chunk(mchunkptr p) |
#else |
static void do_check_chunk(p) mchunkptr p; |
#endif |
{ |
INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; |
|
/* No checkable chunk is mmapped */ |
assert(!chunk_is_mmapped(p)); |
|
/* Check for legal address ... */ |
assert((char*)p >= sbrk_base); |
if (p != top) |
assert((char*)p + sz <= (char*)top); |
else |
assert((char*)p + sz <= sbrk_base + sbrked_mem); |
|
} |
|
|
#if __STD_C |
static void do_check_free_chunk(mchunkptr p) |
#else |
static void do_check_free_chunk(p) mchunkptr p; |
#endif |
{ |
INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; |
mchunkptr next = chunk_at_offset(p, sz); |
|
do_check_chunk(p); |
|
/* Check whether it claims to be free ... */ |
assert(!inuse(p)); |
|
/* Unless a special marker, must have OK fields */ |
if ((long)sz >= (long)MINSIZE) |
{ |
assert((sz & MALLOC_ALIGN_MASK) == 0); |
assert(aligned_OK(chunk2mem(p))); |
/* ... matching footer field */ |
assert(next->prev_size == sz); |
/* ... and is fully consolidated */ |
assert(prev_inuse(p)); |
assert (next == top || inuse(next)); |
|
/* ... and has minimally sane links */ |
assert(p->fd->bk == p); |
assert(p->bk->fd == p); |
} |
else /* markers are always of size SIZE_SZ */ |
assert(sz == SIZE_SZ); |
} |
|
#if __STD_C |
static void do_check_inuse_chunk(mchunkptr p) |
#else |
static void do_check_inuse_chunk(p) mchunkptr p; |
#endif |
{ |
mchunkptr next = next_chunk(p); |
do_check_chunk(p); |
|
/* Check whether it claims to be in use ... */ |
assert(inuse(p)); |
|
/* ... and is surrounded by OK chunks. |
Since more things can be checked with free chunks than inuse ones, |
if an inuse chunk borders them and debug is on, it's worth doing them. |
*/ |
if (!prev_inuse(p)) |
{ |
mchunkptr prv = prev_chunk(p); |
assert(next_chunk(prv) == p); |
do_check_free_chunk(prv); |
} |
if (next == top) |
{ |
assert(prev_inuse(next)); |
assert(chunksize(next) >= MINSIZE); |
} |
else if (!inuse(next)) |
do_check_free_chunk(next); |
|
} |
|
#if __STD_C |
static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) |
#else |
static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; |
#endif |
{ |
INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; |
long room = long_sub_size_t(sz, s); |
|
do_check_inuse_chunk(p); |
|
/* Legal size ... */ |
assert((long)sz >= (long)MINSIZE); |
assert((sz & MALLOC_ALIGN_MASK) == 0); |
assert(room >= 0); |
assert(room < (long)MINSIZE); |
|
/* ... and alignment */ |
assert(aligned_OK(chunk2mem(p))); |
|
|
/* ... and was allocated at front of an available chunk */ |
assert(prev_inuse(p)); |
|
} |
|
|
#define check_free_chunk(P) do_check_free_chunk(P) |
#define check_inuse_chunk(P) do_check_inuse_chunk(P) |
#define check_chunk(P) do_check_chunk(P) |
#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) |
#else |
#define check_free_chunk(P) |
#define check_inuse_chunk(P) |
#define check_chunk(P) |
#define check_malloced_chunk(P,N) |
#endif |
|
|
|
/* |
Macro-based internal utilities |
*/ |
|
|
/* |
Linking chunks in bin lists. |
Call these only with variables, not arbitrary expressions, as arguments. |
*/ |
|
/* |
Place chunk p of size s in its bin, in size order, |
putting it ahead of others of same size. |
*/ |
|
|
#define frontlink(P, S, IDX, BK, FD) \ |
{ \ |
if (S < MAX_SMALLBIN_SIZE) \ |
{ \ |
IDX = smallbin_index(S); \ |
mark_binblock(IDX); \ |
BK = bin_at(IDX); \ |
FD = BK->fd; \ |
P->bk = BK; \ |
P->fd = FD; \ |
FD->bk = BK->fd = P; \ |
} \ |
else \ |
{ \ |
IDX = bin_index(S); \ |
BK = bin_at(IDX); \ |
FD = BK->fd; \ |
if (FD == BK) mark_binblock(IDX); \ |
else \ |
{ \ |
while (FD != BK && S < chunksize(FD)) FD = FD->fd; \ |
BK = FD->bk; \ |
} \ |
P->bk = BK; \ |
P->fd = FD; \ |
FD->bk = BK->fd = P; \ |
} \ |
} |
|
|
/* take a chunk off a list */ |
|
#define unlink(P, BK, FD) \ |
{ \ |
BK = P->bk; \ |
FD = P->fd; \ |
FD->bk = BK; \ |
BK->fd = FD; \ |
} \ |
|
/* Place p as the last remainder */ |
|
#define link_last_remainder(P) \ |
{ \ |
last_remainder->fd = last_remainder->bk = P; \ |
P->fd = P->bk = last_remainder; \ |
} |
|
/* Clear the last_remainder bin */ |
|
#define clear_last_remainder \ |
(last_remainder->fd = last_remainder->bk = last_remainder) |
|
|
|
|
|
|
/* Routines dealing with mmap(). */ |
|
#if HAVE_MMAP |
|
#ifdef DEFINE_MALLOC |
|
#if __STD_C |
static mchunkptr mmap_chunk(size_t size) |
#else |
static mchunkptr mmap_chunk(size) size_t size; |
#endif |
{ |
size_t page_mask = malloc_getpagesize - 1; |
mchunkptr p; |
|
#ifndef MAP_ANONYMOUS |
static int fd = -1; |
#endif |
|
if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */ |
|
/* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because |
* there is no following chunk whose prev_size field could be used. |
*/ |
size = (size + SIZE_SZ + page_mask) & ~page_mask; |
|
#ifdef MAP_ANONYMOUS |
p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, |
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); |
#else /* !MAP_ANONYMOUS */ |
if (fd < 0) |
{ |
fd = open("/dev/zero", O_RDWR); |
if(fd < 0) return 0; |
} |
p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); |
#endif |
|
if(p == (mchunkptr)-1) return 0; |
|
n_mmaps++; |
if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps; |
|
/* We demand that eight bytes into a page must be 8-byte aligned. */ |
assert(aligned_OK(chunk2mem(p))); |
|
/* The offset to the start of the mmapped region is stored |
* in the prev_size field of the chunk; normally it is zero, |
* but that can be changed in memalign(). |
*/ |
p->prev_size = 0; |
set_head(p, size|IS_MMAPPED); |
|
mmapped_mem += size; |
if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) |
max_mmapped_mem = mmapped_mem; |
if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) |
max_total_mem = mmapped_mem + sbrked_mem; |
return p; |
} |
|
#endif /* DEFINE_MALLOC */ |
|
#ifdef SEPARATE_OBJECTS |
#define munmap_chunk malloc_munmap_chunk |
#endif |
|
#ifdef DEFINE_FREE |
|
#if __STD_C |
STATIC void munmap_chunk(mchunkptr p) |
#else |
STATIC void munmap_chunk(p) mchunkptr p; |
#endif |
{ |
INTERNAL_SIZE_T size = chunksize(p); |
int ret; |
|
assert (chunk_is_mmapped(p)); |
assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); |
assert((n_mmaps > 0)); |
assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0); |
|
n_mmaps--; |
mmapped_mem -= (size + p->prev_size); |
|
ret = munmap((char *)p - p->prev_size, size + p->prev_size); |
|
/* munmap returns non-zero on failure */ |
assert(ret == 0); |
} |
|
#else /* ! DEFINE_FREE */ |
|
#if __STD_C |
extern void munmap_chunk(mchunkptr); |
#else |
extern void munmap_chunk(); |
#endif |
|
#endif /* ! DEFINE_FREE */ |
|
#if HAVE_MREMAP |
|
#ifdef DEFINE_REALLOC |
|
#if __STD_C |
static mchunkptr mremap_chunk(mchunkptr p, size_t new_size) |
#else |
static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size; |
#endif |
{ |
size_t page_mask = malloc_getpagesize - 1; |
INTERNAL_SIZE_T offset = p->prev_size; |
INTERNAL_SIZE_T size = chunksize(p); |
char *cp; |
|
assert (chunk_is_mmapped(p)); |
assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); |
assert((n_mmaps > 0)); |
assert(((size + offset) & (malloc_getpagesize-1)) == 0); |
|
/* Note the extra SIZE_SZ overhead as in mmap_chunk(). */ |
new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask; |
|
cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1); |
|
if (cp == (char *)-1) return 0; |
|
p = (mchunkptr)(cp + offset); |
|
assert(aligned_OK(chunk2mem(p))); |
|
assert((p->prev_size == offset)); |
set_head(p, (new_size - offset)|IS_MMAPPED); |
|
mmapped_mem -= size + offset; |
mmapped_mem += new_size; |
if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) |
max_mmapped_mem = mmapped_mem; |
if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) |
max_total_mem = mmapped_mem + sbrked_mem; |
return p; |
} |
|
#endif /* DEFINE_REALLOC */ |
|
#endif /* HAVE_MREMAP */ |
|
#endif /* HAVE_MMAP */ |
|
|
|
|
#ifdef DEFINE_MALLOC |
|
/* |
Extend the top-most chunk by obtaining memory from system. |
Main interface to sbrk (but see also malloc_trim). |
*/ |
|
#if __STD_C |
static void malloc_extend_top(RARG INTERNAL_SIZE_T nb) |
#else |
static void malloc_extend_top(RARG nb) RDECL INTERNAL_SIZE_T nb; |
#endif |
{ |
char* brk; /* return value from sbrk */ |
INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */ |
INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */ |
char* new_brk; /* return of 2nd sbrk call */ |
INTERNAL_SIZE_T top_size; /* new size of top chunk */ |
|
mchunkptr old_top = top; /* Record state of old top */ |
INTERNAL_SIZE_T old_top_size = chunksize(old_top); |
char* old_end = (char*)(chunk_at_offset(old_top, old_top_size)); |
|
/* Pad request with top_pad plus minimal overhead */ |
|
INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE; |
unsigned long pagesz = malloc_getpagesize; |
|
/* If not the first time through, round to preserve page boundary */ |
/* Otherwise, we need to correct to a page size below anyway. */ |
/* (We also correct below if an intervening foreign sbrk call.) */ |
|
if (sbrk_base != (char*)(-1)) |
sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1); |
|
brk = (char*)(MORECORE (sbrk_size)); |
|
/* Fail if sbrk failed or if a foreign sbrk call killed our space */ |
if (brk == (char*)(MORECORE_FAILURE) || |
(brk < old_end && old_top != initial_top)) |
return; |
|
sbrked_mem += sbrk_size; |
|
if (brk == old_end) /* can just add bytes to current top */ |
{ |
top_size = sbrk_size + old_top_size; |
set_head(top, top_size | PREV_INUSE); |
} |
else |
{ |
if (sbrk_base == (char*)(-1)) /* First time through. Record base */ |
sbrk_base = brk; |
else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */ |
sbrked_mem += brk - (char*)old_end; |
|
/* Guarantee alignment of first new chunk made from this space */ |
front_misalign = (POINTER_UINT)chunk2mem(brk) & MALLOC_ALIGN_MASK; |
if (front_misalign > 0) |
{ |
correction = (MALLOC_ALIGNMENT) - front_misalign; |
brk += correction; |
} |
else |
correction = 0; |
|
/* Guarantee the next brk will be at a page boundary */ |
correction += pagesz - ((POINTER_UINT)(brk + sbrk_size) & (pagesz - 1)); |
|
/* Allocate correction */ |
new_brk = (char*)(MORECORE (correction)); |
if (new_brk == (char*)(MORECORE_FAILURE)) return; |
|
sbrked_mem += correction; |
|
top = (mchunkptr)brk; |
top_size = new_brk - brk + correction; |
set_head(top, top_size | PREV_INUSE); |
|
if (old_top != initial_top) |
{ |
|
/* There must have been an intervening foreign sbrk call. */ |
/* A double fencepost is necessary to prevent consolidation */ |
|
/* If not enough space to do this, then user did something very wrong */ |
if (old_top_size < MINSIZE) |
{ |
set_head(top, PREV_INUSE); /* will force null return from malloc */ |
return; |
} |
|
/* Also keep size a multiple of MALLOC_ALIGNMENT */ |
old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; |
set_head_size(old_top, old_top_size); |
chunk_at_offset(old_top, old_top_size )->size = |
SIZE_SZ|PREV_INUSE; |
chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size = |
SIZE_SZ|PREV_INUSE; |
/* If possible, release the rest. */ |
if (old_top_size >= MINSIZE) |
fREe(RCALL chunk2mem(old_top)); |
} |
} |
|
if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem) |
max_sbrked_mem = sbrked_mem; |
#if HAVE_MMAP |
if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) |
max_total_mem = mmapped_mem + sbrked_mem; |
#else |
if ((unsigned long)(sbrked_mem) > (unsigned long)max_total_mem) |
max_total_mem = sbrked_mem; |
#endif |
|
/* We always land on a page boundary */ |
assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0); |
} |
|
#endif /* DEFINE_MALLOC */ |
|
|
/* Main public routines */ |
|
#ifdef DEFINE_MALLOC |
|
/* |
Malloc Algorthim: |
|
The requested size is first converted into a usable form, `nb'. |
This currently means to add 4 bytes overhead plus possibly more to |
obtain 8-byte alignment and/or to obtain a size of at least |
MINSIZE (currently 16 bytes), the smallest allocatable size. |
(All fits are considered `exact' if they are within MINSIZE bytes.) |
|
From there, the first successful of the following steps is taken: |
|
1. The bin corresponding to the request size is scanned, and if |
a chunk of exactly the right size is found, it is taken. |
|
2. The most recently remaindered chunk is used if it is big |
enough. This is a form of (roving) first fit, used only in |
the absence of exact fits. Runs of consecutive requests use |
the remainder of the chunk used for the previous such request |
whenever possible. This limited use of a first-fit style |
allocation strategy tends to give contiguous chunks |
coextensive lifetimes, which improves locality and can reduce |
fragmentation in the long run. |
|
3. Other bins are scanned in increasing size order, using a |
chunk big enough to fulfill the request, and splitting off |
any remainder. This search is strictly by best-fit; i.e., |
the smallest (with ties going to approximately the least |
recently used) chunk that fits is selected. |
|
4. If large enough, the chunk bordering the end of memory |
(`top') is split off. (This use of `top' is in accord with |
the best-fit search rule. In effect, `top' is treated as |
larger (and thus less well fitting) than any other available |
chunk since it can be extended to be as large as necessary |
(up to system limitations). |
|
5. If the request size meets the mmap threshold and the |
system supports mmap, and there are few enough currently |
allocated mmapped regions, and a call to mmap succeeds, |
the request is allocated via direct memory mapping. |
|
6. Otherwise, the top of memory is extended by |
obtaining more space from the system (normally using sbrk, |
but definable to anything else via the MORECORE macro). |
Memory is gathered from the system (in system page-sized |
units) in a way that allows chunks obtained across different |
sbrk calls to be consolidated, but does not require |
contiguous memory. Thus, it should be safe to intersperse |
mallocs with other sbrk calls. |
|
|
All allocations are made from the the `lowest' part of any found |
chunk. (The implementation invariant is that prev_inuse is |
always true of any allocated chunk; i.e., that each allocated |
chunk borders either a previously allocated and still in-use chunk, |
or the base of its memory arena.) |
|
*/ |
|
#if __STD_C |
Void_t* mALLOc(RARG size_t bytes) |
#else |
Void_t* mALLOc(RARG bytes) RDECL size_t bytes; |
#endif |
{ |
#ifdef MALLOC_PROVIDED |
|
malloc (bytes); |
|
#else |
|
mchunkptr victim; /* inspected/selected chunk */ |
INTERNAL_SIZE_T victim_size; /* its size */ |
int idx; /* index for bin traversal */ |
mbinptr bin; /* associated bin */ |
mchunkptr remainder; /* remainder from a split */ |
long remainder_size; /* its size */ |
int remainder_index; /* its bin index */ |
unsigned long block; /* block traverser bit */ |
int startidx; /* first bin of a traversed block */ |
mchunkptr fwd; /* misc temp for linking */ |
mchunkptr bck; /* misc temp for linking */ |
mbinptr q; /* misc temp */ |
|
INTERNAL_SIZE_T nb = request2size(bytes); /* padded request size; */ |
|
MALLOC_LOCK; |
|
/* Check for exact match in a bin */ |
|
if (is_small_request(nb)) /* Faster version for small requests */ |
{ |
idx = smallbin_index(nb); |
|
/* No traversal or size check necessary for small bins. */ |
|
q = bin_at(idx); |
victim = last(q); |
|
#if MALLOC_ALIGN != 16 |
/* Also scan the next one, since it would have a remainder < MINSIZE */ |
if (victim == q) |
{ |
q = next_bin(q); |
victim = last(q); |
} |
#endif |
if (victim != q) |
{ |
victim_size = chunksize(victim); |
unlink(victim, bck, fwd); |
set_inuse_bit_at_offset(victim, victim_size); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
|
idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */ |
|
} |
else |
{ |
idx = bin_index(nb); |
bin = bin_at(idx); |
|
for (victim = last(bin); victim != bin; victim = victim->bk) |
{ |
victim_size = chunksize(victim); |
remainder_size = long_sub_size_t(victim_size, nb); |
|
if (remainder_size >= (long)MINSIZE) /* too big */ |
{ |
--idx; /* adjust to rescan below after checking last remainder */ |
break; |
} |
|
else if (remainder_size >= 0) /* exact fit */ |
{ |
unlink(victim, bck, fwd); |
set_inuse_bit_at_offset(victim, victim_size); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
} |
|
++idx; |
|
} |
|
/* Try to use the last split-off remainder */ |
|
if ( (victim = last_remainder->fd) != last_remainder) |
{ |
victim_size = chunksize(victim); |
remainder_size = long_sub_size_t(victim_size, nb); |
|
if (remainder_size >= (long)MINSIZE) /* re-split */ |
{ |
remainder = chunk_at_offset(victim, nb); |
set_head(victim, nb | PREV_INUSE); |
link_last_remainder(remainder); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_foot(remainder, remainder_size); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
|
clear_last_remainder; |
|
if (remainder_size >= 0) /* exhaust */ |
{ |
set_inuse_bit_at_offset(victim, victim_size); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
|
/* Else place in bin */ |
|
frontlink(victim, victim_size, remainder_index, bck, fwd); |
} |
|
/* |
If there are any possibly nonempty big-enough blocks, |
search for best fitting chunk by scanning bins in blockwidth units. |
*/ |
|
if ( (block = idx2binblock(idx)) <= binblocks) |
{ |
|
/* Get to the first marked block */ |
|
if ( (block & binblocks) == 0) |
{ |
/* force to an even block boundary */ |
idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH; |
block <<= 1; |
while ((block & binblocks) == 0) |
{ |
idx += BINBLOCKWIDTH; |
block <<= 1; |
} |
} |
|
/* For each possibly nonempty block ... */ |
for (;;) |
{ |
startidx = idx; /* (track incomplete blocks) */ |
q = bin = bin_at(idx); |
|
/* For each bin in this block ... */ |
do |
{ |
/* Find and use first big enough chunk ... */ |
|
for (victim = last(bin); victim != bin; victim = victim->bk) |
{ |
victim_size = chunksize(victim); |
remainder_size = long_sub_size_t(victim_size, nb); |
|
if (remainder_size >= (long)MINSIZE) /* split */ |
{ |
remainder = chunk_at_offset(victim, nb); |
set_head(victim, nb | PREV_INUSE); |
unlink(victim, bck, fwd); |
link_last_remainder(remainder); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_foot(remainder, remainder_size); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
|
else if (remainder_size >= 0) /* take */ |
{ |
set_inuse_bit_at_offset(victim, victim_size); |
unlink(victim, bck, fwd); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
|
} |
|
bin = next_bin(bin); |
|
#if MALLOC_ALIGN == 16 |
if (idx < MAX_SMALLBIN) |
{ |
bin = next_bin(bin); |
++idx; |
} |
#endif |
} while ((++idx & (BINBLOCKWIDTH - 1)) != 0); |
|
/* Clear out the block bit. */ |
|
do /* Possibly backtrack to try to clear a partial block */ |
{ |
if ((startidx & (BINBLOCKWIDTH - 1)) == 0) |
{ |
binblocks &= ~block; |
break; |
} |
--startidx; |
q = prev_bin(q); |
} while (first(q) == q); |
|
/* Get to the next possibly nonempty block */ |
|
if ( (block <<= 1) <= binblocks && (block != 0) ) |
{ |
while ((block & binblocks) == 0) |
{ |
idx += BINBLOCKWIDTH; |
block <<= 1; |
} |
} |
else |
break; |
} |
} |
|
|
/* Try to use top chunk */ |
|
/* Require that there be a remainder, ensuring top always exists */ |
remainder_size = long_sub_size_t(chunksize(top), nb); |
if (chunksize(top) < nb || remainder_size < (long)MINSIZE) |
{ |
|
#if HAVE_MMAP |
/* If big and would otherwise need to extend, try to use mmap instead */ |
if ((unsigned long)nb >= (unsigned long)mmap_threshold && |
(victim = mmap_chunk(nb)) != 0) |
{ |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
} |
#endif |
|
/* Try to extend */ |
malloc_extend_top(RCALL nb); |
remainder_size = long_sub_size_t(chunksize(top), nb); |
if (chunksize(top) < nb || remainder_size < (long)MINSIZE) |
{ |
MALLOC_UNLOCK; |
return 0; /* propagate failure */ |
} |
} |
|
victim = top; |
set_head(victim, nb | PREV_INUSE); |
top = chunk_at_offset(victim, nb); |
set_head(top, remainder_size | PREV_INUSE); |
check_malloced_chunk(victim, nb); |
MALLOC_UNLOCK; |
return chunk2mem(victim); |
|
#endif /* MALLOC_PROVIDED */ |
} |
|
#endif /* DEFINE_MALLOC */ |
|
#ifdef DEFINE_FREE |
|
/* |
|
free() algorithm : |
|
cases: |
|
1. free(0) has no effect. |
|
2. If the chunk was allocated via mmap, it is release via munmap(). |
|
3. If a returned chunk borders the current high end of memory, |
it is consolidated into the top, and if the total unused |
topmost memory exceeds the trim threshold, malloc_trim is |
called. |
|
4. Other chunks are consolidated as they arrive, and |
placed in corresponding bins. (This includes the case of |
consolidating with the current `last_remainder'). |
|
*/ |
|
|
#if __STD_C |
void fREe(RARG Void_t* mem) |
#else |
void fREe(RARG mem) RDECL Void_t* mem; |
#endif |
{ |
#ifdef MALLOC_PROVIDED |
|
free (mem); |
|
#else |
|
mchunkptr p; /* chunk corresponding to mem */ |
INTERNAL_SIZE_T hd; /* its head field */ |
INTERNAL_SIZE_T sz; /* its size */ |
int idx; /* its bin index */ |
mchunkptr next; /* next contiguous chunk */ |
INTERNAL_SIZE_T nextsz; /* its size */ |
INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */ |
mchunkptr bck; /* misc temp for linking */ |
mchunkptr fwd; /* misc temp for linking */ |
int islr; /* track whether merging with last_remainder */ |
|
if (mem == 0) /* free(0) has no effect */ |
return; |
|
MALLOC_LOCK; |
|
p = mem2chunk(mem); |
hd = p->size; |
|
#if HAVE_MMAP |
if (hd & IS_MMAPPED) /* release mmapped memory. */ |
{ |
munmap_chunk(p); |
MALLOC_UNLOCK; |
return; |
} |
#endif |
|
check_inuse_chunk(p); |
|
sz = hd & ~PREV_INUSE; |
next = chunk_at_offset(p, sz); |
nextsz = chunksize(next); |
|
if (next == top) /* merge with top */ |
{ |
sz += nextsz; |
|
if (!(hd & PREV_INUSE)) /* consolidate backward */ |
{ |
prevsz = p->prev_size; |
p = chunk_at_offset(p, -prevsz); |
sz += prevsz; |
unlink(p, bck, fwd); |
} |
|
set_head(p, sz | PREV_INUSE); |
top = p; |
if ((unsigned long)(sz) >= (unsigned long)trim_threshold) |
malloc_trim(RCALL top_pad); |
MALLOC_UNLOCK; |
return; |
} |
|
set_head(next, nextsz); /* clear inuse bit */ |
|
islr = 0; |
|
if (!(hd & PREV_INUSE)) /* consolidate backward */ |
{ |
prevsz = p->prev_size; |
p = chunk_at_offset(p, -prevsz); |
sz += prevsz; |
|
if (p->fd == last_remainder) /* keep as last_remainder */ |
islr = 1; |
else |
unlink(p, bck, fwd); |
} |
|
if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */ |
{ |
sz += nextsz; |
|
if (!islr && next->fd == last_remainder) /* re-insert last_remainder */ |
{ |
islr = 1; |
link_last_remainder(p); |
} |
else |
unlink(next, bck, fwd); |
} |
|
|
set_head(p, sz | PREV_INUSE); |
set_foot(p, sz); |
if (!islr) |
frontlink(p, sz, idx, bck, fwd); |
|
MALLOC_UNLOCK; |
|
#endif /* MALLOC_PROVIDED */ |
} |
|
#endif /* DEFINE_FREE */ |
|
#ifdef DEFINE_REALLOC |
|
/* |
|
Realloc algorithm: |
|
Chunks that were obtained via mmap cannot be extended or shrunk |
unless HAVE_MREMAP is defined, in which case mremap is used. |
Otherwise, if their reallocation is for additional space, they are |
copied. If for less, they are just left alone. |
|
Otherwise, if the reallocation is for additional space, and the |
chunk can be extended, it is, else a malloc-copy-free sequence is |
taken. There are several different ways that a chunk could be |
extended. All are tried: |
|
* Extending forward into following adjacent free chunk. |
* Shifting backwards, joining preceding adjacent space |
* Both shifting backwards and extending forward. |
* Extending into newly sbrked space |
|
Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a |
size argument of zero (re)allocates a minimum-sized chunk. |
|
If the reallocation is for less space, and the new request is for |
a `small' (<512 bytes) size, then the newly unused space is lopped |
off and freed. |
|
The old unix realloc convention of allowing the last-free'd chunk |
to be used as an argument to realloc is no longer supported. |
I don't know of any programs still relying on this feature, |
and allowing it would also allow too many other incorrect |
usages of realloc to be sensible. |
|
|
*/ |
|
|
#if __STD_C |
Void_t* rEALLOc(RARG Void_t* oldmem, size_t bytes) |
#else |
Void_t* rEALLOc(RARG oldmem, bytes) RDECL Void_t* oldmem; size_t bytes; |
#endif |
{ |
#ifdef MALLOC_PROVIDED |
|
realloc (oldmem, bytes); |
|
#else |
|
INTERNAL_SIZE_T nb; /* padded request size */ |
|
mchunkptr oldp; /* chunk corresponding to oldmem */ |
INTERNAL_SIZE_T oldsize; /* its size */ |
|
mchunkptr newp; /* chunk to return */ |
INTERNAL_SIZE_T newsize; /* its size */ |
Void_t* newmem; /* corresponding user mem */ |
|
mchunkptr next; /* next contiguous chunk after oldp */ |
INTERNAL_SIZE_T nextsize; /* its size */ |
|
mchunkptr prev; /* previous contiguous chunk before oldp */ |
INTERNAL_SIZE_T prevsize; /* its size */ |
|
mchunkptr remainder; /* holds split off extra space from newp */ |
INTERNAL_SIZE_T remainder_size; /* its size */ |
|
mchunkptr bck; /* misc temp for linking */ |
mchunkptr fwd; /* misc temp for linking */ |
|
#ifdef REALLOC_ZERO_BYTES_FREES |
if (bytes == 0) { fREe(RCALL oldmem); return 0; } |
#endif |
|
|
/* realloc of null is supposed to be same as malloc */ |
if (oldmem == 0) return mALLOc(RCALL bytes); |
|
MALLOC_LOCK; |
|
newp = oldp = mem2chunk(oldmem); |
newsize = oldsize = chunksize(oldp); |
|
|
nb = request2size(bytes); |
|
#if HAVE_MMAP |
if (chunk_is_mmapped(oldp)) |
{ |
#if HAVE_MREMAP |
newp = mremap_chunk(oldp, nb); |
if(newp) |
{ |
MALLOC_UNLOCK; |
return chunk2mem(newp); |
} |
#endif |
/* Note the extra SIZE_SZ overhead. */ |
if(oldsize - SIZE_SZ >= nb) |
{ |
MALLOC_UNLOCK; |
return oldmem; /* do nothing */ |
} |
/* Must alloc, copy, free. */ |
newmem = mALLOc(RCALL bytes); |
if (newmem == 0) |
{ |
MALLOC_UNLOCK; |
return 0; /* propagate failure */ |
} |
MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); |
munmap_chunk(oldp); |
MALLOC_UNLOCK; |
return newmem; |
} |
#endif |
|
check_inuse_chunk(oldp); |
|
if ((long)(oldsize) < (long)(nb)) |
{ |
|
/* Try expanding forward */ |
|
next = chunk_at_offset(oldp, oldsize); |
if (next == top || !inuse(next)) |
{ |
nextsize = chunksize(next); |
|
/* Forward into top only if a remainder */ |
if (next == top) |
{ |
if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE)) |
{ |
newsize += nextsize; |
top = chunk_at_offset(oldp, nb); |
set_head(top, (newsize - nb) | PREV_INUSE); |
set_head_size(oldp, nb); |
MALLOC_UNLOCK; |
return chunk2mem(oldp); |
} |
} |
|
/* Forward into next chunk */ |
else if (((long)(nextsize + newsize) >= (long)(nb))) |
{ |
unlink(next, bck, fwd); |
newsize += nextsize; |
goto split; |
} |
} |
else |
{ |
next = 0; |
nextsize = 0; |
} |
|
/* Try shifting backwards. */ |
|
if (!prev_inuse(oldp)) |
{ |
prev = prev_chunk(oldp); |
prevsize = chunksize(prev); |
|
/* try forward + backward first to save a later consolidation */ |
|
if (next != 0) |
{ |
/* into top */ |
if (next == top) |
{ |
if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE)) |
{ |
unlink(prev, bck, fwd); |
newp = prev; |
newsize += prevsize + nextsize; |
newmem = chunk2mem(newp); |
MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
top = chunk_at_offset(newp, nb); |
set_head(top, (newsize - nb) | PREV_INUSE); |
set_head_size(newp, nb); |
MALLOC_UNLOCK; |
return newmem; |
} |
} |
|
/* into next chunk */ |
else if (((long)(nextsize + prevsize + newsize) >= (long)(nb))) |
{ |
unlink(next, bck, fwd); |
unlink(prev, bck, fwd); |
newp = prev; |
newsize += nextsize + prevsize; |
newmem = chunk2mem(newp); |
MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
goto split; |
} |
} |
|
/* backward only */ |
if (prev != 0 && (long)(prevsize + newsize) >= (long)nb) |
{ |
unlink(prev, bck, fwd); |
newp = prev; |
newsize += prevsize; |
newmem = chunk2mem(newp); |
MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
goto split; |
} |
} |
|
/* Must allocate */ |
|
newmem = mALLOc (RCALL bytes); |
|
if (newmem == 0) /* propagate failure */ |
{ |
MALLOC_UNLOCK; |
return 0; |
} |
|
/* Avoid copy if newp is next chunk after oldp. */ |
/* (This can only happen when new chunk is sbrk'ed.) */ |
|
if ( (newp = mem2chunk(newmem)) == next_chunk(oldp)) |
{ |
newsize += chunksize(newp); |
newp = oldp; |
goto split; |
} |
|
/* Otherwise copy, free, and exit */ |
MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); |
fREe(RCALL oldmem); |
MALLOC_UNLOCK; |
return newmem; |
} |
|
|
split: /* split off extra room in old or expanded chunk */ |
|
remainder_size = long_sub_size_t(newsize, nb); |
|
if (remainder_size >= (long)MINSIZE) /* split off remainder */ |
{ |
remainder = chunk_at_offset(newp, nb); |
set_head_size(newp, nb); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_inuse_bit_at_offset(remainder, remainder_size); |
fREe(RCALL chunk2mem(remainder)); /* let free() deal with it */ |
} |
else |
{ |
set_head_size(newp, newsize); |
set_inuse_bit_at_offset(newp, newsize); |
} |
|
check_inuse_chunk(newp); |
MALLOC_UNLOCK; |
return chunk2mem(newp); |
|
#endif /* MALLOC_PROVIDED */ |
} |
|
#endif /* DEFINE_REALLOC */ |
|
#ifdef DEFINE_MEMALIGN |
|
/* |
|
memalign algorithm: |
|
memalign requests more than enough space from malloc, finds a spot |
within that chunk that meets the alignment request, and then |
possibly frees the leading and trailing space. |
|
The alignment argument must be a power of two. This property is not |
checked by memalign, so misuse may result in random runtime errors. |
|
8-byte alignment is guaranteed by normal malloc calls, so don't |
bother calling memalign with an argument of 8 or less. |
|
Overreliance on memalign is a sure way to fragment space. |
|
*/ |
|
|
#if __STD_C |
Void_t* mEMALIGn(RARG size_t alignment, size_t bytes) |
#else |
Void_t* mEMALIGn(RARG alignment, bytes) RDECL size_t alignment; size_t bytes; |
#endif |
{ |
INTERNAL_SIZE_T nb; /* padded request size */ |
char* m; /* memory returned by malloc call */ |
mchunkptr p; /* corresponding chunk */ |
char* brk; /* alignment point within p */ |
mchunkptr newp; /* chunk to return */ |
INTERNAL_SIZE_T newsize; /* its size */ |
INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */ |
mchunkptr remainder; /* spare room at end to split off */ |
long remainder_size; /* its size */ |
|
/* If need less alignment than we give anyway, just relay to malloc */ |
|
if (alignment <= MALLOC_ALIGNMENT) return mALLOc(RCALL bytes); |
|
/* Otherwise, ensure that it is at least a minimum chunk size */ |
|
if (alignment < MINSIZE) alignment = MINSIZE; |
|
/* Call malloc with worst case padding to hit alignment. */ |
|
nb = request2size(bytes); |
m = (char*)(mALLOc(RCALL nb + alignment + MINSIZE)); |
|
if (m == 0) return 0; /* propagate failure */ |
|
MALLOC_LOCK; |
|
p = mem2chunk(m); |
|
if ((((unsigned long)(m)) % alignment) == 0) /* aligned */ |
{ |
#if HAVE_MMAP |
if(chunk_is_mmapped(p)) |
{ |
MALLOC_UNLOCK; |
return chunk2mem(p); /* nothing more to do */ |
} |
#endif |
} |
else /* misaligned */ |
{ |
/* |
Find an aligned spot inside chunk. |
Since we need to give back leading space in a chunk of at |
least MINSIZE, if the first calculation places us at |
a spot with less than MINSIZE leader, we can move to the |
next aligned spot -- we've allocated enough total room so that |
this is always possible. |
*/ |
|
brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -alignment); |
if ((long)(brk - (char*)(p)) < (long)MINSIZE) brk = brk + alignment; |
|
newp = (mchunkptr)brk; |
leadsize = brk - (char*)(p); |
newsize = chunksize(p) - leadsize; |
|
#if HAVE_MMAP |
if(chunk_is_mmapped(p)) |
{ |
newp->prev_size = p->prev_size + leadsize; |
set_head(newp, newsize|IS_MMAPPED); |
MALLOC_UNLOCK; |
return chunk2mem(newp); |
} |
#endif |
|
/* give back leader, use the rest */ |
|
set_head(newp, newsize | PREV_INUSE); |
set_inuse_bit_at_offset(newp, newsize); |
set_head_size(p, leadsize); |
fREe(RCALL chunk2mem(p)); |
p = newp; |
|
assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0); |
} |
|
/* Also give back spare room at the end */ |
|
remainder_size = long_sub_size_t(chunksize(p), nb); |
|
if (remainder_size >= (long)MINSIZE) |
{ |
remainder = chunk_at_offset(p, nb); |
set_head(remainder, remainder_size | PREV_INUSE); |
set_head_size(p, nb); |
fREe(RCALL chunk2mem(remainder)); |
} |
|
check_inuse_chunk(p); |
MALLOC_UNLOCK; |
return chunk2mem(p); |
|
} |
|
#endif /* DEFINE_MEMALIGN */ |
|
#ifdef DEFINE_VALLOC |
|
/* |
valloc just invokes memalign with alignment argument equal |
to the page size of the system (or as near to this as can |
be figured out from all the includes/defines above.) |
*/ |
|
#if __STD_C |
Void_t* vALLOc(RARG size_t bytes) |
#else |
Void_t* vALLOc(RARG bytes) RDECL size_t bytes; |
#endif |
{ |
return mEMALIGn (RCALL malloc_getpagesize, bytes); |
} |
|
#endif /* DEFINE_VALLOC */ |
|
#ifdef DEFINE_PVALLOC |
|
/* |
pvalloc just invokes valloc for the nearest pagesize |
that will accommodate request |
*/ |
|
|
#if __STD_C |
Void_t* pvALLOc(RARG size_t bytes) |
#else |
Void_t* pvALLOc(RARG bytes) RDECL size_t bytes; |
#endif |
{ |
size_t pagesize = malloc_getpagesize; |
return mEMALIGn (RCALL pagesize, (bytes + pagesize - 1) & ~(pagesize - 1)); |
} |
|
#endif /* DEFINE_PVALLOC */ |
|
#ifdef DEFINE_CALLOC |
|
/* |
|
calloc calls malloc, then zeroes out the allocated chunk. |
|
*/ |
|
#if __STD_C |
Void_t* cALLOc(RARG size_t n, size_t elem_size) |
#else |
Void_t* cALLOc(RARG n, elem_size) RDECL size_t n; size_t elem_size; |
#endif |
{ |
mchunkptr p; |
INTERNAL_SIZE_T csz; |
|
INTERNAL_SIZE_T sz = n * elem_size; |
|
#if MORECORE_CLEARS |
mchunkptr oldtop; |
INTERNAL_SIZE_T oldtopsize; |
#endif |
Void_t* mem; |
|
/* check if expand_top called, in which case don't need to clear */ |
#if MORECORE_CLEARS |
MALLOC_LOCK; |
oldtop = top; |
oldtopsize = chunksize(top); |
#endif |
|
mem = mALLOc (RCALL sz); |
|
if (mem == 0) |
{ |
#if MORECORE_CLEARS |
MALLOC_UNLOCK; |
#endif |
return 0; |
} |
else |
{ |
p = mem2chunk(mem); |
|
/* Two optional cases in which clearing not necessary */ |
|
|
#if HAVE_MMAP |
if (chunk_is_mmapped(p)) |
{ |
#if MORECORE_CLEARS |
MALLOC_UNLOCK; |
#endif |
return mem; |
} |
#endif |
|
csz = chunksize(p); |
|
#if MORECORE_CLEARS |
if (p == oldtop && csz > oldtopsize) |
{ |
/* clear only the bytes from non-freshly-sbrked memory */ |
csz = oldtopsize; |
} |
MALLOC_UNLOCK; |
#endif |
|
MALLOC_ZERO(mem, csz - SIZE_SZ); |
return mem; |
} |
} |
|
#endif /* DEFINE_CALLOC */ |
|
#if defined(DEFINE_CFREE) && !defined(__CYGWIN__) |
|
/* |
|
cfree just calls free. It is needed/defined on some systems |
that pair it with calloc, presumably for odd historical reasons. |
|
*/ |
|
#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__) |
#if !defined(INTERNAL_NEWLIB) || !defined(_REENT_ONLY) |
#if __STD_C |
void cfree(Void_t *mem) |
#else |
void cfree(mem) Void_t *mem; |
#endif |
{ |
#ifdef INTERNAL_NEWLIB |
fREe(_REENT, mem); |
#else |
fREe(mem); |
#endif |
} |
#endif |
#endif |
|
#endif /* DEFINE_CFREE */ |
|
#ifdef DEFINE_FREE |
|
/* |
|
Malloc_trim gives memory back to the system (via negative |
arguments to sbrk) if there is unused memory at the `high' end of |
the malloc pool. You can call this after freeing large blocks of |
memory to potentially reduce the system-level memory requirements |
of a program. However, it cannot guarantee to reduce memory. Under |
some allocation patterns, some large free blocks of memory will be |
locked between two used chunks, so they cannot be given back to |
the system. |
|
The `pad' argument to malloc_trim represents the amount of free |
trailing space to leave untrimmed. If this argument is zero, |
only the minimum amount of memory to maintain internal data |
structures will be left (one page or less). Non-zero arguments |
can be supplied to maintain enough trailing space to service |
future expected allocations without having to re-obtain memory |
from the system. |
|
Malloc_trim returns 1 if it actually released any memory, else 0. |
|
*/ |
|
#if __STD_C |
int malloc_trim(RARG size_t pad) |
#else |
int malloc_trim(RARG pad) RDECL size_t pad; |
#endif |
{ |
long top_size; /* Amount of top-most memory */ |
long extra; /* Amount to release */ |
char* current_brk; /* address returned by pre-check sbrk call */ |
char* new_brk; /* address returned by negative sbrk call */ |
|
unsigned long pagesz = malloc_getpagesize; |
|
MALLOC_LOCK; |
|
top_size = chunksize(top); |
extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; |
|
if (extra < (long)pagesz) /* Not enough memory to release */ |
{ |
MALLOC_UNLOCK; |
return 0; |
} |
|
else |
{ |
/* Test to make sure no one else called sbrk */ |
current_brk = (char*)(MORECORE (0)); |
if (current_brk != (char*)(top) + top_size) |
{ |
MALLOC_UNLOCK; |
return 0; /* Apparently we don't own memory; must fail */ |
} |
|
else |
{ |
new_brk = (char*)(MORECORE (-extra)); |
|
if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */ |
{ |
/* Try to figure out what we have */ |
current_brk = (char*)(MORECORE (0)); |
top_size = current_brk - (char*)top; |
if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */ |
{ |
sbrked_mem = current_brk - sbrk_base; |
set_head(top, top_size | PREV_INUSE); |
} |
check_chunk(top); |
MALLOC_UNLOCK; |
return 0; |
} |
|
else |
{ |
/* Success. Adjust top accordingly. */ |
set_head(top, (top_size - extra) | PREV_INUSE); |
sbrked_mem -= extra; |
check_chunk(top); |
MALLOC_UNLOCK; |
return 1; |
} |
} |
} |
} |
|
#endif /* DEFINE_FREE */ |
|
#ifdef DEFINE_MALLOC_USABLE_SIZE |
|
/* |
malloc_usable_size: |
|
This routine tells you how many bytes you can actually use in an |
allocated chunk, which may be more than you requested (although |
often not). You can use this many bytes without worrying about |
overwriting other allocated objects. Not a particularly great |
programming practice, but still sometimes useful. |
|
*/ |
|
#if __STD_C |
size_t malloc_usable_size(RARG Void_t* mem) |
#else |
size_t malloc_usable_size(RARG mem) RDECL Void_t* mem; |
#endif |
{ |
mchunkptr p; |
if (mem == 0) |
return 0; |
else |
{ |
p = mem2chunk(mem); |
if(!chunk_is_mmapped(p)) |
{ |
if (!inuse(p)) return 0; |
#if DEBUG |
MALLOC_LOCK; |
check_inuse_chunk(p); |
MALLOC_UNLOCK; |
#endif |
return chunksize(p) - SIZE_SZ; |
} |
return chunksize(p) - 2*SIZE_SZ; |
} |
} |
|
#endif /* DEFINE_MALLOC_USABLE_SIZE */ |
|
#ifdef DEFINE_MALLINFO |
|
/* Utility to update current_mallinfo for malloc_stats and mallinfo() */ |
|
STATIC void malloc_update_mallinfo() |
{ |
int i; |
mbinptr b; |
mchunkptr p; |
#if DEBUG |
mchunkptr q; |
#endif |
|
INTERNAL_SIZE_T avail = chunksize(top); |
int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0; |
|
for (i = 1; i < NAV; ++i) |
{ |
b = bin_at(i); |
for (p = last(b); p != b; p = p->bk) |
{ |
#if DEBUG |
check_free_chunk(p); |
for (q = next_chunk(p); |
q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; |
q = next_chunk(q)) |
check_inuse_chunk(q); |
#endif |
avail += chunksize(p); |
navail++; |
} |
} |
|
current_mallinfo.ordblks = navail; |
current_mallinfo.uordblks = sbrked_mem - avail; |
current_mallinfo.fordblks = avail; |
#if HAVE_MMAP |
current_mallinfo.hblks = n_mmaps; |
current_mallinfo.hblkhd = mmapped_mem; |
#endif |
current_mallinfo.keepcost = chunksize(top); |
|
} |
|
#else /* ! DEFINE_MALLINFO */ |
|
#if __STD_C |
extern void malloc_update_mallinfo(void); |
#else |
extern void malloc_update_mallinfo(); |
#endif |
|
#endif /* ! DEFINE_MALLINFO */ |
|
#ifdef DEFINE_MALLOC_STATS |
|
/* |
|
malloc_stats: |
|
Prints on stderr the amount of space obtain from the system (both |
via sbrk and mmap), the maximum amount (which may be more than |
current if malloc_trim and/or munmap got called), the maximum |
number of simultaneous mmap regions used, and the current number |
of bytes allocated via malloc (or realloc, etc) but not yet |
freed. (Note that this is the number of bytes allocated, not the |
number requested. It will be larger than the number requested |
because of alignment and bookkeeping overhead.) |
|
*/ |
|
#if __STD_C |
void malloc_stats(RONEARG) |
#else |
void malloc_stats(RONEARG) RDECL |
#endif |
{ |
unsigned long local_max_total_mem; |
int local_sbrked_mem; |
struct mallinfo local_mallinfo; |
#if HAVE_MMAP |
unsigned long local_mmapped_mem, local_max_n_mmaps; |
#endif |
FILE *fp; |
|
MALLOC_LOCK; |
malloc_update_mallinfo(); |
local_max_total_mem = max_total_mem; |
local_sbrked_mem = sbrked_mem; |
local_mallinfo = current_mallinfo; |
#if HAVE_MMAP |
local_mmapped_mem = mmapped_mem; |
local_max_n_mmaps = max_n_mmaps; |
#endif |
MALLOC_UNLOCK; |
|
#ifdef INTERNAL_NEWLIB |
fp = _stderr_r(reent_ptr); |
#define fprintf fiprintf |
#else |
fp = stderr; |
#endif |
|
fprintf(fp, "max system bytes = %10u\n", |
(unsigned int)(local_max_total_mem)); |
#if HAVE_MMAP |
fprintf(fp, "system bytes = %10u\n", |
(unsigned int)(local_sbrked_mem + local_mmapped_mem)); |
fprintf(fp, "in use bytes = %10u\n", |
(unsigned int)(local_mallinfo.uordblks + local_mmapped_mem)); |
#else |
fprintf(fp, "system bytes = %10u\n", |
(unsigned int)local_sbrked_mem); |
fprintf(fp, "in use bytes = %10u\n", |
(unsigned int)local_mallinfo.uordblks); |
#endif |
#if HAVE_MMAP |
fprintf(fp, "max mmap regions = %10u\n", |
(unsigned int)local_max_n_mmaps); |
#endif |
} |
|
#endif /* DEFINE_MALLOC_STATS */ |
|
#ifdef DEFINE_MALLINFO |
|
/* |
mallinfo returns a copy of updated current mallinfo. |
*/ |
|
#if __STD_C |
struct mallinfo mALLINFo(RONEARG) |
#else |
struct mallinfo mALLINFo(RONEARG) RDECL |
#endif |
{ |
struct mallinfo ret; |
|
MALLOC_LOCK; |
malloc_update_mallinfo(); |
ret = current_mallinfo; |
MALLOC_UNLOCK; |
return ret; |
} |
|
#endif /* DEFINE_MALLINFO */ |
|
#ifdef DEFINE_MALLOPT |
|
/* |
mallopt: |
|
mallopt is the general SVID/XPG interface to tunable parameters. |
The format is to provide a (parameter-number, parameter-value) pair. |
mallopt then sets the corresponding parameter to the argument |
value if it can (i.e., so long as the value is meaningful), |
and returns 1 if successful else 0. |
|
See descriptions of tunable parameters above. |
|
*/ |
|
#if __STD_C |
int mALLOPt(RARG int param_number, int value) |
#else |
int mALLOPt(RARG param_number, value) RDECL int param_number; int value; |
#endif |
{ |
MALLOC_LOCK; |
switch(param_number) |
{ |
case M_TRIM_THRESHOLD: |
trim_threshold = value; MALLOC_UNLOCK; return 1; |
case M_TOP_PAD: |
top_pad = value; MALLOC_UNLOCK; return 1; |
case M_MMAP_THRESHOLD: |
#if HAVE_MMAP |
mmap_threshold = value; |
#endif |
MALLOC_UNLOCK; |
return 1; |
case M_MMAP_MAX: |
#if HAVE_MMAP |
n_mmaps_max = value; MALLOC_UNLOCK; return 1; |
#else |
MALLOC_UNLOCK; return value == 0; |
#endif |
|
default: |
MALLOC_UNLOCK; |
return 0; |
} |
} |
|
#endif /* DEFINE_MALLOPT */ |
|
/* |
|
History: |
|
V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) |
* Added pvalloc, as recommended by H.J. Liu |
* Added 64bit pointer support mainly from Wolfram Gloger |
* Added anonymously donated WIN32 sbrk emulation |
* Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen |
* malloc_extend_top: fix mask error that caused wastage after |
foreign sbrks |
* Add linux mremap support code from HJ Liu |
|
V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) |
* Integrated most documentation with the code. |
* Add support for mmap, with help from |
Wolfram Gloger (Gloger@lrz.uni-muenchen.de). |
* Use last_remainder in more cases. |
* Pack bins using idea from colin@nyx10.cs.du.edu |
* Use ordered bins instead of best-fit threshhold |
* Eliminate block-local decls to simplify tracing and debugging. |
* Support another case of realloc via move into top |
* Fix error occuring when initial sbrk_base not word-aligned. |
* Rely on page size for units instead of SBRK_UNIT to |
avoid surprises about sbrk alignment conventions. |
* Add mallinfo, mallopt. Thanks to Raymond Nijssen |
(raymond@es.ele.tue.nl) for the suggestion. |
* Add `pad' argument to malloc_trim and top_pad mallopt parameter. |
* More precautions for cases where other routines call sbrk, |
courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). |
* Added macros etc., allowing use in linux libc from |
H.J. Lu (hjl@gnu.ai.mit.edu) |
* Inverted this history list |
|
V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) |
* Re-tuned and fixed to behave more nicely with V2.6.0 changes. |
* Removed all preallocation code since under current scheme |
the work required to undo bad preallocations exceeds |
the work saved in good cases for most test programs. |
* No longer use return list or unconsolidated bins since |
no scheme using them consistently outperforms those that don't |
given above changes. |
* Use best fit for very large chunks to prevent some worst-cases. |
* Added some support for debugging |
|
V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) |
* Removed footers when chunks are in use. Thanks to |
Paul Wilson (wilson@cs.texas.edu) for the suggestion. |
|
V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) |
* Added malloc_trim, with help from Wolfram Gloger |
(wmglo@Dent.MED.Uni-Muenchen.DE). |
|
V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) |
|
V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) |
* realloc: try to expand in both directions |
* malloc: swap order of clean-bin strategy; |
* realloc: only conditionally expand backwards |
* Try not to scavenge used bins |
* Use bin counts as a guide to preallocation |
* Occasionally bin return list chunks in first scan |
* Add a few optimizations from colin@nyx10.cs.du.edu |
|
V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) |
* faster bin computation & slightly different binning |
* merged all consolidations to one part of malloc proper |
(eliminating old malloc_find_space & malloc_clean_bin) |
* Scan 2 returns chunks (not just 1) |
* Propagate failure in realloc if malloc returns 0 |
* Add stuff to allow compilation on non-ANSI compilers |
from kpv@research.att.com |
|
V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) |
* removed potential for odd address access in prev_chunk |
* removed dependency on getpagesize.h |
* misc cosmetics and a bit more internal documentation |
* anticosmetics: mangled names in macros to evade debugger strangeness |
* tested on sparc, hp-700, dec-mips, rs6000 |
with gcc & native cc (hp, dec only) allowing |
Detlefs & Zorn comparison study (in SIGPLAN Notices.) |
|
Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) |
* Based loosely on libg++-1.2X malloc. (It retains some of the overall |
structure of old version, but most details differ.) |
|
*/ |
#endif |
/atof.c
0,0 → 1,72
/* |
FUNCTION |
<<atof>>, <<atoff>>---string to double or float |
|
INDEX |
atof |
INDEX |
atoff |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
double atof(const char *<[s]>); |
float atoff(const char *<[s]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
double atof(<[s]>) |
char *<[s]>; |
|
float atoff(<[s]>) |
char *<[s]>; |
|
DESCRIPTION |
<<atof>> converts the initial portion of a string to a <<double>>. |
<<atoff>> converts the initial portion of a string to a <<float>>. |
|
The functions parse the character string <[s]>, |
locating a substring which can be converted to a floating point |
value. The substring must match the format: |
. [+|-]<[digits]>[.][<[digits]>][(e|E)[+|-]<[digits]>] |
The substring converted is the longest initial |
fragment of <[s]> that has the expected format, beginning with |
the first non-whitespace character. The substring |
is empty if <<str>> is empty, consists entirely |
of whitespace, or if the first non-whitespace character is |
something other than <<+>>, <<->>, <<.>>, or a digit. |
|
<<atof(<[s]>)>> is implemented as <<strtod(<[s]>, NULL)>>. |
<<atoff(<[s]>)>> is implemented as <<strtodf(<[s]>, NULL)>>. |
|
RETURNS |
<<atof>> returns the converted substring value, if any, as a |
<<double>>; or <<0.0>>, if no conversion could be performed. |
If the correct value is out of the range of representable values, plus |
or minus <<HUGE_VAL>> is returned, and <<ERANGE>> is stored in |
<<errno>>. |
If the correct value would cause underflow, <<0.0>> is returned |
and <<ERANGE>> is stored in <<errno>>. |
|
<<atoff>> obeys the same rules as <<atof>>, except that it |
returns a <<float>>. |
|
PORTABILITY |
<<atof>> is ANSI C. <<atof>>, <<atoi>>, and <<atol>> are subsumed by <<strod>> |
and <<strol>>, but are used extensively in existing code. These functions are |
less reliable, but may be faster if the argument is verified to be in a valid |
range. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
|
#include <stdlib.h> |
#include <_ansi.h> |
|
double |
_DEFUN (atof, (s), |
_CONST char *s) |
{ |
return strtod (s, NULL); |
} |
/mblen.c
0,0 → 1,66
/* |
FUNCTION |
<<mblen>>---minimal multibyte length function |
|
INDEX |
mblen |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int mblen(const char *<[s]>, size_t <[n]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int mblen(<[s]>, <[n]>) |
const char *<[s]>; |
size_t <[n]>; |
|
DESCRIPTION |
When MB_CAPABLE is not defined, this is a minimal ANSI-conforming |
implementation of <<mblen>>. In this case, the |
only ``multi-byte character sequences'' recognized are single bytes, |
and thus <<1>> is returned unless <[s]> is the null pointer or |
has a length of 0 or is the empty string. |
|
When MB_CAPABLE is defined, this routine calls <<_mbtowc_r>> to perform |
the conversion, passing a state variable to allow state dependent |
decoding. The result is based on the locale setting which may |
be restricted to a defined set of locales. |
|
RETURNS |
This implementation of <<mblen>> returns <<0>> if |
<[s]> is <<NULL>> or the empty string; it returns <<1>> if not MB_CAPABLE or |
the character is a single-byte character; it returns <<-1>> |
if the multi-byte character is invalid; otherwise it returns |
the number of bytes in the multibyte character. |
|
PORTABILITY |
<<mblen>> is required in the ANSI C standard. However, the precise |
effects vary with the locale. |
|
<<mblen>> requires no supporting OS subroutines. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
|
int |
_DEFUN (mblen, (s, n), |
const char *s _AND |
size_t n) |
{ |
#ifdef MB_CAPABLE |
static int state; |
|
return _mbtowc_r (_REENT, NULL, s, n, &state); |
#else /* not MB_CAPABLE */ |
if (s == NULL || *s == '\0') |
return 0; |
if (n == 0) |
return -1; |
return 1; |
#endif /* not MB_CAPABLE */ |
} |
|
#endif /* !_REENT_ONLY */ |
/atexit.c
0,0 → 1,80
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* %sccs.include.redist.c% |
*/ |
|
/* |
FUNCTION |
<<atexit>>---request execution of functions at program exit |
|
INDEX |
atexit |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int atexit (void (*<[function]>)(void)); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int atexit ((<[function]>) |
void (*<[function]>)(); |
|
DESCRIPTION |
You can use <<atexit>> to enroll functions in a list of functions that |
will be called when your program terminates normally. The argument is |
a pointer to a user-defined function (which must not require arguments and |
must not return a result). |
|
The functions are kept in a LIFO stack; that is, the last function |
enrolled by <<atexit>> will be the first to execute when your program |
exits. |
|
There is no built-in limit to the number of functions you can enroll |
in this list; however, after every group of 32 functions is enrolled, |
<<atexit>> will call <<malloc>> to get space for the next part of the |
list. The initial list of 32 functions is statically allocated, so |
you can always count on at least that many slots available. |
|
RETURNS |
<<atexit>> returns <<0>> if it succeeds in enrolling your function, |
<<-1>> if it fails (possible only if no space was available for |
<<malloc>> to extend the list of functions). |
|
PORTABILITY |
<<atexit>> is required by the ANSI standard, which also specifies that |
implementations must support enrolling at least 32 functions. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
#include <stddef.h> |
#include <stdlib.h> |
#include <reent.h> |
|
/* |
* Register a function to be performed at exit. |
*/ |
|
int |
_DEFUN (atexit, |
(fn), |
_VOID _EXFUN ((*fn), (_VOID))) |
{ |
register struct _atexit *p; |
|
if ((p = _REENT->_atexit) == NULL) |
_REENT->_atexit = p = &_REENT->_atexit0; |
if (p->_ind >= _ATEXIT_SIZE) |
{ |
if ((p = (struct _atexit *) malloc (sizeof *p)) == NULL) |
return -1; |
p->_ind = 0; |
p->_next = _REENT->_atexit; |
_REENT->_atexit = p; |
} |
p->_fns[p->_ind++] = fn; |
return 0; |
} |
/ecvtbuf.c
0,0 → 1,469
/* |
FUNCTION |
<<ecvtbuf>>, <<fcvtbuf>>---double or float to string |
|
INDEX |
ecvtbuf |
INDEX |
fcvtbuf |
|
ANSI_SYNOPSIS |
#include <stdio.h> |
|
char *ecvtbuf(double <[val]>, int <[chars]>, int *<[decpt]>, |
int *<[sgn]>, char *<[buf]>); |
|
char *fcvtbuf(double <[val]>, int <[decimals]>, int *<[decpt]>, |
int *<[sgn]>, char *<[buf]>); |
|
TRAD_SYNOPSIS |
#include <stdio.h> |
|
char *ecvtbuf(<[val]>, <[chars]>, <[decpt]>, <[sgn]>, <[buf]>); |
double <[val]>; |
int <[chars]>; |
int *<[decpt]>; |
int *<[sgn]>; |
char *<[buf]>; |
|
char *fcvtbuf(<[val]>, <[decimals]>, <[decpt]>, <[sgn]>, <[buf]>); |
double <[val]>; |
int <[decimals]>; |
int *<[decpt]>; |
int *<[sgn]>; |
char *<[buf]>; |
|
DESCRIPTION |
<<ecvtbuf>> and <<fcvtbuf>> produce (null-terminated) strings |
of digits representating the <<double>> number <[val]>. |
|
The only difference between <<ecvtbuf>> and <<fcvtbuf>> is the |
interpretation of the second argument (<[chars]> or |
<[decimals]>). For <<ecvtbuf>>, the second argument <[chars]> |
specifies the total number of characters to write (which is |
also the number of significant digits in the formatted string, |
since these two functions write only digits). For <<fcvtbuf>>, |
the second argument <[decimals]> specifies the number of |
characters to write after the decimal point; all digits for |
the integer part of <[val]> are always included. |
|
Since <<ecvtbuf>> and <<fcvtbuf>> write only digits in the |
output string, they record the location of the decimal point |
in <<*<[decpt]>>>, and the sign of the number in <<*<[sgn]>>>. |
After formatting a number, <<*<[decpt]>>> contains the number |
of digits to the left of the decimal point. <<*<[sgn]>>> |
contains <<0>> if the number is positive, and <<1>> if it is |
negative. For both functions, you supply a pointer <[buf]> to |
an area of memory to hold the converted string. |
|
RETURNS |
Both functions return a pointer to <[buf]>, the string |
containing a character representation of <[val]>. |
|
PORTABILITY |
Neither function is ANSI C. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
#include <_ansi.h> |
#include <stdlib.h> |
#include <string.h> |
#include <reent.h> |
#include "mprec.h" |
#include "local.h" |
|
static void |
_DEFUN (print_f, (ptr, buf, invalue, ndigit, type, dot, mode), |
struct _reent *ptr _AND |
char *buf _AND |
double invalue _AND |
int ndigit _AND |
char type _AND |
int dot _AND |
int mode) |
{ |
int decpt; |
int sign; |
char *p, *start, *end; |
|
start = p = _dtoa_r (ptr, invalue, mode, ndigit, &decpt, &sign, &end); |
|
if (decpt == 9999) |
{ |
strcpy (buf, p); |
return; |
} |
while (*p && decpt > 0) |
{ |
*buf++ = *p++; |
decpt--; |
} |
/* Even if not in buffer */ |
while (decpt > 0) |
{ |
*buf++ = '0'; |
decpt--; |
} |
|
if (dot || *p) |
{ |
if (p == start) |
*buf++ = '0'; |
*buf++ = '.'; |
while (decpt < 0 && ndigit > 0) |
{ |
*buf++ = '0'; |
decpt++; |
ndigit--; |
} |
|
/* Print rest of stuff */ |
while (*p && ndigit > 0) |
{ |
*buf++ = *p++; |
ndigit--; |
} |
/* And trailing zeros */ |
while (ndigit > 0) |
{ |
*buf++ = '0'; |
ndigit--; |
} |
} |
*buf++ = 0; |
} |
|
/* Print number in e format with width chars after. |
|
TYPE is one of 'e' or 'E'. It may also be one of 'g' or 'G' indicating |
that _gcvt is calling us and we should remove trailing zeroes. |
|
WIDTH is the number of digits of precision after the decimal point. */ |
|
static void |
_DEFUN (print_e, (ptr, buf, invalue, width, type, dot), |
struct _reent *ptr _AND |
char *buf _AND |
double invalue _AND |
int width _AND |
char type _AND |
int dot) |
{ |
int sign; |
char *end; |
char *p; |
int decpt; |
int top; |
int ndigit = width; |
|
p = _dtoa_r (ptr, invalue, 2, width + 1, &decpt, &sign, &end); |
|
if (decpt == 9999) |
{ |
strcpy (buf, p); |
return; |
} |
|
*buf++ = *p++; |
if (dot || ndigit != 0) |
*buf++ = '.'; |
|
while (*p && ndigit > 0) |
{ |
*buf++ = *p++; |
ndigit--; |
} |
|
/* Add trailing zeroes to fill out to ndigits unless this is 'g' format. |
Also, convert g/G to e/E. */ |
|
if (type == 'g') |
type = 'e'; |
else if (type == 'G') |
type = 'E'; |
else |
{ |
while (ndigit > 0) |
{ |
*buf++ = '0'; |
ndigit--; |
} |
} |
|
/* Add the exponent. */ |
|
*buf++ = type; |
decpt--; |
if (decpt < 0) |
{ |
*buf++ = '-'; |
decpt = -decpt; |
} |
else |
{ |
*buf++ = '+'; |
} |
if (decpt > 99) |
{ |
int top = decpt / 100; |
*buf++ = top + '0'; |
decpt -= top * 100; |
} |
top = decpt / 10; |
*buf++ = top + '0'; |
decpt -= top * 10; |
*buf++ = decpt + '0'; |
|
*buf++ = 0; |
} |
|
#ifndef _REENT_ONLY |
|
/* Undocumented behaviour: when given NULL as a buffer, return a |
pointer to static space in the rent structure. This is only to |
support ecvt and fcvt, which aren't ANSI anyway. */ |
|
char * |
_DEFUN (fcvtbuf, (invalue, ndigit, decpt, sign, fcvt_buf), |
double invalue _AND |
int ndigit _AND |
int *decpt _AND |
int *sign _AND |
char *fcvt_buf) |
{ |
char *save; |
char *p; |
char *end; |
int done = 0; |
|
if (fcvt_buf == NULL) |
{ |
if (_REENT->_cvtlen <= ndigit + 35) |
{ |
if ((fcvt_buf = (char *) _realloc_r (_REENT, _REENT->_cvtbuf, |
ndigit + 36)) == NULL) |
return NULL; |
_REENT->_cvtlen = ndigit + 36; |
_REENT->_cvtbuf = fcvt_buf; |
} |
|
fcvt_buf = _REENT->_cvtbuf ; |
} |
|
save = fcvt_buf; |
|
if (invalue < 1.0 && invalue > -1.0) |
{ |
p = _dtoa_r (_REENT, invalue, 2, ndigit, decpt, sign, &end); |
} |
else |
{ |
p = _dtoa_r (_REENT, invalue, 3, ndigit, decpt, sign, &end); |
} |
|
/* Now copy */ |
|
done = -*decpt; |
while (p < end) |
{ |
*fcvt_buf++ = *p++; |
done++; |
} |
/* And unsuppress the trailing zeroes */ |
while (done < ndigit) |
{ |
*fcvt_buf++ = '0'; |
done++; |
} |
*fcvt_buf++ = 0; |
return save; |
} |
|
char * |
_DEFUN (ecvtbuf, (invalue, ndigit, decpt, sign, fcvt_buf), |
double invalue _AND |
int ndigit _AND |
int *decpt _AND |
int *sign _AND |
char *fcvt_buf) |
{ |
char *save; |
char *p; |
char *end; |
int done = 0; |
|
if (fcvt_buf == NULL) |
{ |
if (_REENT->_cvtlen <= ndigit) |
{ |
if ((fcvt_buf = (char *) _realloc_r (_REENT, _REENT->_cvtbuf, |
ndigit + 1)) == NULL) |
return NULL; |
_REENT->_cvtlen = ndigit + 1; |
_REENT->_cvtbuf = fcvt_buf; |
} |
|
fcvt_buf = _REENT->_cvtbuf ; |
} |
|
save = fcvt_buf; |
|
p = _dtoa_r (_REENT, invalue, 2, ndigit, decpt, sign, &end); |
|
/* Now copy */ |
|
while (p < end) |
{ |
*fcvt_buf++ = *p++; |
done++; |
} |
/* And unsuppress the trailing zeroes */ |
while (done < ndigit) |
{ |
*fcvt_buf++ = '0'; |
done++; |
} |
*fcvt_buf++ = 0; |
return save; |
} |
|
#endif |
|
char * |
_DEFUN (_gcvt, (ptr, invalue, ndigit, buf, type, dot), |
struct _reent *ptr _AND |
double invalue _AND |
int ndigit _AND |
char *buf _AND |
char type _AND |
int dot) |
{ |
char *save = buf; |
|
if (invalue < 0) |
{ |
invalue = -invalue; |
} |
|
if (invalue == 0) |
{ |
*buf++ = '0'; |
*buf = '\0'; |
} |
else |
/* Which one to print ? |
ANSI says that anything with more that 4 zeros after the . or more |
than precision digits before is printed in e with the qualification |
that trailing zeroes are removed from the fraction portion. */ |
|
if (0.0001 >= invalue || invalue >= _mprec_log10 (ndigit)) |
{ |
/* We subtract 1 from ndigit because in the 'e' format the precision is |
the number of digits after the . but in 'g' format it is the number |
of significant digits. |
|
We defer changing type to e/E so that print_e() can know it's us |
calling and thus should remove trailing zeroes. */ |
|
print_e (ptr, buf, invalue, ndigit - 1, type, dot); |
} |
else |
{ |
int decpt; |
int sign; |
char *end; |
char *p; |
|
if (invalue < 1.0) |
{ |
/* what we want is ndigits after the point */ |
p = _dtoa_r (ptr, invalue, 3, ndigit, &decpt, &sign, &end); |
} |
else |
{ |
p = _dtoa_r (ptr, invalue, 2, ndigit, &decpt, &sign, &end); |
} |
|
if (decpt == 9999) |
{ |
strcpy (buf, p); |
return save; |
} |
while (*p && decpt > 0) |
{ |
*buf++ = *p++; |
decpt--; |
ndigit--; |
} |
/* Even if not in buffer */ |
while (decpt > 0 && ndigit > 0) |
{ |
*buf++ = '0'; |
decpt--; |
ndigit--; |
} |
|
if (dot || *p) |
{ |
if (buf == save) |
*buf++ = '0'; |
*buf++ = '.'; |
while (decpt < 0 && ndigit > 0) |
{ |
*buf++ = '0'; |
decpt++; |
ndigit--; |
} |
|
/* Print rest of stuff */ |
while (*p && ndigit > 0) |
{ |
*buf++ = *p++; |
ndigit--; |
} |
/* And trailing zeros */ |
if (dot) |
{ |
while (ndigit > 0) |
{ |
*buf++ = '0'; |
ndigit--; |
} |
} |
} |
*buf++ = 0; |
} |
|
return save; |
} |
|
char * |
_DEFUN (_dcvt, (ptr, buffer, invalue, precision, width, type, dot), |
struct _reent *ptr _AND |
char *buffer _AND |
double invalue _AND |
int precision _AND |
int width _AND |
char type _AND |
int dot) |
{ |
switch (type) |
{ |
case 'f': |
case 'F': |
print_f (ptr, buffer, invalue, precision, type, precision == 0 ? dot : 1, 3); |
break; |
case 'g': |
case 'G': |
if (precision == 0) |
precision = 1; |
_gcvt (ptr, invalue, precision, buffer, type, dot); |
break; |
case 'e': |
case 'E': |
print_e (ptr, buffer, invalue, precision, type, dot); |
} |
return buffer; |
} |
/atol.c
0,0 → 1,12
/* |
* Andy Wilson, 2-Oct-89. |
*/ |
|
#include <stdlib.h> |
#include <_ansi.h> |
|
long |
_DEFUN (atol, (s), _CONST char *s) |
{ |
return strtol (s, NULL, 10); |
} |
/mbstowcs.c
0,0 → 1,80
/* |
FUNCTION |
<<mbstowcs>>---minimal multibyte string to wide char converter |
|
INDEX |
mbstowcs |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int mbstowcs(wchar_t *<[pwc]>, const char *<[s]>, size_t <[n]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int mbstowcs(<[pwc]>, <[s]>, <[n]>) |
wchar_t *<[pwc]>; |
const char *<[s]>; |
size_t <[n]>; |
|
DESCRIPTION |
When MB_CAPABLE is not defined, this is a minimal ANSI-conforming |
implementation of <<mbstowcs>>. In this case, the |
only ``multi-byte character sequences'' recognized are single bytes, |
and they are ``converted'' to wide-char versions simply by byte |
extension. |
|
When MB_CAPABLE is defined, this routine calls <<_mbstowcs_r>> to perform |
the conversion, passing a state variable to allow state dependent |
decoding. The result is based on the locale setting which may |
be restricted to a defined set of locales. |
|
RETURNS |
This implementation of <<mbstowcs>> returns <<0>> if |
<[s]> is <<NULL>> or is the empty string; |
it returns <<-1>> if MB_CAPABLE and one of the |
multi-byte characters is invalid or incomplete; |
otherwise it returns the minimum of: <<n>> or the |
number of multi-byte characters in <<s>> plus 1 (to |
compensate for the nul character). |
If the return value is -1, the state of the <<pwc>> string is |
indeterminate. If the input has a length of 0, the output |
string will be modified to contain a wchar_t nul terminator. |
|
PORTABILITY |
<<mbstowcs>> is required in the ANSI C standard. However, the precise |
effects vary with the locale. |
|
<<mbstowcs>> requires no supporting OS subroutines. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
|
size_t |
_DEFUN (mbstowcs, (pwcs, s, n), |
wchar_t *pwcs _AND |
const char *s _AND |
size_t n) |
{ |
#ifdef MB_CAPABLE |
int state = 0; |
|
return _mbstowcs_r (_REENT, pwcs, s, n, &state); |
#else /* not MB_CAPABLE */ |
|
int count = 0; |
|
if (n != 0) { |
do { |
if ((*pwcs++ = (wchar_t) *s++) == 0) |
break; |
count++; |
} while (--n != 0); |
} |
|
return count; |
#endif /* not MB_CAPABLE */ |
} |
|
#endif /* !_REENT_ONLY */ |
/getopt.c
0,0 → 1,117
/* |
* Copyright (c) 1987, 1993, 1994 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#if defined(LIBC_SCCS) && !defined(lint) |
/* static char sccsid[] = "from: @(#)getopt.c 8.2 (Berkeley) 4/2/94"; */ |
static char *rcsid = "$Id: getopt.c,v 1.1 2002-08-23 22:31:29 ivang Exp $"; |
#endif /* LIBC_SCCS and not lint */ |
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
|
int opterr = 1, /* if error message should be printed */ |
optind = 1, /* index into parent argv vector */ |
optopt, /* character checked for validity */ |
optreset; /* reset getopt */ |
char *optarg; /* argument associated with option */ |
|
#define BADCH (int)'?' |
#define BADARG (int)':' |
#define EMSG "" |
|
/* |
* getopt -- |
* Parse argc/argv argument vector. |
*/ |
int |
getopt(nargc, nargv, ostr) |
int nargc; |
char * const *nargv; |
const char *ostr; |
{ |
static char *place = EMSG; /* option letter processing */ |
char *oli; /* option letter list index */ |
|
if (optreset || !*place) { /* update scanning pointer */ |
optreset = 0; |
if (optind >= nargc || *(place = nargv[optind]) != '-') { |
place = EMSG; |
return (-1); |
} |
if (place[1] && *++place == '-') { /* found "--" */ |
++optind; |
place = EMSG; |
return (-1); |
} |
} /* option letter okay? */ |
if ((optopt = (int)*place++) == (int)':' || |
!(oli = strchr(ostr, optopt))) { |
/* |
* if the user didn't specify '-' as an option, |
* assume it means -1. |
*/ |
if (optopt == (int)'-') |
return (-1); |
if (!*place) |
++optind; |
if (opterr && *ostr != ':') |
(void)fprintf(stderr, |
"%s: illegal option -- %c\n", nargv[0], optopt); |
return (BADCH); |
} |
if (*++oli != ':') { /* don't need argument */ |
optarg = NULL; |
if (!*place) |
++optind; |
} |
else { /* need an argument */ |
if (*place) /* no white space */ |
optarg = place; |
else if (nargc <= ++optind) { /* no arg */ |
place = EMSG; |
if (*ostr == ':') |
return (BADARG); |
if (opterr) |
(void)fprintf(stderr, |
"%s: option requires an argument -- %c\n", |
nargv[0], optopt); |
return (BADCH); |
} |
else /* white space */ |
optarg = nargv[optind]; |
place = EMSG; |
++optind; |
} |
return (optopt); /* dump back option letter */ |
} |
/ldtoa.c
0,0 → 1,3720
|
/* Extended precision arithmetic functions for long double I/O. |
* This program has been placed in the public domain. |
*/ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <string.h> |
#include <stdlib.h> |
#include "mprec.h" |
|
/* These are the externally visible entries. */ |
/* linux name: long double _IO_strtold (char *, char **); */ |
long double _strtold (char *, char **); |
char * _ldtoa_r (struct _reent *, long double, int, int, int *, int *, char **); |
int _ldcheck (long double *); |
#if 0 |
void _IO_ldtostr(long double *, char *, int, int, char); |
#endif |
|
/* Number of 16 bit words in external x type format */ |
#define NE 10 |
|
/* Number of 16 bit words in internal format */ |
#define NI (NE+3) |
|
/* Array offset to exponent */ |
#define E 1 |
|
/* Array offset to high guard word */ |
#define M 2 |
|
/* Number of bits of precision */ |
#define NBITS ((NI-4)*16) |
|
/* Maximum number of decimal digits in ASCII conversion |
* = NBITS*log10(2) |
*/ |
#define NDEC (NBITS*8/27) |
|
/* The exponent of 1.0 */ |
#define EXONE (0x3fff) |
|
/* Control structure for long doublue conversion including rounding precision values. |
* rndprc can be set to 80 (if NE=6), 64, 56, 53, or 24 bits. |
*/ |
typedef struct |
{ |
int rlast; |
int rndprc; |
int rw; |
int re; |
int outexpon; |
unsigned short rmsk; |
unsigned short rmbit; |
unsigned short rebit; |
unsigned short rbit[NI]; |
unsigned short equot[NI]; |
} LDPARMS; |
|
static void esub(short unsigned int *a, short unsigned int *b, short unsigned int *c, LDPARMS *ldp); |
static void emul(short unsigned int *a, short unsigned int *b, short unsigned int *c, LDPARMS *ldp); |
static void ediv(short unsigned int *a, short unsigned int *b, short unsigned int *c, LDPARMS *ldp); |
static int ecmp(short unsigned int *a, short unsigned int *b); |
static int enormlz(short unsigned int *x); |
static int eshift(short unsigned int *x, int sc); |
static void eshup1(register short unsigned int *x); |
static void eshup8(register short unsigned int *x); |
static void eshup6(register short unsigned int *x); |
static void eshdn1(register short unsigned int *x); |
static void eshdn8(register short unsigned int *x); |
static void eshdn6(register short unsigned int *x); |
static void eneg(short unsigned int *x); |
static void emov(register short unsigned int *a, register short unsigned int *b); |
static void eclear(register short unsigned int *x); |
static void einfin(register short unsigned int *x, register LDPARMS *ldp); |
static void efloor(short unsigned int *x, short unsigned int *y, LDPARMS *ldp); |
static void etoasc(short unsigned int *x, char *string, int ndigs, int outformat, LDPARMS *ldp); |
|
#if LDBL_MANT_DIG == 24 |
static void e24toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp); |
#elif LDBL_MANT_DIG == 53 |
static void e53toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp); |
#elif LDBL_MANT_DIG == 64 |
static void e64toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp); |
#else |
static void e113toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp); |
#endif |
|
/* econst.c */ |
/* e type constants used by high precision check routines */ |
|
#if NE == 10 |
/* 0.0 */ |
static unsigned short ezero[NE] = |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,}; |
|
/* 1.0E0 */ |
static unsigned short eone[NE] = |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0x3fff,}; |
|
#else |
|
/* 0.0 */ |
static unsigned short ezero[NE] = { |
0, 0000000,0000000,0000000,0000000,0000000,}; |
/* 1.0E0 */ |
static unsigned short eone[NE] = { |
0, 0000000,0000000,0000000,0100000,0x3fff,}; |
|
#endif |
|
/* Debugging routine for displaying errors */ |
#ifdef DEBUG |
/* Notice: the order of appearance of the following |
* messages is bound to the error codes defined |
* in mconf.h. |
*/ |
static char *ermsg[7] = { |
"unknown", /* error code 0 */ |
"domain", /* error code 1 */ |
"singularity", /* et seq. */ |
"overflow", |
"underflow", |
"total loss of precision", |
"partial loss of precision" |
}; |
#define mtherr(name, code) printf( "\n%s %s error\n", name, ermsg[code] ); |
#else |
#define mtherr(name, code) |
#endif |
|
/* ieee.c |
* |
* Extended precision IEEE binary floating point arithmetic routines |
* |
* Numbers are stored in C language as arrays of 16-bit unsigned |
* short integers. The arguments of the routines are pointers to |
* the arrays. |
* |
* |
* External e type data structure, simulates Intel 8087 chip |
* temporary real format but possibly with a larger significand: |
* |
* NE-1 significand words (least significant word first, |
* most significant bit is normally set) |
* exponent (value = EXONE for 1.0, |
* top bit is the sign) |
* |
* |
* Internal data structure of a number (a "word" is 16 bits): |
* |
* ei[0] sign word (0 for positive, 0xffff for negative) |
* ei[1] biased exponent (value = EXONE for the number 1.0) |
* ei[2] high guard word (always zero after normalization) |
* ei[3] |
* to ei[NI-2] significand (NI-4 significand words, |
* most significant word first, |
* most significant bit is set) |
* ei[NI-1] low guard word (0x8000 bit is rounding place) |
* |
* |
* |
* Routines for external format numbers |
* |
* asctoe( string, e ) ASCII string to extended double e type |
* asctoe64( string, &d ) ASCII string to long double |
* asctoe53( string, &d ) ASCII string to double |
* asctoe24( string, &f ) ASCII string to single |
* asctoeg( string, e, prec, ldp ) ASCII string to specified precision |
* e24toe( &f, e, ldp ) IEEE single precision to e type |
* e53toe( &d, e, ldp ) IEEE double precision to e type |
* e64toe( &d, e, ldp ) IEEE long double precision to e type |
* e113toe( &d, e, ldp ) IEEE long double precision to e type |
* eabs(e) absolute value |
* eadd( a, b, c ) c = b + a |
* eclear(e) e = 0 |
* ecmp (a, b) Returns 1 if a > b, 0 if a == b, |
* -1 if a < b, -2 if either a or b is a NaN. |
* ediv( a, b, c, ldp ) c = b / a |
* efloor( a, b, ldp ) truncate to integer, toward -infinity |
* efrexp( a, exp, s ) extract exponent and significand |
* eifrac( e, &l, frac ) e to long integer and e type fraction |
* euifrac( e, &l, frac ) e to unsigned long integer and e type fraction |
* einfin( e, ldp ) set e to infinity, leaving its sign alone |
* eldexp( a, n, b ) multiply by 2**n |
* emov( a, b ) b = a |
* emul( a, b, c, ldp ) c = b * a |
* eneg(e) e = -e |
* eround( a, b ) b = nearest integer value to a |
* esub( a, b, c, ldp ) c = b - a |
* e24toasc( &f, str, n ) single to ASCII string, n digits after decimal |
* e53toasc( &d, str, n ) double to ASCII string, n digits after decimal |
* e64toasc( &d, str, n ) long double to ASCII string |
* etoasc(e,str,n,fmt,ldp)e to ASCII string, n digits after decimal |
* etoe24( e, &f ) convert e type to IEEE single precision |
* etoe53( e, &d ) convert e type to IEEE double precision |
* etoe64( e, &d ) convert e type to IEEE long double precision |
* ltoe( &l, e ) long (32 bit) integer to e type |
* ultoe( &l, e ) unsigned long (32 bit) integer to e type |
* eisneg( e ) 1 if sign bit of e != 0, else 0 |
* eisinf( e ) 1 if e has maximum exponent (non-IEEE) |
* or is infinite (IEEE) |
* eisnan( e ) 1 if e is a NaN |
* esqrt( a, b ) b = square root of a |
* |
* |
* Routines for internal format numbers |
* |
* eaddm( ai, bi ) add significands, bi = bi + ai |
* ecleaz(ei) ei = 0 |
* ecleazs(ei) set ei = 0 but leave its sign alone |
* ecmpm( ai, bi ) compare significands, return 1, 0, or -1 |
* edivm( ai, bi, ldp ) divide significands, bi = bi / ai |
* emdnorm(ai,l,s,exp,ldp) normalize and round off |
* emovi( a, ai ) convert external a to internal ai |
* emovo( ai, a, ldp ) convert internal ai to external a |
* emovz( ai, bi ) bi = ai, low guard word of bi = 0 |
* emulm( ai, bi, ldp ) multiply significands, bi = bi * ai |
* enormlz(ei) left-justify the significand |
* eshdn1( ai ) shift significand and guards down 1 bit |
* eshdn8( ai ) shift down 8 bits |
* eshdn6( ai ) shift down 16 bits |
* eshift( ai, n ) shift ai n bits up (or down if n < 0) |
* eshup1( ai ) shift significand and guards up 1 bit |
* eshup8( ai ) shift up 8 bits |
* eshup6( ai ) shift up 16 bits |
* esubm( ai, bi ) subtract significands, bi = bi - ai |
* |
* |
* The result is always normalized and rounded to NI-4 word precision |
* after each arithmetic operation. |
* |
* Exception flags are NOT fully supported. |
* |
* Define INFINITY in mconf.h for support of infinity; otherwise a |
* saturation arithmetic is implemented. |
* |
* Define NANS for support of Not-a-Number items; otherwise the |
* arithmetic will never produce a NaN output, and might be confused |
* by a NaN input. |
* If NaN's are supported, the output of ecmp(a,b) is -2 if |
* either a or b is a NaN. This means asking if(ecmp(a,b) < 0) |
* may not be legitimate. Use if(ecmp(a,b) == -1) for less-than |
* if in doubt. |
* Signaling NaN's are NOT supported; they are treated the same |
* as quiet NaN's. |
* |
* Denormals are always supported here where appropriate (e.g., not |
* for conversion to DEC numbers). |
*/ |
|
/* |
* Revision history: |
* |
* 5 Jan 84 PDP-11 assembly language version |
* 6 Dec 86 C language version |
* 30 Aug 88 100 digit version, improved rounding |
* 15 May 92 80-bit long double support |
* 22 Nov 00 Revised to fit into newlib by Jeff Johnston <jjohnstn@redhat.com> |
* |
* Author: S. L. Moshier. |
* |
* Copyright (c) 1984,2000 S.L. Moshier |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose without fee is hereby granted, provided that this entire notice |
* is included in all copies of any software which is or includes a copy |
* or modification of this software and in all copies of the supporting |
* documentation for such software. |
* |
* THIS SOFTWARE IS BEING 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 <stdio.h> |
/* #include "\usr\include\stdio.h" */ |
/*#include "ehead.h"*/ |
/*#include "mconf.h"*/ |
/* mconf.h |
* |
* Common include file for math routines |
* |
* |
* |
* SYNOPSIS: |
* |
* #include "mconf.h" |
* |
* |
* |
* DESCRIPTION: |
* |
* This file contains definitions for error codes that are |
* passed to the common error handling routine mtherr() |
* (which see). |
* |
* The file also includes a conditional assembly definition |
* for the type of computer arithmetic (IEEE, DEC, Motorola |
* IEEE, or UNKnown). |
* |
* For Digital Equipment PDP-11 and VAX computers, certain |
* IBM systems, and others that use numbers with a 56-bit |
* significand, the symbol DEC should be defined. In this |
* mode, most floating point constants are given as arrays |
* of octal integers to eliminate decimal to binary conversion |
* errors that might be introduced by the compiler. |
* |
* For computers, such as IBM PC, that follow the IEEE |
* Standard for Binary Floating Point Arithmetic (ANSI/IEEE |
* Std 754-1985), the symbol IBMPC should be defined. These |
* numbers have 53-bit significands. In this mode, constants |
* are provided as arrays of hexadecimal 16 bit integers. |
* |
* To accommodate other types of computer arithmetic, all |
* constants are also provided in a normal decimal radix |
* which one can hope are correctly converted to a suitable |
* format by the available C language compiler. To invoke |
* this mode, the symbol UNK is defined. |
* |
* An important difference among these modes is a predefined |
* set of machine arithmetic constants for each. The numbers |
* MACHEP (the machine roundoff error), MAXNUM (largest number |
* represented), and several other parameters are preset by |
* the configuration symbol. Check the file const.c to |
* ensure that these values are correct for your computer. |
* |
* For ANSI C compatibility, define ANSIC equal to 1. Currently |
* this affects only the atan2() function and others that use it. |
*/ |
|
/* Constant definitions for math error conditions |
*/ |
|
#define DOMAIN 1 /* argument domain error */ |
#define SING 2 /* argument singularity */ |
#define OVERFLOW 3 /* overflow range error */ |
#define UNDERFLOW 4 /* underflow range error */ |
#define TLOSS 5 /* total loss of precision */ |
#define PLOSS 6 /* partial loss of precision */ |
|
#define EDOM 33 |
#define ERANGE 34 |
|
typedef struct |
{ |
double r; |
double i; |
}cmplx; |
|
/* Type of computer arithmetic */ |
|
#ifndef DEC |
#ifdef __IEEE_LITTLE_ENDIAN |
#define IBMPC 1 |
#else /* !__IEEE_LITTLE_ENDIAN */ |
#define MIEEE 1 |
#endif /* !__IEEE_LITTLE_ENDIAN */ |
#endif /* !DEC */ |
|
/* Define 1 for ANSI C atan2() function |
* See atan.c and clog.c. |
*/ |
#define ANSIC 1 |
|
/*define VOLATILE volatile*/ |
#define VOLATILE |
|
#define NANS |
#define INFINITY |
|
/* NaN's require infinity support. */ |
#ifdef NANS |
#ifndef INFINITY |
#define INFINITY |
#endif |
#endif |
|
/* This handles 64-bit long ints. */ |
#define LONGBITS (8 * sizeof(long)) |
|
|
static void eaddm(short unsigned int *x, short unsigned int *y); |
static void esubm(short unsigned int *x, short unsigned int *y); |
static void emdnorm(short unsigned int *s, int lost, int subflg, long int exp, int rcntrl, LDPARMS *ldp); |
static int asctoeg(char *ss, short unsigned int *y, int oprec, LDPARMS *ldp); |
static void enan(short unsigned int *nan, int size); |
#if LDBL_MANT_DIG == 24 |
static void toe24(short unsigned int *x, short unsigned int *y); |
#elif LDBL_MANT_DIG == 53 |
static void toe53(short unsigned int *x, short unsigned int *y); |
#elif LDBL_MANT_DIG == 64 |
static void toe64(short unsigned int *a, short unsigned int *b); |
#else |
static void toe113(short unsigned int *a, short unsigned int *b); |
#endif |
static void eiremain(short unsigned int *den, short unsigned int *num, LDPARMS *ldp); |
static int ecmpm(register short unsigned int *a, register short unsigned int *b); |
static int edivm(short unsigned int *den, short unsigned int *num, LDPARMS *ldp); |
static int emulm(short unsigned int *a, short unsigned int *b, LDPARMS *ldp); |
static int eisneg(short unsigned int *x); |
static int eisinf(short unsigned int *x); |
static void emovi(short unsigned int *a, short unsigned int *b); |
static void emovo(short unsigned int *a, short unsigned int *b, LDPARMS *ldp); |
static void emovz(register short unsigned int *a, register short unsigned int *b); |
static void ecleaz(register short unsigned int *xi); |
static void eadd1(short unsigned int *a, short unsigned int *b, short unsigned int *c, int subflg, LDPARMS *ldp); |
static int eisnan(short unsigned int *x); |
static int eiisnan(short unsigned int *x); |
|
#ifdef DEC |
static void etodec(), todec(), dectoe(); |
#endif |
|
/* |
; Clear out entire external format number. |
; |
; unsigned short x[]; |
; eclear( x ); |
*/ |
|
static void eclear(register short unsigned int *x) |
{ |
register int i; |
|
for( i=0; i<NE; i++ ) |
*x++ = 0; |
} |
|
|
|
/* Move external format number from a to b. |
* |
* emov( a, b ); |
*/ |
|
static void emov(register short unsigned int *a, register short unsigned int *b) |
{ |
register int i; |
|
for( i=0; i<NE; i++ ) |
*b++ = *a++; |
} |
|
|
/* |
; Negate external format number |
; |
; unsigned short x[NE]; |
; eneg( x ); |
*/ |
|
static void eneg(short unsigned int *x) |
{ |
|
#ifdef NANS |
if( eisnan(x) ) |
return; |
#endif |
x[NE-1] ^= 0x8000; /* Toggle the sign bit */ |
} |
|
|
|
/* Return 1 if external format number is negative, |
* else return zero. |
*/ |
static int eisneg(short unsigned int *x) |
{ |
|
#ifdef NANS |
if( eisnan(x) ) |
return( 0 ); |
#endif |
if( x[NE-1] & 0x8000 ) |
return( 1 ); |
else |
return( 0 ); |
} |
|
|
/* Return 1 if external format number has maximum possible exponent, |
* else return zero. |
*/ |
static int eisinf(short unsigned int *x) |
{ |
|
if( (x[NE-1] & 0x7fff) == 0x7fff ) |
{ |
#ifdef NANS |
if( eisnan(x) ) |
return( 0 ); |
#endif |
return( 1 ); |
} |
else |
return( 0 ); |
} |
|
/* Check if e-type number is not a number. |
*/ |
static int eisnan(short unsigned int *x) |
{ |
|
#ifdef NANS |
int i; |
/* NaN has maximum exponent */ |
if( (x[NE-1] & 0x7fff) != 0x7fff ) |
return (0); |
/* ... and non-zero significand field. */ |
for( i=0; i<NE-1; i++ ) |
{ |
if( *x++ != 0 ) |
return (1); |
} |
#endif |
return (0); |
} |
|
/* |
; Fill entire number, including exponent and significand, with |
; largest possible number. These programs implement a saturation |
; value that is an ordinary, legal number. A special value |
; "infinity" may also be implemented; this would require tests |
; for that value and implementation of special rules for arithmetic |
; operations involving inifinity. |
*/ |
|
static void einfin(register short unsigned int *x, register LDPARMS *ldp) |
{ |
register int i; |
|
#ifdef INFINITY |
for( i=0; i<NE-1; i++ ) |
*x++ = 0; |
*x |= 32767; |
ldp = ldp; |
#else |
for( i=0; i<NE-1; i++ ) |
*x++ = 0xffff; |
*x |= 32766; |
if( ldp->rndprc < NBITS ) |
{ |
if (ldp->rndprc == 113) |
{ |
*(x - 9) = 0; |
*(x - 8) = 0; |
} |
if( ldp->rndprc == 64 ) |
{ |
*(x-5) = 0; |
} |
if( ldp->rndprc == 53 ) |
{ |
*(x-4) = 0xf800; |
} |
else |
{ |
*(x-4) = 0; |
*(x-3) = 0; |
*(x-2) = 0xff00; |
} |
} |
#endif |
} |
|
/* Move in external format number, |
* converting it to internal format. |
*/ |
static void emovi(short unsigned int *a, short unsigned int *b) |
{ |
register unsigned short *p, *q; |
int i; |
|
q = b; |
p = a + (NE-1); /* point to last word of external number */ |
/* get the sign bit */ |
if( *p & 0x8000 ) |
*q++ = 0xffff; |
else |
*q++ = 0; |
/* get the exponent */ |
*q = *p--; |
*q++ &= 0x7fff; /* delete the sign bit */ |
#ifdef INFINITY |
if( (*(q-1) & 0x7fff) == 0x7fff ) |
{ |
#ifdef NANS |
if( eisnan(a) ) |
{ |
*q++ = 0; |
for( i=3; i<NI; i++ ) |
*q++ = *p--; |
return; |
} |
#endif |
for( i=2; i<NI; i++ ) |
*q++ = 0; |
return; |
} |
#endif |
/* clear high guard word */ |
*q++ = 0; |
/* move in the significand */ |
for( i=0; i<NE-1; i++ ) |
*q++ = *p--; |
/* clear low guard word */ |
*q = 0; |
} |
|
|
/* Move internal format number out, |
* converting it to external format. |
*/ |
static void emovo(short unsigned int *a, short unsigned int *b, LDPARMS *ldp) |
{ |
register unsigned short *p, *q; |
unsigned short i; |
|
p = a; |
q = b + (NE-1); /* point to output exponent */ |
/* combine sign and exponent */ |
i = *p++; |
if( i ) |
*q-- = *p++ | 0x8000; |
else |
*q-- = *p++; |
#ifdef INFINITY |
if( *(p-1) == 0x7fff ) |
{ |
#ifdef NANS |
if( eiisnan(a) ) |
{ |
enan( b, NBITS ); |
return; |
} |
#endif |
einfin(b, ldp); |
return; |
} |
#endif |
/* skip over guard word */ |
++p; |
/* move the significand */ |
for( i=0; i<NE-1; i++ ) |
*q-- = *p++; |
} |
|
|
/* Clear out internal format number. |
*/ |
|
static void ecleaz(register short unsigned int *xi) |
{ |
register int i; |
|
for( i=0; i<NI; i++ ) |
*xi++ = 0; |
} |
|
/* same, but don't touch the sign. */ |
|
static void ecleazs(register short unsigned int *xi) |
{ |
register int i; |
|
++xi; |
for(i=0; i<NI-1; i++) |
*xi++ = 0; |
} |
|
|
|
|
/* Move internal format number from a to b. |
*/ |
static void emovz(register short unsigned int *a, register short unsigned int *b) |
{ |
register int i; |
|
for( i=0; i<NI-1; i++ ) |
*b++ = *a++; |
/* clear low guard word */ |
*b = 0; |
} |
|
/* Return nonzero if internal format number is a NaN. |
*/ |
|
static int eiisnan (short unsigned int *x) |
{ |
int i; |
|
if( (x[E] & 0x7fff) == 0x7fff ) |
{ |
for( i=M+1; i<NI; i++ ) |
{ |
if( x[i] != 0 ) |
return(1); |
} |
} |
return(0); |
} |
|
#if LDBL_MANT_DIG == 64 |
|
/* Return nonzero if internal format number is infinite. */ |
static int |
eiisinf (x) |
unsigned short x[]; |
{ |
|
#ifdef NANS |
if (eiisnan (x)) |
return (0); |
#endif |
if ((x[E] & 0x7fff) == 0x7fff) |
return (1); |
return (0); |
} |
#endif /* LDBL_MANT_DIG == 64 */ |
|
/* |
; Compare significands of numbers in internal format. |
; Guard words are included in the comparison. |
; |
; unsigned short a[NI], b[NI]; |
; cmpm( a, b ); |
; |
; for the significands: |
; returns +1 if a > b |
; 0 if a == b |
; -1 if a < b |
*/ |
static int ecmpm(register short unsigned int *a, register short unsigned int *b) |
{ |
int i; |
|
a += M; /* skip up to significand area */ |
b += M; |
for( i=M; i<NI; i++ ) |
{ |
if( *a++ != *b++ ) |
goto difrnt; |
} |
return(0); |
|
difrnt: |
if( *(--a) > *(--b) ) |
return(1); |
else |
return(-1); |
} |
|
|
/* |
; Shift significand down by 1 bit |
*/ |
|
static void eshdn1(register short unsigned int *x) |
{ |
register unsigned short bits; |
int i; |
|
x += M; /* point to significand area */ |
|
bits = 0; |
for( i=M; i<NI; i++ ) |
{ |
if( *x & 1 ) |
bits |= 1; |
*x >>= 1; |
if( bits & 2 ) |
*x |= 0x8000; |
bits <<= 1; |
++x; |
} |
} |
|
|
|
/* |
; Shift significand up by 1 bit |
*/ |
|
static void eshup1(register short unsigned int *x) |
{ |
register unsigned short bits; |
int i; |
|
x += NI-1; |
bits = 0; |
|
for( i=M; i<NI; i++ ) |
{ |
if( *x & 0x8000 ) |
bits |= 1; |
*x <<= 1; |
if( bits & 2 ) |
*x |= 1; |
bits <<= 1; |
--x; |
} |
} |
|
|
|
/* |
; Shift significand down by 8 bits |
*/ |
|
static void eshdn8(register short unsigned int *x) |
{ |
register unsigned short newbyt, oldbyt; |
int i; |
|
x += M; |
oldbyt = 0; |
for( i=M; i<NI; i++ ) |
{ |
newbyt = *x << 8; |
*x >>= 8; |
*x |= oldbyt; |
oldbyt = newbyt; |
++x; |
} |
} |
|
/* |
; Shift significand up by 8 bits |
*/ |
|
static void eshup8(register short unsigned int *x) |
{ |
int i; |
register unsigned short newbyt, oldbyt; |
|
x += NI-1; |
oldbyt = 0; |
|
for( i=M; i<NI; i++ ) |
{ |
newbyt = *x >> 8; |
*x <<= 8; |
*x |= oldbyt; |
oldbyt = newbyt; |
--x; |
} |
} |
|
/* |
; Shift significand up by 16 bits |
*/ |
|
static void eshup6(register short unsigned int *x) |
{ |
int i; |
register unsigned short *p; |
|
p = x + M; |
x += M + 1; |
|
for( i=M; i<NI-1; i++ ) |
*p++ = *x++; |
|
*p = 0; |
} |
|
/* |
; Shift significand down by 16 bits |
*/ |
|
static void eshdn6(register short unsigned int *x) |
{ |
int i; |
register unsigned short *p; |
|
x += NI-1; |
p = x + 1; |
|
for( i=M; i<NI-1; i++ ) |
*(--p) = *(--x); |
|
*(--p) = 0; |
} |
|
/* |
; Add significands |
; x + y replaces y |
*/ |
|
static void eaddm(short unsigned int *x, short unsigned int *y) |
{ |
register unsigned long a; |
int i; |
unsigned int carry; |
|
x += NI-1; |
y += NI-1; |
carry = 0; |
for( i=M; i<NI; i++ ) |
{ |
a = (unsigned long )(*x) + (unsigned long )(*y) + carry; |
if( a & 0x10000 ) |
carry = 1; |
else |
carry = 0; |
*y = (unsigned short )a; |
--x; |
--y; |
} |
} |
|
/* |
; Subtract significands |
; y - x replaces y |
*/ |
|
static void esubm(short unsigned int *x, short unsigned int *y) |
{ |
unsigned long a; |
int i; |
unsigned int carry; |
|
x += NI-1; |
y += NI-1; |
carry = 0; |
for( i=M; i<NI; i++ ) |
{ |
a = (unsigned long )(*y) - (unsigned long )(*x) - carry; |
if( a & 0x10000 ) |
carry = 1; |
else |
carry = 0; |
*y = (unsigned short )a; |
--x; |
--y; |
} |
} |
|
|
/* Divide significands */ |
|
|
/* Multiply significand of e-type number b |
by 16-bit quantity a, e-type result to c. */ |
|
static void m16m(short unsigned int a, short unsigned int *b, short unsigned int *c) |
{ |
register unsigned short *pp; |
register unsigned long carry; |
unsigned short *ps; |
unsigned short p[NI]; |
unsigned long aa, m; |
int i; |
|
aa = a; |
pp = &p[NI-2]; |
*pp++ = 0; |
*pp = 0; |
ps = &b[NI-1]; |
|
for( i=M+1; i<NI; i++ ) |
{ |
if( *ps == 0 ) |
{ |
--ps; |
--pp; |
*(pp-1) = 0; |
} |
else |
{ |
m = (unsigned long) aa * *ps--; |
carry = (m & 0xffff) + *pp; |
*pp-- = (unsigned short )carry; |
carry = (carry >> 16) + (m >> 16) + *pp; |
*pp = (unsigned short )carry; |
*(pp-1) = carry >> 16; |
} |
} |
for( i=M; i<NI; i++ ) |
c[i] = p[i]; |
} |
|
|
/* Divide significands. Neither the numerator nor the denominator |
is permitted to have its high guard word nonzero. */ |
|
|
static int edivm(short unsigned int *den, short unsigned int *num, LDPARMS *ldp) |
{ |
int i; |
register unsigned short *p; |
unsigned long tnum; |
unsigned short j, tdenm, tquot; |
unsigned short tprod[NI+1]; |
unsigned short *equot = ldp->equot; |
|
p = &equot[0]; |
*p++ = num[0]; |
*p++ = num[1]; |
|
for( i=M; i<NI; i++ ) |
{ |
*p++ = 0; |
} |
eshdn1( num ); |
tdenm = den[M+1]; |
for( i=M; i<NI; i++ ) |
{ |
/* Find trial quotient digit (the radix is 65536). */ |
tnum = (((unsigned long) num[M]) << 16) + num[M+1]; |
|
/* Do not execute the divide instruction if it will overflow. */ |
if( (tdenm * 0xffffUL) < tnum ) |
tquot = 0xffff; |
else |
tquot = tnum / tdenm; |
|
/* Prove that the divide worked. */ |
/* |
tcheck = (unsigned long )tquot * tdenm; |
if( tnum - tcheck > tdenm ) |
tquot = 0xffff; |
*/ |
/* Multiply denominator by trial quotient digit. */ |
m16m( tquot, den, tprod ); |
/* The quotient digit may have been overestimated. */ |
if( ecmpm( tprod, num ) > 0 ) |
{ |
tquot -= 1; |
esubm( den, tprod ); |
if( ecmpm( tprod, num ) > 0 ) |
{ |
tquot -= 1; |
esubm( den, tprod ); |
} |
} |
/* |
if( ecmpm( tprod, num ) > 0 ) |
{ |
eshow( "tprod", tprod ); |
eshow( "num ", num ); |
printf( "tnum = %08lx, tden = %04x, tquot = %04x\n", |
tnum, den[M+1], tquot ); |
} |
*/ |
esubm( tprod, num ); |
/* |
if( ecmpm( num, den ) >= 0 ) |
{ |
eshow( "num ", num ); |
eshow( "den ", den ); |
printf( "tnum = %08lx, tden = %04x, tquot = %04x\n", |
tnum, den[M+1], tquot ); |
} |
*/ |
equot[i] = tquot; |
eshup6(num); |
} |
/* test for nonzero remainder after roundoff bit */ |
p = &num[M]; |
j = 0; |
for( i=M; i<NI; i++ ) |
{ |
j |= *p++; |
} |
if( j ) |
j = 1; |
|
for( i=0; i<NI; i++ ) |
num[i] = equot[i]; |
|
return( (int )j ); |
} |
|
|
|
/* Multiply significands */ |
static int emulm(short unsigned int *a, short unsigned int *b, LDPARMS *ldp) |
{ |
unsigned short *p, *q; |
unsigned short pprod[NI]; |
unsigned short j; |
int i; |
unsigned short *equot = ldp->equot; |
|
equot[0] = b[0]; |
equot[1] = b[1]; |
for( i=M; i<NI; i++ ) |
equot[i] = 0; |
|
j = 0; |
p = &a[NI-1]; |
q = &equot[NI-1]; |
for( i=M+1; i<NI; i++ ) |
{ |
if( *p == 0 ) |
{ |
--p; |
} |
else |
{ |
m16m( *p--, b, pprod ); |
eaddm(pprod, equot); |
} |
j |= *q; |
eshdn6(equot); |
} |
|
for( i=0; i<NI; i++ ) |
b[i] = equot[i]; |
|
/* return flag for lost nonzero bits */ |
return( (int)j ); |
} |
|
|
/* |
static void eshow(str, x) |
char *str; |
unsigned short *x; |
{ |
int i; |
|
printf( "%s ", str ); |
for( i=0; i<NI; i++ ) |
printf( "%04x ", *x++ ); |
printf( "\n" ); |
} |
*/ |
|
|
/* |
* Normalize and round off. |
* |
* The internal format number to be rounded is "s". |
* Input "lost" indicates whether the number is exact. |
* This is the so-called sticky bit. |
* |
* Input "subflg" indicates whether the number was obtained |
* by a subtraction operation. In that case if lost is nonzero |
* then the number is slightly smaller than indicated. |
* |
* Input "exp" is the biased exponent, which may be negative. |
* the exponent field of "s" is ignored but is replaced by |
* "exp" as adjusted by normalization and rounding. |
* |
* Input "rcntrl" is the rounding control. |
*/ |
|
|
static void emdnorm(short unsigned int *s, int lost, int subflg, long int exp, int rcntrl, LDPARMS *ldp) |
{ |
int i, j; |
unsigned short r; |
|
/* Normalize */ |
j = enormlz( s ); |
|
/* a blank significand could mean either zero or infinity. */ |
#ifndef INFINITY |
if( j > NBITS ) |
{ |
ecleazs( s ); |
return; |
} |
#endif |
exp -= j; |
#ifndef INFINITY |
if( exp >= 32767L ) |
goto overf; |
#else |
if( (j > NBITS) && (exp < 32767L) ) |
{ |
ecleazs( s ); |
return; |
} |
#endif |
if( exp < 0L ) |
{ |
if( exp > (long )(-NBITS-1) ) |
{ |
j = (int )exp; |
i = eshift( s, j ); |
if( i ) |
lost = 1; |
} |
else |
{ |
ecleazs( s ); |
return; |
} |
} |
/* Round off, unless told not to by rcntrl. */ |
if( rcntrl == 0 ) |
goto mdfin; |
/* Set up rounding parameters if the control register changed. */ |
if( ldp->rndprc != ldp->rlast ) |
{ |
ecleaz( ldp->rbit ); |
switch( ldp->rndprc ) |
{ |
default: |
case NBITS: |
ldp->rw = NI-1; /* low guard word */ |
ldp->rmsk = 0xffff; |
ldp->rmbit = 0x8000; |
ldp->rebit = 1; |
ldp->re = ldp->rw - 1; |
break; |
case 113: |
ldp->rw = 10; |
ldp->rmsk = 0x7fff; |
ldp->rmbit = 0x4000; |
ldp->rebit = 0x8000; |
ldp->re = ldp->rw; |
break; |
case 64: |
ldp->rw = 7; |
ldp->rmsk = 0xffff; |
ldp->rmbit = 0x8000; |
ldp->rebit = 1; |
ldp->re = ldp->rw-1; |
break; |
/* For DEC arithmetic */ |
case 56: |
ldp->rw = 6; |
ldp->rmsk = 0xff; |
ldp->rmbit = 0x80; |
ldp->rebit = 0x100; |
ldp->re = ldp->rw; |
break; |
case 53: |
ldp->rw = 6; |
ldp->rmsk = 0x7ff; |
ldp->rmbit = 0x0400; |
ldp->rebit = 0x800; |
ldp->re = ldp->rw; |
break; |
case 24: |
ldp->rw = 4; |
ldp->rmsk = 0xff; |
ldp->rmbit = 0x80; |
ldp->rebit = 0x100; |
ldp->re = ldp->rw; |
break; |
} |
ldp->rbit[ldp->re] = ldp->rebit; |
ldp->rlast = ldp->rndprc; |
} |
|
/* Shift down 1 temporarily if the data structure has an implied |
* most significant bit and the number is denormal. |
* For rndprc = 64 or NBITS, there is no implied bit. |
* But Intel long double denormals lose one bit of significance even so. |
*/ |
#if IBMPC |
if( (exp <= 0) && (ldp->rndprc != NBITS) ) |
#else |
if( (exp <= 0) && (ldp->rndprc != 64) && (ldp->rndprc != NBITS) ) |
#endif |
{ |
lost |= s[NI-1] & 1; |
eshdn1(s); |
} |
/* Clear out all bits below the rounding bit, |
* remembering in r if any were nonzero. |
*/ |
r = s[ldp->rw] & ldp->rmsk; |
if( ldp->rndprc < NBITS ) |
{ |
i = ldp->rw + 1; |
while( i < NI ) |
{ |
if( s[i] ) |
r |= 1; |
s[i] = 0; |
++i; |
} |
} |
s[ldp->rw] &= ~ldp->rmsk; |
if( (r & ldp->rmbit) != 0 ) |
{ |
if( r == ldp->rmbit ) |
{ |
if( lost == 0 ) |
{ /* round to even */ |
if( (s[ldp->re] & ldp->rebit) == 0 ) |
goto mddone; |
} |
else |
{ |
if( subflg != 0 ) |
goto mddone; |
} |
} |
eaddm( ldp->rbit, s ); |
} |
mddone: |
#if IBMPC |
if( (exp <= 0) && (ldp->rndprc != NBITS) ) |
#else |
if( (exp <= 0) && (ldp->rndprc != 64) && (ldp->rndprc != NBITS) ) |
#endif |
{ |
eshup1(s); |
} |
if( s[2] != 0 ) |
{ /* overflow on roundoff */ |
eshdn1(s); |
exp += 1; |
} |
mdfin: |
s[NI-1] = 0; |
if( exp >= 32767L ) |
{ |
#ifndef INFINITY |
overf: |
#endif |
#ifdef INFINITY |
s[1] = 32767; |
for( i=2; i<NI-1; i++ ) |
s[i] = 0; |
#else |
s[1] = 32766; |
s[2] = 0; |
for( i=M+1; i<NI-1; i++ ) |
s[i] = 0xffff; |
s[NI-1] = 0; |
if( (ldp->rndprc < 64) || (ldp->rndprc == 113) ) |
{ |
s[ldp->rw] &= ~ldp->rmsk; |
if( ldp->rndprc == 24 ) |
{ |
s[5] = 0; |
s[6] = 0; |
} |
} |
#endif |
return; |
} |
if( exp < 0 ) |
s[1] = 0; |
else |
s[1] = (unsigned short )exp; |
} |
|
|
|
/* |
; Subtract external format numbers. |
; |
; unsigned short a[NE], b[NE], c[NE]; |
; LDPARMS *ldp; |
; esub( a, b, c, ldp ); c = b - a |
*/ |
|
static void esub(short unsigned int *a, short unsigned int *b, short unsigned int *c, LDPARMS *ldp) |
{ |
|
#ifdef NANS |
if( eisnan(a) ) |
{ |
emov (a, c); |
return; |
} |
if( eisnan(b) ) |
{ |
emov(b,c); |
return; |
} |
/* Infinity minus infinity is a NaN. |
* Test for subtracting infinities of the same sign. |
*/ |
if( eisinf(a) && eisinf(b) && ((eisneg (a) ^ eisneg (b)) == 0)) |
{ |
mtherr( "esub", DOMAIN ); |
enan( c, NBITS ); |
return; |
} |
#endif |
eadd1( a, b, c, 1, ldp ); |
} |
|
|
|
static void eadd1(short unsigned int *a, short unsigned int *b, short unsigned int *c, int subflg, LDPARMS *ldp) |
{ |
unsigned short ai[NI], bi[NI], ci[NI]; |
int i, lost, j, k; |
long lt, lta, ltb; |
|
#ifdef INFINITY |
if( eisinf(a) ) |
{ |
emov(a,c); |
if( subflg ) |
eneg(c); |
return; |
} |
if( eisinf(b) ) |
{ |
emov(b,c); |
return; |
} |
#endif |
emovi( a, ai ); |
emovi( b, bi ); |
if( subflg ) |
ai[0] = ~ai[0]; |
|
/* compare exponents */ |
lta = ai[E]; |
ltb = bi[E]; |
lt = lta - ltb; |
if( lt > 0L ) |
{ /* put the larger number in bi */ |
emovz( bi, ci ); |
emovz( ai, bi ); |
emovz( ci, ai ); |
ltb = bi[E]; |
lt = -lt; |
} |
lost = 0; |
if( lt != 0L ) |
{ |
if( lt < (long )(-NBITS-1) ) |
goto done; /* answer same as larger addend */ |
k = (int )lt; |
lost = eshift( ai, k ); /* shift the smaller number down */ |
} |
else |
{ |
/* exponents were the same, so must compare significands */ |
i = ecmpm( ai, bi ); |
if( i == 0 ) |
{ /* the numbers are identical in magnitude */ |
/* if different signs, result is zero */ |
if( ai[0] != bi[0] ) |
{ |
eclear(c); |
return; |
} |
/* if same sign, result is double */ |
/* double denomalized tiny number */ |
if( (bi[E] == 0) && ((bi[3] & 0x8000) == 0) ) |
{ |
eshup1( bi ); |
goto done; |
} |
/* add 1 to exponent unless both are zero! */ |
for( j=1; j<NI-1; j++ ) |
{ |
if( bi[j] != 0 ) |
{ |
/* This could overflow, but let emovo take care of that. */ |
ltb += 1; |
break; |
} |
} |
bi[E] = (unsigned short )ltb; |
goto done; |
} |
if( i > 0 ) |
{ /* put the larger number in bi */ |
emovz( bi, ci ); |
emovz( ai, bi ); |
emovz( ci, ai ); |
} |
} |
if( ai[0] == bi[0] ) |
{ |
eaddm( ai, bi ); |
subflg = 0; |
} |
else |
{ |
esubm( ai, bi ); |
subflg = 1; |
} |
emdnorm( bi, lost, subflg, ltb, 64, ldp ); |
|
done: |
emovo( bi, c, ldp ); |
} |
|
|
|
/* |
; Divide. |
; |
; unsigned short a[NE], b[NE], c[NE]; |
; LDPARMS *ldp; |
; ediv( a, b, c, ldp ); c = b / a |
*/ |
static void ediv(short unsigned int *a, short unsigned int *b, short unsigned int *c, LDPARMS *ldp) |
{ |
unsigned short ai[NI], bi[NI]; |
int i; |
long lt, lta, ltb; |
|
#ifdef NANS |
/* Return any NaN input. */ |
if( eisnan(a) ) |
{ |
emov(a,c); |
return; |
} |
if( eisnan(b) ) |
{ |
emov(b,c); |
return; |
} |
/* Zero over zero, or infinity over infinity, is a NaN. */ |
if( ((ecmp(a,ezero) == 0) && (ecmp(b,ezero) == 0)) |
|| (eisinf (a) && eisinf (b)) ) |
{ |
mtherr( "ediv", DOMAIN ); |
enan( c, NBITS ); |
return; |
} |
#endif |
/* Infinity over anything else is infinity. */ |
#ifdef INFINITY |
if( eisinf(b) ) |
{ |
if( eisneg(a) ^ eisneg(b) ) |
*(c+(NE-1)) = 0x8000; |
else |
*(c+(NE-1)) = 0; |
einfin(c, ldp); |
return; |
} |
if( eisinf(a) ) |
{ |
eclear(c); |
return; |
} |
#endif |
emovi( a, ai ); |
emovi( b, bi ); |
lta = ai[E]; |
ltb = bi[E]; |
if( bi[E] == 0 ) |
{ /* See if numerator is zero. */ |
for( i=1; i<NI-1; i++ ) |
{ |
if( bi[i] != 0 ) |
{ |
ltb -= enormlz( bi ); |
goto dnzro1; |
} |
} |
eclear(c); |
return; |
} |
dnzro1: |
|
if( ai[E] == 0 ) |
{ /* possible divide by zero */ |
for( i=1; i<NI-1; i++ ) |
{ |
if( ai[i] != 0 ) |
{ |
lta -= enormlz( ai ); |
goto dnzro2; |
} |
} |
if( ai[0] == bi[0] ) |
*(c+(NE-1)) = 0; |
else |
*(c+(NE-1)) = 0x8000; |
einfin(c, ldp); |
mtherr( "ediv", SING ); |
return; |
} |
dnzro2: |
|
i = edivm( ai, bi, ldp ); |
/* calculate exponent */ |
lt = ltb - lta + EXONE; |
emdnorm( bi, i, 0, lt, 64, ldp ); |
/* set the sign */ |
if( ai[0] == bi[0] ) |
bi[0] = 0; |
else |
bi[0] = 0Xffff; |
emovo( bi, c, ldp ); |
} |
|
|
|
/* |
; Multiply. |
; |
; unsigned short a[NE], b[NE], c[NE]; |
; LDPARMS *ldp |
; emul( a, b, c, ldp ); c = b * a |
*/ |
static void emul(short unsigned int *a, short unsigned int *b, short unsigned int *c, LDPARMS *ldp) |
{ |
unsigned short ai[NI], bi[NI]; |
int i, j; |
long lt, lta, ltb; |
|
#ifdef NANS |
/* NaN times anything is the same NaN. */ |
if( eisnan(a) ) |
{ |
emov(a,c); |
return; |
} |
if( eisnan(b) ) |
{ |
emov(b,c); |
return; |
} |
/* Zero times infinity is a NaN. */ |
if( (eisinf(a) && (ecmp(b,ezero) == 0)) |
|| (eisinf(b) && (ecmp(a,ezero) == 0)) ) |
{ |
mtherr( "emul", DOMAIN ); |
enan( c, NBITS ); |
return; |
} |
#endif |
/* Infinity times anything else is infinity. */ |
#ifdef INFINITY |
if( eisinf(a) || eisinf(b) ) |
{ |
if( eisneg(a) ^ eisneg(b) ) |
*(c+(NE-1)) = 0x8000; |
else |
*(c+(NE-1)) = 0; |
einfin(c, ldp); |
return; |
} |
#endif |
emovi( a, ai ); |
emovi( b, bi ); |
lta = ai[E]; |
ltb = bi[E]; |
if( ai[E] == 0 ) |
{ |
for( i=1; i<NI-1; i++ ) |
{ |
if( ai[i] != 0 ) |
{ |
lta -= enormlz( ai ); |
goto mnzer1; |
} |
} |
eclear(c); |
return; |
} |
mnzer1: |
|
if( bi[E] == 0 ) |
{ |
for( i=1; i<NI-1; i++ ) |
{ |
if( bi[i] != 0 ) |
{ |
ltb -= enormlz( bi ); |
goto mnzer2; |
} |
} |
eclear(c); |
return; |
} |
mnzer2: |
|
/* Multiply significands */ |
j = emulm( ai, bi, ldp ); |
/* calculate exponent */ |
lt = lta + ltb - (EXONE - 1); |
emdnorm( bi, j, 0, lt, 64, ldp ); |
/* calculate sign of product */ |
if( ai[0] == bi[0] ) |
bi[0] = 0; |
else |
bi[0] = 0xffff; |
emovo( bi, c, ldp ); |
} |
|
|
|
#if LDBL_MANT_DIG > 64 |
static void e113toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp) |
{ |
register unsigned short r; |
unsigned short *e, *p; |
unsigned short yy[NI]; |
int denorm, i; |
|
e = pe; |
denorm = 0; |
ecleaz(yy); |
#ifdef IBMPC |
e += 7; |
#endif |
r = *e; |
yy[0] = 0; |
if( r & 0x8000 ) |
yy[0] = 0xffff; |
r &= 0x7fff; |
#ifdef INFINITY |
if( r == 0x7fff ) |
{ |
#ifdef NANS |
#ifdef IBMPC |
for( i=0; i<7; i++ ) |
{ |
if( pe[i] != 0 ) |
{ |
enan( y, NBITS ); |
return; |
} |
} |
#else /* !IBMPC */ |
for( i=1; i<8; i++ ) |
{ |
if( pe[i] != 0 ) |
{ |
enan( y, NBITS ); |
return; |
} |
} |
#endif /* !IBMPC */ |
#endif /* NANS */ |
eclear( y ); |
einfin( y, ldp ); |
if( *e & 0x8000 ) |
eneg(y); |
return; |
} |
#endif /* INFINITY */ |
yy[E] = r; |
p = &yy[M + 1]; |
#ifdef IBMPC |
for( i=0; i<7; i++ ) |
*p++ = *(--e); |
#else /* IBMPC */ |
++e; |
for( i=0; i<7; i++ ) |
*p++ = *e++; |
#endif /* IBMPC */ |
/* If denormal, remove the implied bit; else shift down 1. */ |
if( r == 0 ) |
{ |
yy[M] = 0; |
} |
else |
{ |
yy[M] = 1; |
eshift( yy, -1 ); |
} |
emovo(yy,y,ldp); |
} |
|
/* move out internal format to ieee long double */ |
static void toe113(short unsigned int *a, short unsigned int *b) |
{ |
register unsigned short *p, *q; |
unsigned short i; |
|
#ifdef NANS |
if( eiisnan(a) ) |
{ |
enan( b, 113 ); |
return; |
} |
#endif |
p = a; |
#ifdef MIEEE |
q = b; |
#else |
q = b + 7; /* point to output exponent */ |
#endif |
|
/* If not denormal, delete the implied bit. */ |
if( a[E] != 0 ) |
{ |
eshup1 (a); |
} |
/* combine sign and exponent */ |
i = *p++; |
#ifdef MIEEE |
if( i ) |
*q++ = *p++ | 0x8000; |
else |
*q++ = *p++; |
#else |
if( i ) |
*q-- = *p++ | 0x8000; |
else |
*q-- = *p++; |
#endif |
/* skip over guard word */ |
++p; |
/* move the significand */ |
#ifdef MIEEE |
for (i = 0; i < 7; i++) |
*q++ = *p++; |
#else |
for (i = 0; i < 7; i++) |
*q-- = *p++; |
#endif |
} |
#endif /* LDBL_MANT_DIG > 64 */ |
|
|
#if LDBL_MANT_DIG == 64 |
static void e64toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp) |
{ |
unsigned short yy[NI]; |
unsigned short *p, *q, *e; |
int i; |
|
e = pe; |
p = yy; |
|
for( i=0; i<NE-5; i++ ) |
*p++ = 0; |
#ifdef IBMPC |
for( i=0; i<5; i++ ) |
*p++ = *e++; |
#endif |
#ifdef DEC |
for( i=0; i<5; i++ ) |
*p++ = *e++; |
#endif |
#ifdef MIEEE |
p = &yy[0] + (NE-1); |
*p-- = *e++; |
++e; /* MIEEE skips over 2nd short */ |
for( i=0; i<4; i++ ) |
*p-- = *e++; |
#endif |
|
#ifdef IBMPC |
/* For Intel long double, shift denormal significand up 1 |
-- but only if the top significand bit is zero. */ |
if((yy[NE-1] & 0x7fff) == 0 && (yy[NE-2] & 0x8000) == 0) |
{ |
unsigned short temp[NI+1]; |
emovi(yy, temp); |
eshup1(temp); |
emovo(temp,y,ldp); |
return; |
} |
#endif |
#ifdef INFINITY |
/* Point to the exponent field. */ |
p = &yy[NE-1]; |
if( *p == 0x7fff ) |
{ |
#ifdef NANS |
#ifdef IBMPC |
for( i=0; i<4; i++ ) |
{ |
if((i != 3 && pe[i] != 0) |
/* Check for Intel long double infinity pattern. */ |
|| (i == 3 && pe[i] != 0x8000)) |
{ |
enan( y, NBITS ); |
return; |
} |
} |
#endif |
#ifdef MIEEE |
for( i=2; i<=5; i++ ) |
{ |
if( pe[i] != 0 ) |
{ |
enan( y, NBITS ); |
return; |
} |
} |
#endif |
#endif /* NANS */ |
eclear( y ); |
einfin( y, ldp ); |
if( *p & 0x8000 ) |
eneg(y); |
return; |
} |
#endif /* INFINITY */ |
p = yy; |
q = y; |
for( i=0; i<NE; i++ ) |
*q++ = *p++; |
} |
|
/* move out internal format to ieee long double */ |
static void toe64(short unsigned int *a, short unsigned int *b) |
{ |
register unsigned short *p, *q; |
unsigned short i; |
|
#ifdef NANS |
if( eiisnan(a) ) |
{ |
enan( b, 64 ); |
return; |
} |
#endif |
#ifdef IBMPC |
/* Shift Intel denormal significand down 1. */ |
if( a[E] == 0 ) |
eshdn1(a); |
#endif |
p = a; |
#ifdef MIEEE |
q = b; |
#else |
q = b + 4; /* point to output exponent */ |
/* NOTE: Intel data type is 96 bits wide, clear the last word here. */ |
*(q+1)= 0; |
#endif |
|
/* combine sign and exponent */ |
i = *p++; |
#ifdef MIEEE |
if( i ) |
*q++ = *p++ | 0x8000; |
else |
*q++ = *p++; |
*q++ = 0; /* leave 2nd short blank */ |
#else |
if( i ) |
*q-- = *p++ | 0x8000; |
else |
*q-- = *p++; |
#endif |
/* skip over guard word */ |
++p; |
/* move the significand */ |
#ifdef MIEEE |
for( i=0; i<4; i++ ) |
*q++ = *p++; |
#else |
#ifdef INFINITY |
#ifdef IBMPC |
if (eiisinf (a)) |
{ |
/* Intel long double infinity. */ |
*q-- = 0x8000; |
*q-- = 0; |
*q-- = 0; |
*q = 0; |
return; |
} |
#endif /* IBMPC */ |
#endif /* INFINITY */ |
for( i=0; i<4; i++ ) |
*q-- = *p++; |
#endif |
} |
|
#endif /* LDBL_MANT_DIG == 64 */ |
|
#if LDBL_MANT_DIG == 53 |
/* |
; Convert IEEE double precision to e type |
; double d; |
; unsigned short x[N+2]; |
; e53toe( &d, x ); |
*/ |
static void e53toe(short unsigned int *pe, short unsigned int *y, LDPARMS *ldp) |
{ |
#ifdef DEC |
|
dectoe( pe, y ); /* see etodec.c */ |
|
#else |
|
register unsigned short r; |
register unsigned short *p, *e; |
unsigned short yy[NI]; |
int denorm, k; |
|
e = pe; |
denorm = 0; /* flag if denormalized number */ |
ecleaz(yy); |
#ifdef IBMPC |
e += 3; |
#endif |
#ifdef DEC |
e += 3; |
#endif |
r = *e; |
yy[0] = 0; |
if( r & 0x8000 ) |
yy[0] = 0xffff; |
yy[M] = (r & 0x0f) | 0x10; |
r &= ~0x800f; /* strip sign and 4 significand bits */ |
#ifdef INFINITY |
if( r == 0x7ff0 ) |
{ |
#ifdef NANS |
#ifdef IBMPC |
if( ((pe[3] & 0xf) != 0) || (pe[2] != 0) |
|| (pe[1] != 0) || (pe[0] != 0) ) |
{ |
enan( y, NBITS ); |
return; |
} |
#else /* !IBMPC */ |
if( ((pe[0] & 0xf) != 0) || (pe[1] != 0) |
|| (pe[2] != 0) || (pe[3] != 0) ) |
{ |
enan( y, NBITS ); |
return; |
} |
#endif /* !IBMPC */ |
#endif /* NANS */ |
eclear( y ); |
einfin( y, ldp ); |
if( yy[0] ) |
eneg(y); |
return; |
} |
#endif |
r >>= 4; |
/* If zero exponent, then the significand is denormalized. |
* So, take back the understood high significand bit. */ |
if( r == 0 ) |
{ |
denorm = 1; |
yy[M] &= ~0x10; |
} |
r += EXONE - 01777; |
yy[E] = r; |
p = &yy[M+1]; |
#ifdef IBMPC |
*p++ = *(--e); |
*p++ = *(--e); |
*p++ = *(--e); |
#else /* !IBMPC */ |
++e; |
*p++ = *e++; |
*p++ = *e++; |
*p++ = *e++; |
#endif /* !IBMPC */ |
(void )eshift( yy, -5 ); |
if( denorm ) |
{ /* if zero exponent, then normalize the significand */ |
if( (k = enormlz(yy)) > NBITS ) |
ecleazs(yy); |
else |
yy[E] -= (unsigned short )(k-1); |
} |
emovo( yy, y, ldp ); |
#endif /* !DEC */ |
} |
|
/* |
; e type to IEEE double precision |
; double d; |
; unsigned short x[NE]; |
; etoe53( x, &d ); |
*/ |
|
#ifdef DEC |
|
static void etoe53( x, e ) |
unsigned short *x, *e; |
{ |
etodec( x, e ); /* see etodec.c */ |
} |
|
static void toe53( x, y ) |
unsigned short *x, *y; |
{ |
todec( x, y ); |
} |
|
#else |
|
static void toe53(short unsigned int *x, short unsigned int *y) |
{ |
unsigned short i; |
unsigned short *p; |
|
|
#ifdef NANS |
if( eiisnan(x) ) |
{ |
enan( y, 53 ); |
return; |
} |
#endif |
p = &x[0]; |
#ifdef IBMPC |
y += 3; |
#endif |
#ifdef DEC |
y += 3; |
#endif |
*y = 0; /* output high order */ |
if( *p++ ) |
*y = 0x8000; /* output sign bit */ |
|
i = *p++; |
if( i >= (unsigned int )2047 ) |
{ /* Saturate at largest number less than infinity. */ |
#ifdef INFINITY |
*y |= 0x7ff0; |
#ifdef IBMPC |
*(--y) = 0; |
*(--y) = 0; |
*(--y) = 0; |
#else /* !IBMPC */ |
++y; |
*y++ = 0; |
*y++ = 0; |
*y++ = 0; |
#endif /* IBMPC */ |
#else /* !INFINITY */ |
*y |= (unsigned short )0x7fef; |
#ifdef IBMPC |
*(--y) = 0xffff; |
*(--y) = 0xffff; |
*(--y) = 0xffff; |
#else /* !IBMPC */ |
++y; |
*y++ = 0xffff; |
*y++ = 0xffff; |
*y++ = 0xffff; |
#endif |
#endif /* !INFINITY */ |
return; |
} |
if( i == 0 ) |
{ |
(void )eshift( x, 4 ); |
} |
else |
{ |
i <<= 4; |
(void )eshift( x, 5 ); |
} |
i |= *p++ & (unsigned short )0x0f; /* *p = xi[M] */ |
*y |= (unsigned short )i; /* high order output already has sign bit set */ |
#ifdef IBMPC |
*(--y) = *p++; |
*(--y) = *p++; |
*(--y) = *p; |
#else /* !IBMPC */ |
++y; |
*y++ = *p++; |
*y++ = *p++; |
*y++ = *p++; |
#endif /* !IBMPC */ |
} |
|
#endif /* not DEC */ |
#endif /* LDBL_MANT_DIG == 53 */ |
|
#if LDBL_MANT_DIG == 24 |
/* |
; Convert IEEE single precision to e type |
; float d; |
; unsigned short x[N+2]; |
; dtox( &d, x ); |
*/ |
void e24toe( short unsigned int *pe, short unsigned int *y, LDPARMS *ldp ) |
{ |
register unsigned short r; |
register unsigned short *p, *e; |
unsigned short yy[NI]; |
int denorm, k; |
|
e = pe; |
denorm = 0; /* flag if denormalized number */ |
ecleaz(yy); |
#ifdef IBMPC |
e += 1; |
#endif |
#ifdef DEC |
e += 1; |
#endif |
r = *e; |
yy[0] = 0; |
if( r & 0x8000 ) |
yy[0] = 0xffff; |
yy[M] = (r & 0x7f) | 0200; |
r &= ~0x807f; /* strip sign and 7 significand bits */ |
#ifdef INFINITY |
if( r == 0x7f80 ) |
{ |
#ifdef NANS |
#ifdef MIEEE |
if( ((pe[0] & 0x7f) != 0) || (pe[1] != 0) ) |
{ |
enan( y, NBITS ); |
return; |
} |
#else /* !MIEEE */ |
if( ((pe[1] & 0x7f) != 0) || (pe[0] != 0) ) |
{ |
enan( y, NBITS ); |
return; |
} |
#endif /* !MIEEE */ |
#endif /* NANS */ |
eclear( y ); |
einfin( y, ldp ); |
if( yy[0] ) |
eneg(y); |
return; |
} |
#endif |
r >>= 7; |
/* If zero exponent, then the significand is denormalized. |
* So, take back the understood high significand bit. */ |
if( r == 0 ) |
{ |
denorm = 1; |
yy[M] &= ~0200; |
} |
r += EXONE - 0177; |
yy[E] = r; |
p = &yy[M+1]; |
#ifdef IBMPC |
*p++ = *(--e); |
#endif |
#ifdef DEC |
*p++ = *(--e); |
#endif |
#ifdef MIEEE |
++e; |
*p++ = *e++; |
#endif |
(void )eshift( yy, -8 ); |
if( denorm ) |
{ /* if zero exponent, then normalize the significand */ |
if( (k = enormlz(yy)) > NBITS ) |
ecleazs(yy); |
else |
yy[E] -= (unsigned short )(k-1); |
} |
emovo( yy, y, ldp ); |
} |
|
static void toe24(short unsigned int *x, short unsigned int *y) |
{ |
unsigned short i; |
unsigned short *p; |
|
#ifdef NANS |
if( eiisnan(x) ) |
{ |
enan( y, 24 ); |
return; |
} |
#endif |
p = &x[0]; |
#ifdef IBMPC |
y += 1; |
#endif |
#ifdef DEC |
y += 1; |
#endif |
*y = 0; /* output high order */ |
if( *p++ ) |
*y = 0x8000; /* output sign bit */ |
|
i = *p++; |
if( i >= 255 ) |
{ /* Saturate at largest number less than infinity. */ |
#ifdef INFINITY |
*y |= (unsigned short )0x7f80; |
#ifdef IBMPC |
*(--y) = 0; |
#endif |
#ifdef DEC |
*(--y) = 0; |
#endif |
#ifdef MIEEE |
++y; |
*y = 0; |
#endif |
#else /* !INFINITY */ |
*y |= (unsigned short )0x7f7f; |
#ifdef IBMPC |
*(--y) = 0xffff; |
#endif |
#ifdef DEC |
*(--y) = 0xffff; |
#endif |
#ifdef MIEEE |
++y; |
*y = 0xffff; |
#endif |
#endif /* !INFINITY */ |
return; |
} |
if( i == 0 ) |
{ |
(void )eshift( x, 7 ); |
} |
else |
{ |
i <<= 7; |
(void )eshift( x, 8 ); |
} |
i |= *p++ & (unsigned short )0x7f; /* *p = xi[M] */ |
*y |= i; /* high order output already has sign bit set */ |
#ifdef IBMPC |
*(--y) = *p; |
#endif |
#ifdef DEC |
*(--y) = *p; |
#endif |
#ifdef MIEEE |
++y; |
*y = *p; |
#endif |
} |
#endif /* LDBL_MANT_DIG == 24 */ |
|
/* Compare two e type numbers. |
* |
* unsigned short a[NE], b[NE]; |
* ecmp( a, b ); |
* |
* returns +1 if a > b |
* 0 if a == b |
* -1 if a < b |
* -2 if either a or b is a NaN. |
*/ |
static int ecmp(short unsigned int *a, short unsigned int *b) |
{ |
unsigned short ai[NI], bi[NI]; |
register unsigned short *p, *q; |
register int i; |
int msign; |
|
#ifdef NANS |
if (eisnan (a) || eisnan (b)) |
return( -2 ); |
#endif |
emovi( a, ai ); |
p = ai; |
emovi( b, bi ); |
q = bi; |
|
if( *p != *q ) |
{ /* the signs are different */ |
/* -0 equals + 0 */ |
for( i=1; i<NI-1; i++ ) |
{ |
if( ai[i] != 0 ) |
goto nzro; |
if( bi[i] != 0 ) |
goto nzro; |
} |
return(0); |
nzro: |
if( *p == 0 ) |
return( 1 ); |
else |
return( -1 ); |
} |
/* both are the same sign */ |
if( *p == 0 ) |
msign = 1; |
else |
msign = -1; |
i = NI-1; |
do |
{ |
if( *p++ != *q++ ) |
{ |
goto diff; |
} |
} |
while( --i > 0 ); |
|
return(0); /* equality */ |
|
|
|
diff: |
|
if( *(--p) > *(--q) ) |
return( msign ); /* p is bigger */ |
else |
return( -msign ); /* p is littler */ |
} |
|
|
/* |
; Shift significand |
; |
; Shifts significand area up or down by the number of bits |
; given by the variable sc. |
*/ |
static int eshift(short unsigned int *x, int sc) |
{ |
unsigned short lost; |
unsigned short *p; |
|
if( sc == 0 ) |
return( 0 ); |
|
lost = 0; |
p = x + NI-1; |
|
if( sc < 0 ) |
{ |
sc = -sc; |
while( sc >= 16 ) |
{ |
lost |= *p; /* remember lost bits */ |
eshdn6(x); |
sc -= 16; |
} |
|
while( sc >= 8 ) |
{ |
lost |= *p & 0xff; |
eshdn8(x); |
sc -= 8; |
} |
|
while( sc > 0 ) |
{ |
lost |= *p & 1; |
eshdn1(x); |
sc -= 1; |
} |
} |
else |
{ |
while( sc >= 16 ) |
{ |
eshup6(x); |
sc -= 16; |
} |
|
while( sc >= 8 ) |
{ |
eshup8(x); |
sc -= 8; |
} |
|
while( sc > 0 ) |
{ |
eshup1(x); |
sc -= 1; |
} |
} |
if( lost ) |
lost = 1; |
return( (int )lost ); |
} |
|
|
|
/* |
; normalize |
; |
; Shift normalizes the significand area pointed to by argument |
; shift count (up = positive) is returned. |
*/ |
static int enormlz(short unsigned int *x) |
{ |
register unsigned short *p; |
int sc; |
|
sc = 0; |
p = &x[M]; |
if( *p != 0 ) |
goto normdn; |
++p; |
if( *p & 0x8000 ) |
return( 0 ); /* already normalized */ |
while( *p == 0 ) |
{ |
eshup6(x); |
sc += 16; |
/* With guard word, there are NBITS+16 bits available. |
* return true if all are zero. |
*/ |
if( sc > NBITS ) |
return( sc ); |
} |
/* see if high byte is zero */ |
while( (*p & 0xff00) == 0 ) |
{ |
eshup8(x); |
sc += 8; |
} |
/* now shift 1 bit at a time */ |
while( (*p & 0x8000) == 0) |
{ |
eshup1(x); |
sc += 1; |
if( sc > (NBITS+16) ) |
{ |
mtherr( "enormlz", UNDERFLOW ); |
return( sc ); |
} |
} |
return( sc ); |
|
/* Normalize by shifting down out of the high guard word |
of the significand */ |
normdn: |
|
if( *p & 0xff00 ) |
{ |
eshdn8(x); |
sc -= 8; |
} |
while( *p != 0 ) |
{ |
eshdn1(x); |
sc -= 1; |
|
if( sc < -NBITS ) |
{ |
mtherr( "enormlz", OVERFLOW ); |
return( sc ); |
} |
} |
return( sc ); |
} |
|
|
|
|
/* Convert e type number to decimal format ASCII string. |
* The constants are for 64 bit precision. |
*/ |
|
#define NTEN 12 |
#define MAXP 4096 |
|
#if NE == 10 |
static unsigned short etens[NTEN + 1][NE] = |
{ |
{0x6576, 0x4a92, 0x804a, 0x153f, |
0xc94c, 0x979a, 0x8a20, 0x5202, 0xc460, 0x7525,}, /* 10**4096 */ |
{0x6a32, 0xce52, 0x329a, 0x28ce, |
0xa74d, 0x5de4, 0xc53d, 0x3b5d, 0x9e8b, 0x5a92,}, /* 10**2048 */ |
{0x526c, 0x50ce, 0xf18b, 0x3d28, |
0x650d, 0x0c17, 0x8175, 0x7586, 0xc976, 0x4d48,}, |
{0x9c66, 0x58f8, 0xbc50, 0x5c54, |
0xcc65, 0x91c6, 0xa60e, 0xa0ae, 0xe319, 0x46a3,}, |
{0x851e, 0xeab7, 0x98fe, 0x901b, |
0xddbb, 0xde8d, 0x9df9, 0xebfb, 0xaa7e, 0x4351,}, |
{0x0235, 0x0137, 0x36b1, 0x336c, |
0xc66f, 0x8cdf, 0x80e9, 0x47c9, 0x93ba, 0x41a8,}, |
{0x50f8, 0x25fb, 0xc76b, 0x6b71, |
0x3cbf, 0xa6d5, 0xffcf, 0x1f49, 0xc278, 0x40d3,}, |
{0x0000, 0x0000, 0x0000, 0x0000, |
0xf020, 0xb59d, 0x2b70, 0xada8, 0x9dc5, 0x4069,}, |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0400, 0xc9bf, 0x8e1b, 0x4034,}, |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x2000, 0xbebc, 0x4019,}, |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x0000, 0x9c40, 0x400c,}, |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x0000, 0xc800, 0x4005,}, |
{0x0000, 0x0000, 0x0000, 0x0000, |
0x0000, 0x0000, 0x0000, 0x0000, 0xa000, 0x4002,}, /* 10**1 */ |
}; |
|
static unsigned short emtens[NTEN + 1][NE] = |
{ |
{0x2030, 0xcffc, 0xa1c3, 0x8123, |
0x2de3, 0x9fde, 0xd2ce, 0x04c8, 0xa6dd, 0x0ad8,}, /* 10**-4096 */ |
{0x8264, 0xd2cb, 0xf2ea, 0x12d4, |
0x4925, 0x2de4, 0x3436, 0x534f, 0xceae, 0x256b,}, /* 10**-2048 */ |
{0xf53f, 0xf698, 0x6bd3, 0x0158, |
0x87a6, 0xc0bd, 0xda57, 0x82a5, 0xa2a6, 0x32b5,}, |
{0xe731, 0x04d4, 0xe3f2, 0xd332, |
0x7132, 0xd21c, 0xdb23, 0xee32, 0x9049, 0x395a,}, |
{0xa23e, 0x5308, 0xfefb, 0x1155, |
0xfa91, 0x1939, 0x637a, 0x4325, 0xc031, 0x3cac,}, |
{0xe26d, 0xdbde, 0xd05d, 0xb3f6, |
0xac7c, 0xe4a0, 0x64bc, 0x467c, 0xddd0, 0x3e55,}, |
{0x2a20, 0x6224, 0x47b3, 0x98d7, |
0x3f23, 0xe9a5, 0xa539, 0xea27, 0xa87f, 0x3f2a,}, |
{0x0b5b, 0x4af2, 0xa581, 0x18ed, |
0x67de, 0x94ba, 0x4539, 0x1ead, 0xcfb1, 0x3f94,}, |
{0xbf71, 0xa9b3, 0x7989, 0xbe68, |
0x4c2e, 0xe15b, 0xc44d, 0x94be, 0xe695, 0x3fc9,}, |
{0x3d4d, 0x7c3d, 0x36ba, 0x0d2b, |
0xfdc2, 0xcefc, 0x8461, 0x7711, 0xabcc, 0x3fe4,}, |
{0xc155, 0xa4a8, 0x404e, 0x6113, |
0xd3c3, 0x652b, 0xe219, 0x1758, 0xd1b7, 0x3ff1,}, |
{0xd70a, 0x70a3, 0x0a3d, 0xa3d7, |
0x3d70, 0xd70a, 0x70a3, 0x0a3d, 0xa3d7, 0x3ff8,}, |
{0xcccd, 0xcccc, 0xcccc, 0xcccc, |
0xcccc, 0xcccc, 0xcccc, 0xcccc, 0xcccc, 0x3ffb,}, /* 10**-1 */ |
}; |
#else |
static unsigned short etens[NTEN+1][NE] = { |
{0xc94c,0x979a,0x8a20,0x5202,0xc460,0x7525,},/* 10**4096 */ |
{0xa74d,0x5de4,0xc53d,0x3b5d,0x9e8b,0x5a92,},/* 10**2048 */ |
{0x650d,0x0c17,0x8175,0x7586,0xc976,0x4d48,}, |
{0xcc65,0x91c6,0xa60e,0xa0ae,0xe319,0x46a3,}, |
{0xddbc,0xde8d,0x9df9,0xebfb,0xaa7e,0x4351,}, |
{0xc66f,0x8cdf,0x80e9,0x47c9,0x93ba,0x41a8,}, |
{0x3cbf,0xa6d5,0xffcf,0x1f49,0xc278,0x40d3,}, |
{0xf020,0xb59d,0x2b70,0xada8,0x9dc5,0x4069,}, |
{0x0000,0x0000,0x0400,0xc9bf,0x8e1b,0x4034,}, |
{0x0000,0x0000,0x0000,0x2000,0xbebc,0x4019,}, |
{0x0000,0x0000,0x0000,0x0000,0x9c40,0x400c,}, |
{0x0000,0x0000,0x0000,0x0000,0xc800,0x4005,}, |
{0x0000,0x0000,0x0000,0x0000,0xa000,0x4002,}, /* 10**1 */ |
}; |
|
static unsigned short emtens[NTEN+1][NE] = { |
{0x2de4,0x9fde,0xd2ce,0x04c8,0xa6dd,0x0ad8,}, /* 10**-4096 */ |
{0x4925,0x2de4,0x3436,0x534f,0xceae,0x256b,}, /* 10**-2048 */ |
{0x87a6,0xc0bd,0xda57,0x82a5,0xa2a6,0x32b5,}, |
{0x7133,0xd21c,0xdb23,0xee32,0x9049,0x395a,}, |
{0xfa91,0x1939,0x637a,0x4325,0xc031,0x3cac,}, |
{0xac7d,0xe4a0,0x64bc,0x467c,0xddd0,0x3e55,}, |
{0x3f24,0xe9a5,0xa539,0xea27,0xa87f,0x3f2a,}, |
{0x67de,0x94ba,0x4539,0x1ead,0xcfb1,0x3f94,}, |
{0x4c2f,0xe15b,0xc44d,0x94be,0xe695,0x3fc9,}, |
{0xfdc2,0xcefc,0x8461,0x7711,0xabcc,0x3fe4,}, |
{0xd3c3,0x652b,0xe219,0x1758,0xd1b7,0x3ff1,}, |
{0x3d71,0xd70a,0x70a3,0x0a3d,0xa3d7,0x3ff8,}, |
{0xcccd,0xcccc,0xcccc,0xcccc,0xcccc,0x3ffb,}, /* 10**-1 */ |
}; |
#endif |
|
|
|
/* ASCII string outputs for unix */ |
|
|
#if 0 |
void _IO_ldtostr(x, string, ndigs, flags, fmt) |
long double *x; |
char *string; |
int ndigs; |
int flags; |
char fmt; |
{ |
unsigned short w[NI]; |
char *t, *u; |
LDPARMS rnd; |
LDPARMS *ldp = &rnd; |
|
rnd.rlast = -1; |
rnd.rndprc = NBITS; |
|
if (sizeof(long double) == 16) |
e113toe( (unsigned short *)x, w, ldp ); |
else |
e64toe( (unsigned short *)x, w, ldp ); |
|
etoasc( w, string, ndigs, -1, ldp ); |
if( ndigs == 0 && flags == 0 ) |
{ |
/* Delete the decimal point unless alternate format. */ |
t = string; |
while( *t != '.' ) |
++t; |
u = t + 1; |
while( *t != '\0' ) |
*t++ = *u++; |
} |
if (*string == ' ') |
{ |
t = string; |
u = t + 1; |
while( *t != '\0' ) |
*t++ = *u++; |
} |
if (fmt == 'E') |
{ |
t = string; |
while( *t != 'e' ) |
++t; |
*t = 'E'; |
} |
} |
|
#endif |
|
/* This routine will not return more than NDEC+1 digits. */ |
|
char * |
_ldtoa_r (struct _reent *ptr, long double d, int mode, int ndigits, int *decpt, |
int *sign, char **rve) |
{ |
unsigned short e[NI]; |
char *s, *p; |
int k; |
LDPARMS rnd; |
LDPARMS *ldp = &rnd; |
char *outstr; |
|
rnd.rlast = -1; |
rnd.rndprc = NBITS; |
|
/* reentrancy addition to use mprec storage pool */ |
if (ptr->_result) |
{ |
ptr->_result->_k = ptr->_result_k; |
ptr->_result->_maxwds = 1 << ptr->_result_k; |
Bfree (ptr, ptr->_result); |
ptr->_result = 0; |
} |
|
#if LDBL_MANT_DIG == 24 |
e24toe( (unsigned short *)&d, e, ldp ); |
#elif LDBL_MANT_DIG == 53 |
e53toe( (unsigned short *)&d, e, ldp ); |
#elif LDBL_MANT_DIG == 64 |
e64toe( (unsigned short *)&d, e, ldp ); |
#else |
e113toe( (unsigned short *)&d, e, ldp ); |
#endif |
|
if( eisneg(e) ) |
*sign = 1; |
else |
*sign = 0; |
/* Mode 3 is "f" format. */ |
if( mode != 3 ) |
ndigits -= 1; |
/* Mode 0 is for %.999 format, which is supposed to give a |
minimum length string that will convert back to the same binary value. |
For now, just ask for 20 digits which is enough but sometimes too many. */ |
if( mode == 0 ) |
ndigits = 20; |
/* This sanity limit must agree with the corresponding one in etoasc, to |
keep straight the returned value of outexpon. */ |
if( ndigits > NDEC ) |
ndigits = NDEC; |
|
/* reentrancy addition to use mprec storage pool */ |
ptr->_result = Balloc (ptr, 3); |
ptr->_result_k = 3; |
outstr = (char *)ptr->_result; |
|
etoasc( e, outstr, ndigits, mode, ldp ); |
s = outstr; |
if( eisinf(e) || eisnan(e) ) |
{ |
*decpt = 9999; |
goto stripspaces; |
} |
*decpt = ldp->outexpon + 1; |
|
/* Transform the string returned by etoasc into what the caller wants. */ |
|
/* Look for decimal point and delete it from the string. */ |
s = outstr; |
while( *s != '\0' ) |
{ |
if( *s == '.' ) |
goto yesdecpt; |
++s; |
} |
goto nodecpt; |
|
yesdecpt: |
|
/* Delete the decimal point. */ |
while( *s != '\0' ) |
{ |
*s = *(s+1); |
++s; |
} |
|
nodecpt: |
|
/* Back up over the exponent field. */ |
while( *s != 'E' && s > outstr) |
--s; |
*s = '\0'; |
|
stripspaces: |
|
/* Strip leading spaces and sign. */ |
p = outstr; |
while( *p == ' ' || *p == '-') |
++p; |
|
/* Find new end of string. */ |
s = outstr; |
while( (*s++ = *p++) != '\0' ) |
; |
--s; |
|
/* Strip trailing zeros. */ |
if( mode == 2 ) |
k = 1; |
else if( ndigits > ldp->outexpon ) |
k = ndigits; |
else |
k = ldp->outexpon; |
|
while( *(s-1) == '0' && ((s - outstr) > k)) |
*(--s) = '\0'; |
|
/* In f format, flush small off-scale values to zero. |
Rounding has been taken care of by etoasc. */ |
if( mode == 3 && ((ndigits + ldp->outexpon) < 0)) |
{ |
s = outstr; |
*s = '\0'; |
*decpt = 0; |
} |
|
if( rve ) |
*rve = s; |
return outstr; |
} |
|
/* Routine used to tell if long double is NaN or Infinity or regular number. |
Returns: 0 = regular number |
1 = Nan |
2 = Infinity |
*/ |
int |
_ldcheck (long double *d) |
{ |
unsigned short e[NI]; |
char *s, *p; |
int k; |
LDPARMS rnd; |
LDPARMS *ldp = &rnd; |
char *outstr; |
|
rnd.rlast = -1; |
rnd.rndprc = NBITS; |
|
#if LDBL_MANT_DIG == 24 |
e24toe( (unsigned short *)d, e, ldp ); |
#elif LDBL_MANT_DIG == 53 |
e53toe( (unsigned short *)d, e, ldp ); |
#elif LDBL_MANT_DIG == 64 |
e64toe( (unsigned short *)d, e, ldp ); |
#else |
e113toe( (unsigned short *)d, e, ldp ); |
#endif |
|
if( (e[NE-1] & 0x7fff) == 0x7fff ) |
{ |
#ifdef NANS |
if( eisnan(e) ) |
return( 1 ); |
#endif |
return( 2 ); |
} |
else |
return( 0 ); |
} /* _ldcheck */ |
|
static void etoasc(short unsigned int *x, char *string, int ndigits, int outformat, LDPARMS *ldp) |
{ |
long digit; |
unsigned short y[NI], t[NI], u[NI], w[NI]; |
unsigned short *p, *r, *ten; |
unsigned short sign; |
int i, j, k, expon, rndsav, ndigs; |
char *s, *ss; |
unsigned short m; |
unsigned short *equot = ldp->equot; |
|
ndigs = ndigits; |
rndsav = ldp->rndprc; |
#ifdef NANS |
if( eisnan(x) ) |
{ |
sprintf( string, " NaN " ); |
expon = 9999; |
goto bxit; |
} |
#endif |
ldp->rndprc = NBITS; /* set to full precision */ |
emov( x, y ); /* retain external format */ |
if( y[NE-1] & 0x8000 ) |
{ |
sign = 0xffff; |
y[NE-1] &= 0x7fff; |
} |
else |
{ |
sign = 0; |
} |
expon = 0; |
ten = &etens[NTEN][0]; |
emov( eone, t ); |
/* Test for zero exponent */ |
if( y[NE-1] == 0 ) |
{ |
for( k=0; k<NE-1; k++ ) |
{ |
if( y[k] != 0 ) |
goto tnzro; /* denormalized number */ |
} |
goto isone; /* legal all zeros */ |
} |
tnzro: |
|
/* Test for infinity. |
*/ |
if( y[NE-1] == 0x7fff ) |
{ |
if( sign ) |
sprintf( string, " -Infinity " ); |
else |
sprintf( string, " Infinity " ); |
expon = 9999; |
goto bxit; |
} |
|
/* Test for exponent nonzero but significand denormalized. |
* This is an error condition. |
*/ |
if( (y[NE-1] != 0) && ((y[NE-2] & 0x8000) == 0) ) |
{ |
mtherr( "etoasc", DOMAIN ); |
sprintf( string, "NaN" ); |
expon = 9999; |
goto bxit; |
} |
|
/* Compare to 1.0 */ |
i = ecmp( eone, y ); |
if( i == 0 ) |
goto isone; |
|
if( i < 0 ) |
{ /* Number is greater than 1 */ |
/* Convert significand to an integer and strip trailing decimal zeros. */ |
emov( y, u ); |
u[NE-1] = EXONE + NBITS - 1; |
|
p = &etens[NTEN-4][0]; |
m = 16; |
do |
{ |
ediv( p, u, t, ldp ); |
efloor( t, w, ldp ); |
for( j=0; j<NE-1; j++ ) |
{ |
if( t[j] != w[j] ) |
goto noint; |
} |
emov( t, u ); |
expon += (int )m; |
noint: |
p += NE; |
m >>= 1; |
} |
while( m != 0 ); |
|
/* Rescale from integer significand */ |
u[NE-1] += y[NE-1] - (unsigned int )(EXONE + NBITS - 1); |
emov( u, y ); |
/* Find power of 10 */ |
emov( eone, t ); |
m = MAXP; |
p = &etens[0][0]; |
while( ecmp( ten, u ) <= 0 ) |
{ |
if( ecmp( p, u ) <= 0 ) |
{ |
ediv( p, u, u, ldp ); |
emul( p, t, t, ldp ); |
expon += (int )m; |
} |
m >>= 1; |
if( m == 0 ) |
break; |
p += NE; |
} |
} |
else |
{ /* Number is less than 1.0 */ |
/* Pad significand with trailing decimal zeros. */ |
if( y[NE-1] == 0 ) |
{ |
while( (y[NE-2] & 0x8000) == 0 ) |
{ |
emul( ten, y, y, ldp ); |
expon -= 1; |
} |
} |
else |
{ |
emovi( y, w ); |
for( i=0; i<NDEC+1; i++ ) |
{ |
if( (w[NI-1] & 0x7) != 0 ) |
break; |
/* multiply by 10 */ |
emovz( w, u ); |
eshdn1( u ); |
eshdn1( u ); |
eaddm( w, u ); |
u[1] += 3; |
while( u[2] != 0 ) |
{ |
eshdn1(u); |
u[1] += 1; |
} |
if( u[NI-1] != 0 ) |
break; |
if( eone[NE-1] <= u[1] ) |
break; |
emovz( u, w ); |
expon -= 1; |
} |
emovo( w, y, ldp ); |
} |
k = -MAXP; |
p = &emtens[0][0]; |
r = &etens[0][0]; |
emov( y, w ); |
emov( eone, t ); |
while( ecmp( eone, w ) > 0 ) |
{ |
if( ecmp( p, w ) >= 0 ) |
{ |
emul( r, w, w, ldp ); |
emul( r, t, t, ldp ); |
expon += k; |
} |
k /= 2; |
if( k == 0 ) |
break; |
p += NE; |
r += NE; |
} |
ediv( t, eone, t, ldp ); |
} |
isone: |
/* Find the first (leading) digit. */ |
emovi( t, w ); |
emovz( w, t ); |
emovi( y, w ); |
emovz( w, y ); |
eiremain( t, y, ldp ); |
digit = equot[NI-1]; |
while( (digit == 0) && (ecmp(y,ezero) != 0) ) |
{ |
eshup1( y ); |
emovz( y, u ); |
eshup1( u ); |
eshup1( u ); |
eaddm( u, y ); |
eiremain( t, y, ldp ); |
digit = equot[NI-1]; |
expon -= 1; |
} |
s = string; |
if( sign ) |
*s++ = '-'; |
else |
*s++ = ' '; |
/* Examine number of digits requested by caller. */ |
if( outformat == 3 ) |
ndigs += expon; |
/* |
else if( ndigs < 0 ) |
ndigs = 0; |
*/ |
if( ndigs > NDEC ) |
ndigs = NDEC; |
if( digit == 10 ) |
{ |
*s++ = '1'; |
*s++ = '.'; |
if( ndigs > 0 ) |
{ |
*s++ = '0'; |
ndigs -= 1; |
} |
expon += 1; |
if( ndigs < 0 ) |
{ |
ss = s; |
goto doexp; |
} |
} |
else |
{ |
*s++ = (char )digit + '0'; |
*s++ = '.'; |
} |
/* Generate digits after the decimal point. */ |
for( k=0; k<=ndigs; k++ ) |
{ |
/* multiply current number by 10, without normalizing */ |
eshup1( y ); |
emovz( y, u ); |
eshup1( u ); |
eshup1( u ); |
eaddm( u, y ); |
eiremain( t, y, ldp ); |
*s++ = (char )equot[NI-1] + '0'; |
} |
digit = equot[NI-1]; |
--s; |
ss = s; |
/* round off the ASCII string */ |
if( digit > 4 ) |
{ |
/* Test for critical rounding case in ASCII output. */ |
if( digit == 5 ) |
{ |
emovo( y, t, ldp ); |
if( ecmp(t,ezero) != 0 ) |
goto roun; /* round to nearest */ |
if( (*(s-1) & 1) == 0 ) |
goto doexp; /* round to even */ |
} |
/* Round up and propagate carry-outs */ |
roun: |
--s; |
k = *s & 0x7f; |
/* Carry out to most significant digit? */ |
if( ndigs < 0 ) |
{ |
/* This will print like "1E-6". */ |
*s = '1'; |
expon += 1; |
goto doexp; |
} |
else if( k == '.' ) |
{ |
--s; |
k = *s; |
k += 1; |
*s = (char )k; |
/* Most significant digit carries to 10? */ |
if( k > '9' ) |
{ |
expon += 1; |
*s = '1'; |
} |
goto doexp; |
} |
/* Round up and carry out from less significant digits */ |
k += 1; |
*s = (char )k; |
if( k > '9' ) |
{ |
*s = '0'; |
goto roun; |
} |
} |
doexp: |
#ifdef __GO32__ |
if( expon >= 0 ) |
sprintf( ss, "e+%02d", expon ); |
else |
sprintf( ss, "e-%02d", -expon ); |
#else |
sprintf( ss, "E%d", expon ); |
#endif |
bxit: |
ldp->rndprc = rndsav; |
ldp->outexpon = expon; |
} |
|
|
|
|
/* |
; ASCTOQ |
; ASCTOQ.MAC LATEST REV: 11 JAN 84 |
; SLM, 3 JAN 78 |
; |
; Convert ASCII string to quadruple precision floating point |
; |
; Numeric input is free field decimal number |
; with max of 15 digits with or without |
; decimal point entered as ASCII from teletype. |
; Entering E after the number followed by a second |
; number causes the second number to be interpreted |
; as a power of 10 to be multiplied by the first number |
; (i.e., "scientific" notation). |
; |
; Usage: |
; asctoq( string, q ); |
*/ |
|
long double _strtold (char *s, char **se) |
{ |
long double x; |
LDPARMS rnd; |
LDPARMS *ldp = &rnd; |
int lenldstr; |
|
rnd.rlast = -1; |
rnd.rndprc = NBITS; |
|
lenldstr = asctoeg( s, (unsigned short *)&x, LDBL_MANT_DIG, ldp ); |
if (se) |
*se = s + lenldstr; |
return x; |
} |
|
#define REASONABLE_LEN 200 |
|
static int |
asctoeg(char *ss, short unsigned int *y, int oprec, LDPARMS *ldp) |
{ |
unsigned short yy[NI], xt[NI], tt[NI]; |
int esign, decflg, sgnflg, nexp, exp, prec, lost; |
int k, trail, c, rndsav; |
long lexp; |
unsigned short nsign, *p; |
char *sp, *s, *lstr; |
int lenldstr; |
int mflag = 0; |
char tmpstr[REASONABLE_LEN]; |
|
/* Copy the input string. */ |
c = strlen (ss) + 2; |
if (c <= REASONABLE_LEN) |
lstr = tmpstr; |
else |
{ |
lstr = (char *) calloc (c, 1); |
mflag = 1; |
} |
s = ss; |
lenldstr = 0; |
while( *s == ' ' ) /* skip leading spaces */ |
{ |
++s; |
++lenldstr; |
} |
sp = lstr; |
for( k=0; k<c; k++ ) |
{ |
if( (*sp++ = *s++) == '\0' ) |
break; |
} |
*sp = '\0'; |
s = lstr; |
|
rndsav = ldp->rndprc; |
ldp->rndprc = NBITS; /* Set to full precision */ |
lost = 0; |
nsign = 0; |
decflg = 0; |
sgnflg = 0; |
nexp = 0; |
exp = 0; |
prec = 0; |
ecleaz( yy ); |
trail = 0; |
|
nxtcom: |
k = *s - '0'; |
if( (k >= 0) && (k <= 9) ) |
{ |
/* Ignore leading zeros */ |
if( (prec == 0) && (decflg == 0) && (k == 0) ) |
goto donchr; |
/* Identify and strip trailing zeros after the decimal point. */ |
if( (trail == 0) && (decflg != 0) ) |
{ |
sp = s; |
while( (*sp >= '0') && (*sp <= '9') ) |
++sp; |
/* Check for syntax error */ |
c = *sp & 0x7f; |
if( (c != 'e') && (c != 'E') && (c != '\0') |
&& (c != '\n') && (c != '\r') && (c != ' ') |
&& (c != ',') ) |
goto error; |
--sp; |
while( *sp == '0' ) |
*sp-- = 'z'; |
trail = 1; |
if( *s == 'z' ) |
goto donchr; |
} |
/* If enough digits were given to more than fill up the yy register, |
* continuing until overflow into the high guard word yy[2] |
* guarantees that there will be a roundoff bit at the top |
* of the low guard word after normalization. |
*/ |
if( yy[2] == 0 ) |
{ |
if( decflg ) |
nexp += 1; /* count digits after decimal point */ |
eshup1( yy ); /* multiply current number by 10 */ |
emovz( yy, xt ); |
eshup1( xt ); |
eshup1( xt ); |
eaddm( xt, yy ); |
ecleaz( xt ); |
xt[NI-2] = (unsigned short )k; |
eaddm( xt, yy ); |
} |
else |
{ |
/* Mark any lost non-zero digit. */ |
lost |= k; |
/* Count lost digits before the decimal point. */ |
if (decflg == 0) |
nexp -= 1; |
} |
prec += 1; |
goto donchr; |
} |
|
switch( *s ) |
{ |
case 'z': |
break; |
case 'E': |
case 'e': |
goto expnt; |
case '.': /* decimal point */ |
if( decflg ) |
goto error; |
++decflg; |
break; |
case '-': |
nsign = 0xffff; |
if( sgnflg ) |
goto error; |
++sgnflg; |
break; |
case '+': |
if( sgnflg ) |
goto error; |
++sgnflg; |
break; |
case ',': |
case ' ': |
case '\0': |
case '\n': |
case '\r': |
goto daldone; |
case 'i': |
case 'I': |
goto infinite; |
default: |
error: |
#ifdef NANS |
enan( yy, NI*16 ); |
#else |
mtherr( "asctoe", DOMAIN ); |
ecleaz(yy); |
#endif |
goto aexit; |
} |
donchr: |
++s; |
goto nxtcom; |
|
/* Exponent interpretation */ |
expnt: |
|
esign = 1; |
exp = 0; |
++s; |
/* check for + or - */ |
if( *s == '-' ) |
{ |
esign = -1; |
++s; |
} |
if( *s == '+' ) |
++s; |
while( (*s >= '0') && (*s <= '9') ) |
{ |
exp *= 10; |
exp += *s++ - '0'; |
if (exp > 4977) |
{ |
if (esign < 0) |
goto zero; |
else |
goto infinite; |
} |
} |
if( esign < 0 ) |
exp = -exp; |
if( exp > 4932 ) |
{ |
infinite: |
ecleaz(yy); |
yy[E] = 0x7fff; /* infinity */ |
goto aexit; |
} |
if( exp < -4977 ) |
{ |
zero: |
ecleaz(yy); |
goto aexit; |
} |
|
daldone: |
nexp = exp - nexp; |
/* Pad trailing zeros to minimize power of 10, per IEEE spec. */ |
while( (nexp > 0) && (yy[2] == 0) ) |
{ |
emovz( yy, xt ); |
eshup1( xt ); |
eshup1( xt ); |
eaddm( yy, xt ); |
eshup1( xt ); |
if( xt[2] != 0 ) |
break; |
nexp -= 1; |
emovz( xt, yy ); |
} |
if( (k = enormlz(yy)) > NBITS ) |
{ |
ecleaz(yy); |
goto aexit; |
} |
lexp = (EXONE - 1 + NBITS) - k; |
emdnorm( yy, lost, 0, lexp, 64, ldp ); |
/* convert to external format */ |
|
|
/* Multiply by 10**nexp. If precision is 64 bits, |
* the maximum relative error incurred in forming 10**n |
* for 0 <= n <= 324 is 8.2e-20, at 10**180. |
* For 0 <= n <= 999, the peak relative error is 1.4e-19 at 10**947. |
* For 0 >= n >= -999, it is -1.55e-19 at 10**-435. |
*/ |
lexp = yy[E]; |
if( nexp == 0 ) |
{ |
k = 0; |
goto expdon; |
} |
esign = 1; |
if( nexp < 0 ) |
{ |
nexp = -nexp; |
esign = -1; |
if( nexp > 4096 ) |
{ /* Punt. Can't handle this without 2 divides. */ |
emovi( etens[0], tt ); |
lexp -= tt[E]; |
k = edivm( tt, yy, ldp ); |
lexp += EXONE; |
nexp -= 4096; |
} |
} |
p = &etens[NTEN][0]; |
emov( eone, xt ); |
exp = 1; |
do |
{ |
if( exp & nexp ) |
emul( p, xt, xt, ldp ); |
p -= NE; |
exp = exp + exp; |
} |
while( exp <= MAXP ); |
|
emovi( xt, tt ); |
if( esign < 0 ) |
{ |
lexp -= tt[E]; |
k = edivm( tt, yy, ldp ); |
lexp += EXONE; |
} |
else |
{ |
lexp += tt[E]; |
k = emulm( tt, yy, ldp ); |
lexp -= EXONE - 1; |
} |
|
expdon: |
|
/* Round and convert directly to the destination type */ |
if( oprec == 53 ) |
lexp -= EXONE - 0x3ff; |
else if( oprec == 24 ) |
lexp -= EXONE - 0177; |
#ifdef DEC |
else if( oprec == 56 ) |
lexp -= EXONE - 0201; |
#endif |
ldp->rndprc = oprec; |
emdnorm( yy, k, 0, lexp, 64, ldp ); |
|
aexit: |
|
ldp->rndprc = rndsav; |
yy[0] = nsign; |
switch( oprec ) |
{ |
#ifdef DEC |
case 56: |
todec( yy, y ); /* see etodec.c */ |
break; |
#endif |
#if LDBL_MANT_DIG == 53 |
case 53: |
toe53( yy, y ); |
break; |
#elif LDBL_MANT_DIG == 24 |
case 24: |
toe24( yy, y ); |
break; |
#elif LDBL_MANT_DIG == 64 |
case 64: |
toe64( yy, y ); |
break; |
#elif LDBL_MANT_DIG == 113 |
case 113: |
toe113( yy, y ); |
break; |
#else |
case NBITS: |
emovo( yy, y, ldp ); |
break; |
#endif |
} |
lenldstr += s - lstr; |
if (mflag) |
free (lstr); |
return lenldstr; |
} |
|
|
|
/* y = largest integer not greater than x |
* (truncated toward minus infinity) |
* |
* unsigned short x[NE], y[NE] |
* LDPARMS *ldp |
* |
* efloor( x, y, ldp ); |
*/ |
static unsigned short bmask[] = { |
0xffff, |
0xfffe, |
0xfffc, |
0xfff8, |
0xfff0, |
0xffe0, |
0xffc0, |
0xff80, |
0xff00, |
0xfe00, |
0xfc00, |
0xf800, |
0xf000, |
0xe000, |
0xc000, |
0x8000, |
0x0000, |
}; |
|
static void efloor(short unsigned int *x, short unsigned int *y, LDPARMS *ldp) |
{ |
register unsigned short *p; |
int e, expon, i; |
unsigned short f[NE]; |
|
emov( x, f ); /* leave in external format */ |
expon = (int )f[NE-1]; |
e = (expon & 0x7fff) - (EXONE - 1); |
if( e <= 0 ) |
{ |
eclear(y); |
goto isitneg; |
} |
/* number of bits to clear out */ |
e = NBITS - e; |
emov( f, y ); |
if( e <= 0 ) |
return; |
|
p = &y[0]; |
while( e >= 16 ) |
{ |
*p++ = 0; |
e -= 16; |
} |
/* clear the remaining bits */ |
*p &= bmask[e]; |
/* truncate negatives toward minus infinity */ |
isitneg: |
|
if( (unsigned short )expon & (unsigned short )0x8000 ) |
{ |
for( i=0; i<NE-1; i++ ) |
{ |
if( f[i] != y[i] ) |
{ |
esub( eone, y, y, ldp ); |
break; |
} |
} |
} |
} |
|
|
|
static void eiremain(short unsigned int *den, short unsigned int *num, LDPARMS *ldp) |
{ |
long ld, ln; |
unsigned short j; |
unsigned short *equot = ldp->equot; |
|
ld = den[E]; |
ld -= enormlz( den ); |
ln = num[E]; |
ln -= enormlz( num ); |
ecleaz( equot ); |
while( ln >= ld ) |
{ |
if( ecmpm(den,num) <= 0 ) |
{ |
esubm(den, num); |
j = 1; |
} |
else |
{ |
j = 0; |
} |
eshup1(equot); |
equot[NI-1] |= j; |
eshup1(num); |
ln -= 1; |
} |
emdnorm( num, 0, 0, ln, 0, ldp ); |
} |
|
/* NaN bit patterns |
*/ |
#ifdef MIEEE |
static unsigned short nan113[8] = { |
0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; |
static unsigned short nan64[6] = {0x7fff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff}; |
static unsigned short nan53[4] = {0x7fff, 0xffff, 0xffff, 0xffff}; |
static unsigned short nan24[2] = {0x7fff, 0xffff}; |
#else /* !MIEEE */ |
static unsigned short nan113[8] = {0, 0, 0, 0, 0, 0, 0x8000, 0x7fff}; |
static unsigned short nan64[6] = {0, 0, 0, 0, 0xc000, 0x7fff}; |
static unsigned short nan53[4] = {0, 0, 0, 0x7ff8}; |
static unsigned short nan24[2] = {0, 0x7fc0}; |
#endif /* !MIEEE */ |
|
|
static void enan (short unsigned int *nan, int size) |
{ |
int i, n; |
unsigned short *p; |
|
switch( size ) |
{ |
#ifndef DEC |
case 113: |
n = 8; |
p = nan113; |
break; |
|
case 64: |
n = 6; |
p = nan64; |
break; |
|
case 53: |
n = 4; |
p = nan53; |
break; |
|
case 24: |
n = 2; |
p = nan24; |
break; |
|
case NBITS: |
for( i=0; i<NE-2; i++ ) |
*nan++ = 0; |
*nan++ = 0xc000; |
*nan++ = 0x7fff; |
return; |
|
case NI*16: |
*nan++ = 0; |
*nan++ = 0x7fff; |
*nan++ = 0; |
*nan++ = 0xc000; |
for( i=4; i<NI; i++ ) |
*nan++ = 0; |
return; |
#endif |
default: |
mtherr( "enan", DOMAIN ); |
return; |
} |
for (i=0; i < n; i++) |
*nan++ = *p++; |
} |
|
|
|
|
/atexit.h
0,0 → 1,13
/* |
* %G% (UofMD) %D% |
*/ |
|
#define ATEXIT_SIZE 32 /* must be at least 32 to guarantee ANSI conformance */ |
|
struct atexit { |
struct atexit *next; /* next in list */ |
int ind; /* next index in this table */ |
void (*fns[ATEXIT_SIZE])(); /* the table itself */ |
}; |
|
struct atexit *__atexit; /* points to head of LIFO stack */ |
/mprec.c
0,0 → 1,984
/**************************************************************** |
* |
* The author of this software is David M. Gay. |
* |
* Copyright (c) 1991 by AT&T. |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose without fee is hereby granted, provided that this entire notice |
* is included in all copies of any software which is or includes a copy |
* or modification of this software and in all copies of the supporting |
* documentation for such software. |
* |
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED |
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY |
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY |
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. |
* |
***************************************************************/ |
|
/* Please send bug reports to |
David M. Gay |
AT&T Bell Laboratories, Room 2C-463 |
600 Mountain Avenue |
Murray Hill, NJ 07974-2070 |
U.S.A. |
dmg@research.att.com or research!dmg |
*/ |
|
/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. |
* |
* This strtod returns a nearest machine number to the input decimal |
* string (or sets errno to ERANGE). With IEEE arithmetic, ties are |
* broken by the IEEE round-even rule. Otherwise ties are broken by |
* biased rounding (add half and chop). |
* |
* Inspired loosely by William D. Clinger's paper "How to Read Floating |
* Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. |
* |
* Modifications: |
* |
* 1. We only require IEEE, IBM, or VAX double-precision |
* arithmetic (not IEEE double-extended). |
* 2. We get by with floating-point arithmetic in a case that |
* Clinger missed -- when we're computing d * 10^n |
* for a small integer d and the integer n is not too |
* much larger than 22 (the maximum integer k for which |
* we can represent 10^k exactly), we may be able to |
* compute (d*10^k) * 10^(e-k) with just one roundoff. |
* 3. Rather than a bit-at-a-time adjustment of the binary |
* result in the hard case, we use floating-point |
* arithmetic to determine the adjustment to within |
* one bit; only in really hard cases do we need to |
* compute a second residual. |
* 4. Because of 3., we don't need a large table of powers of 10 |
* for ten-to-e (just some small tables, e.g. of 10^k |
* for 0 <= k <= 22). |
*/ |
|
/* |
* #define IEEE_8087 for IEEE-arithmetic machines where the least |
* significant byte has the lowest address. |
* #define IEEE_MC68k for IEEE-arithmetic machines where the most |
* significant byte has the lowest address. |
* #define Sudden_Underflow for IEEE-format machines without gradual |
* underflow (i.e., that flush to zero on underflow). |
* #define IBM for IBM mainframe-style floating-point arithmetic. |
* #define VAX for VAX-style floating-point arithmetic. |
* #define Unsigned_Shifts if >> does treats its left operand as unsigned. |
* #define No_leftright to omit left-right logic in fast floating-point |
* computation of dtoa. |
* #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. |
* #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines |
* that use extended-precision instructions to compute rounded |
* products and quotients) with IBM. |
* #define ROUND_BIASED for IEEE-format with biased rounding. |
* #define Inaccurate_Divide for IEEE-format with correctly rounded |
* products but inaccurate quotients, e.g., for Intel i860. |
* #define Just_16 to store 16 bits per 32-bit long when doing high-precision |
* integer arithmetic. Whether this speeds things up or slows things |
* down depends on the machine and the number being converted. |
*/ |
|
#include <_ansi.h> |
#include <stdlib.h> |
#include <string.h> |
#include <reent.h> |
#include "mprec.h" |
|
/* reent.c knows this value */ |
#define _Kmax 15 |
|
_Bigint * |
_DEFUN (Balloc, (ptr, k), struct _reent *ptr _AND int k) |
{ |
int x; |
_Bigint *rv ; |
|
if (ptr->_freelist == NULL) |
{ |
/* Allocate a list of pointers to the mprec objects */ |
ptr->_freelist = (struct _Bigint **) _calloc_r (ptr, |
sizeof (struct _Bigint *), |
_Kmax + 1); |
if (ptr->_freelist == NULL) |
{ |
return NULL; |
} |
} |
|
if ((rv = ptr->_freelist[k]) != 0) |
{ |
ptr->_freelist[k] = rv->_next; |
} |
else |
{ |
x = 1 << k; |
/* Allocate an mprec Bigint and stick in in the freelist */ |
rv = (_Bigint *) _calloc_r (ptr, |
1, |
sizeof (_Bigint) + |
(x-1) * sizeof(rv->_x)); |
if (rv == NULL) return NULL; |
rv->_k = k; |
rv->_maxwds = x; |
} |
rv->_sign = rv->_wds = 0; |
return rv; |
} |
|
void |
_DEFUN (Bfree, (ptr, v), struct _reent *ptr _AND _Bigint * v) |
{ |
if (v) |
{ |
v->_next = ptr->_freelist[v->_k]; |
ptr->_freelist[v->_k] = v; |
} |
} |
|
_Bigint * |
_DEFUN (multadd, (ptr, b, m, a), |
struct _reent *ptr _AND |
_Bigint * b _AND |
int m _AND |
int a) |
{ |
int i, wds; |
__ULong *x, y; |
#ifdef Pack_32 |
__ULong xi, z; |
#endif |
_Bigint *b1; |
|
wds = b->_wds; |
x = b->_x; |
i = 0; |
do |
{ |
#ifdef Pack_32 |
xi = *x; |
y = (xi & 0xffff) * m + a; |
z = (xi >> 16) * m + (y >> 16); |
a = (int) (z >> 16); |
*x++ = (z << 16) + (y & 0xffff); |
#else |
y = *x * m + a; |
a = (int) (y >> 16); |
*x++ = y & 0xffff; |
#endif |
} |
while (++i < wds); |
if (a) |
{ |
if (wds >= b->_maxwds) |
{ |
b1 = Balloc (ptr, b->_k + 1); |
Bcopy (b1, b); |
Bfree (ptr, b); |
b = b1; |
} |
b->_x[wds++] = a; |
b->_wds = wds; |
} |
return b; |
} |
|
_Bigint * |
_DEFUN (s2b, (ptr, s, nd0, nd, y9), |
struct _reent * ptr _AND |
_CONST char *s _AND |
int nd0 _AND |
int nd _AND |
__ULong y9) |
{ |
_Bigint *b; |
int i, k; |
__Long x, y; |
|
x = (nd + 8) / 9; |
for (k = 0, y = 1; x > y; y <<= 1, k++); |
#ifdef Pack_32 |
b = Balloc (ptr, k); |
b->_x[0] = y9; |
b->_wds = 1; |
#else |
b = Balloc (ptr, k + 1); |
b->_x[0] = y9 & 0xffff; |
b->_wds = (b->_x[1] = y9 >> 16) ? 2 : 1; |
#endif |
|
i = 9; |
if (9 < nd0) |
{ |
s += 9; |
do |
b = multadd (ptr, b, 10, *s++ - '0'); |
while (++i < nd0); |
s++; |
} |
else |
s += 10; |
for (; i < nd; i++) |
b = multadd (ptr, b, 10, *s++ - '0'); |
return b; |
} |
|
int |
_DEFUN (hi0bits, |
(x), register __ULong x) |
{ |
register int k = 0; |
|
if (!(x & 0xffff0000)) |
{ |
k = 16; |
x <<= 16; |
} |
if (!(x & 0xff000000)) |
{ |
k += 8; |
x <<= 8; |
} |
if (!(x & 0xf0000000)) |
{ |
k += 4; |
x <<= 4; |
} |
if (!(x & 0xc0000000)) |
{ |
k += 2; |
x <<= 2; |
} |
if (!(x & 0x80000000)) |
{ |
k++; |
if (!(x & 0x40000000)) |
return 32; |
} |
return k; |
} |
|
int |
_DEFUN (lo0bits, (y), __ULong *y) |
{ |
register int k; |
register __ULong x = *y; |
|
if (x & 7) |
{ |
if (x & 1) |
return 0; |
if (x & 2) |
{ |
*y = x >> 1; |
return 1; |
} |
*y = x >> 2; |
return 2; |
} |
k = 0; |
if (!(x & 0xffff)) |
{ |
k = 16; |
x >>= 16; |
} |
if (!(x & 0xff)) |
{ |
k += 8; |
x >>= 8; |
} |
if (!(x & 0xf)) |
{ |
k += 4; |
x >>= 4; |
} |
if (!(x & 0x3)) |
{ |
k += 2; |
x >>= 2; |
} |
if (!(x & 1)) |
{ |
k++; |
x >>= 1; |
if (!x & 1) |
return 32; |
} |
*y = x; |
return k; |
} |
|
_Bigint * |
_DEFUN (i2b, (ptr, i), struct _reent * ptr _AND int i) |
{ |
_Bigint *b; |
|
b = Balloc (ptr, 1); |
b->_x[0] = i; |
b->_wds = 1; |
return b; |
} |
|
_Bigint * |
_DEFUN (mult, (ptr, a, b), struct _reent * ptr _AND _Bigint * a _AND _Bigint * b) |
{ |
_Bigint *c; |
int k, wa, wb, wc; |
__ULong carry, y, z; |
__ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; |
#ifdef Pack_32 |
__ULong z2; |
#endif |
|
if (a->_wds < b->_wds) |
{ |
c = a; |
a = b; |
b = c; |
} |
k = a->_k; |
wa = a->_wds; |
wb = b->_wds; |
wc = wa + wb; |
if (wc > a->_maxwds) |
k++; |
c = Balloc (ptr, k); |
for (x = c->_x, xa = x + wc; x < xa; x++) |
*x = 0; |
xa = a->_x; |
xae = xa + wa; |
xb = b->_x; |
xbe = xb + wb; |
xc0 = c->_x; |
#ifdef Pack_32 |
for (; xb < xbe; xb++, xc0++) |
{ |
if ((y = *xb & 0xffff) != 0) |
{ |
x = xa; |
xc = xc0; |
carry = 0; |
do |
{ |
z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; |
carry = z >> 16; |
z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; |
carry = z2 >> 16; |
Storeinc (xc, z2, z); |
} |
while (x < xae); |
*xc = carry; |
} |
if ((y = *xb >> 16) != 0) |
{ |
x = xa; |
xc = xc0; |
carry = 0; |
z2 = *xc; |
do |
{ |
z = (*x & 0xffff) * y + (*xc >> 16) + carry; |
carry = z >> 16; |
Storeinc (xc, z, z2); |
z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; |
carry = z2 >> 16; |
} |
while (x < xae); |
*xc = z2; |
} |
} |
#else |
for (; xb < xbe; xc0++) |
{ |
if (y = *xb++) |
{ |
x = xa; |
xc = xc0; |
carry = 0; |
do |
{ |
z = *x++ * y + *xc + carry; |
carry = z >> 16; |
*xc++ = z & 0xffff; |
} |
while (x < xae); |
*xc = carry; |
} |
} |
#endif |
for (xc0 = c->_x, xc = xc0 + wc; wc > 0 && !*--xc; --wc); |
c->_wds = wc; |
return c; |
} |
|
_Bigint * |
_DEFUN (pow5mult, |
(ptr, b, k), struct _reent * ptr _AND _Bigint * b _AND int k) |
{ |
_Bigint *b1, *p5, *p51; |
int i; |
static _CONST int p05[3] = {5, 25, 125}; |
|
if ((i = k & 3) != 0) |
b = multadd (ptr, b, p05[i - 1], 0); |
|
if (!(k >>= 2)) |
return b; |
if (!(p5 = ptr->_p5s)) |
{ |
/* first time */ |
p5 = ptr->_p5s = i2b (ptr, 625); |
p5->_next = 0; |
} |
for (;;) |
{ |
if (k & 1) |
{ |
b1 = mult (ptr, b, p5); |
Bfree (ptr, b); |
b = b1; |
} |
if (!(k >>= 1)) |
break; |
if (!(p51 = p5->_next)) |
{ |
p51 = p5->_next = mult (ptr, p5, p5); |
p51->_next = 0; |
} |
p5 = p51; |
} |
return b; |
} |
|
_Bigint * |
_DEFUN (lshift, (ptr, b, k), struct _reent * ptr _AND _Bigint * b _AND int k) |
{ |
int i, k1, n, n1; |
_Bigint *b1; |
__ULong *x, *x1, *xe, z; |
|
#ifdef Pack_32 |
n = k >> 5; |
#else |
n = k >> 4; |
#endif |
k1 = b->_k; |
n1 = n + b->_wds + 1; |
for (i = b->_maxwds; n1 > i; i <<= 1) |
k1++; |
b1 = Balloc (ptr, k1); |
x1 = b1->_x; |
for (i = 0; i < n; i++) |
*x1++ = 0; |
x = b->_x; |
xe = x + b->_wds; |
#ifdef Pack_32 |
if (k &= 0x1f) |
{ |
k1 = 32 - k; |
z = 0; |
do |
{ |
*x1++ = *x << k | z; |
z = *x++ >> k1; |
} |
while (x < xe); |
if ((*x1 = z) != 0) |
++n1; |
} |
#else |
if (k &= 0xf) |
{ |
k1 = 16 - k; |
z = 0; |
do |
{ |
*x1++ = *x << k & 0xffff | z; |
z = *x++ >> k1; |
} |
while (x < xe); |
if (*x1 = z) |
++n1; |
} |
#endif |
else |
do |
*x1++ = *x++; |
while (x < xe); |
b1->_wds = n1 - 1; |
Bfree (ptr, b); |
return b1; |
} |
|
int |
_DEFUN (cmp, (a, b), _Bigint * a _AND _Bigint * b) |
{ |
__ULong *xa, *xa0, *xb, *xb0; |
int i, j; |
|
i = a->_wds; |
j = b->_wds; |
#ifdef DEBUG |
if (i > 1 && !a->_x[i - 1]) |
Bug ("cmp called with a->_x[a->_wds-1] == 0"); |
if (j > 1 && !b->_x[j - 1]) |
Bug ("cmp called with b->_x[b->_wds-1] == 0"); |
#endif |
if (i -= j) |
return i; |
xa0 = a->_x; |
xa = xa0 + j; |
xb0 = b->_x; |
xb = xb0 + j; |
for (;;) |
{ |
if (*--xa != *--xb) |
return *xa < *xb ? -1 : 1; |
if (xa <= xa0) |
break; |
} |
return 0; |
} |
|
_Bigint * |
_DEFUN (diff, (ptr, a, b), struct _reent * ptr _AND |
_Bigint * a _AND _Bigint * b) |
{ |
_Bigint *c; |
int i, wa, wb; |
__Long borrow, y; /* We need signed shifts here. */ |
__ULong *xa, *xae, *xb, *xbe, *xc; |
#ifdef Pack_32 |
__Long z; |
#endif |
|
i = cmp (a, b); |
if (!i) |
{ |
c = Balloc (ptr, 0); |
c->_wds = 1; |
c->_x[0] = 0; |
return c; |
} |
if (i < 0) |
{ |
c = a; |
a = b; |
b = c; |
i = 1; |
} |
else |
i = 0; |
c = Balloc (ptr, a->_k); |
c->_sign = i; |
wa = a->_wds; |
xa = a->_x; |
xae = xa + wa; |
wb = b->_wds; |
xb = b->_x; |
xbe = xb + wb; |
xc = c->_x; |
borrow = 0; |
#ifdef Pack_32 |
do |
{ |
y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; |
borrow = z >> 16; |
Sign_Extend (borrow, z); |
Storeinc (xc, z, y); |
} |
while (xb < xbe); |
while (xa < xae) |
{ |
y = (*xa & 0xffff) + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
z = (*xa++ >> 16) + borrow; |
borrow = z >> 16; |
Sign_Extend (borrow, z); |
Storeinc (xc, z, y); |
} |
#else |
do |
{ |
y = *xa++ - *xb++ + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
*xc++ = y & 0xffff; |
} |
while (xb < xbe); |
while (xa < xae) |
{ |
y = *xa++ + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
*xc++ = y & 0xffff; |
} |
#endif |
while (!*--xc) |
wa--; |
c->_wds = wa; |
return c; |
} |
|
double |
_DEFUN (ulp, (_x), double _x) |
{ |
union double_union x, a; |
register __Long L; |
|
x.d = _x; |
|
L = (word0 (x) & Exp_mask) - (P - 1) * Exp_msk1; |
#ifndef Sudden_Underflow |
if (L > 0) |
{ |
#endif |
#ifdef IBM |
L |= Exp_msk1 >> 4; |
#endif |
word0 (a) = L; |
#ifndef _DOUBLE_IS_32BITS |
word1 (a) = 0; |
#endif |
|
#ifndef Sudden_Underflow |
} |
else |
{ |
L = -L >> Exp_shift; |
if (L < Exp_shift) |
{ |
word0 (a) = 0x80000 >> L; |
#ifndef _DOUBLE_IS_32BITS |
word1 (a) = 0; |
#endif |
} |
else |
{ |
word0 (a) = 0; |
L -= Exp_shift; |
#ifndef _DOUBLE_IS_32BITS |
word1 (a) = L >= 31 ? 1 : 1 << (31 - L); |
#endif |
} |
} |
#endif |
return a.d; |
} |
|
double |
_DEFUN (b2d, (a, e), |
_Bigint * a _AND int *e) |
{ |
__ULong *xa, *xa0, w, y, z; |
int k; |
union double_union d; |
#ifdef VAX |
__ULong d0, d1; |
#else |
#define d0 word0(d) |
#define d1 word1(d) |
#endif |
|
xa0 = a->_x; |
xa = xa0 + a->_wds; |
y = *--xa; |
#ifdef DEBUG |
if (!y) |
Bug ("zero y in b2d"); |
#endif |
k = hi0bits (y); |
*e = 32 - k; |
#ifdef Pack_32 |
if (k < Ebits) |
{ |
d0 = Exp_1 | y >> (Ebits - k); |
w = xa > xa0 ? *--xa : 0; |
#ifndef _DOUBLE_IS_32BITS |
d1 = y << ((32 - Ebits) + k) | w >> (Ebits - k); |
#endif |
goto ret_d; |
} |
z = xa > xa0 ? *--xa : 0; |
if (k -= Ebits) |
{ |
d0 = Exp_1 | y << k | z >> (32 - k); |
y = xa > xa0 ? *--xa : 0; |
#ifndef _DOUBLE_IS_32BITS |
d1 = z << k | y >> (32 - k); |
#endif |
} |
else |
{ |
d0 = Exp_1 | y; |
#ifndef _DOUBLE_IS_32BITS |
d1 = z; |
#endif |
} |
#else |
if (k < Ebits + 16) |
{ |
z = xa > xa0 ? *--xa : 0; |
d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; |
w = xa > xa0 ? *--xa : 0; |
y = xa > xa0 ? *--xa : 0; |
d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; |
goto ret_d; |
} |
z = xa > xa0 ? *--xa : 0; |
w = xa > xa0 ? *--xa : 0; |
k -= Ebits + 16; |
d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; |
y = xa > xa0 ? *--xa : 0; |
d1 = w << k + 16 | y << k; |
#endif |
ret_d: |
#ifdef VAX |
word0 (d) = d0 >> 16 | d0 << 16; |
word1 (d) = d1 >> 16 | d1 << 16; |
#else |
#undef d0 |
#undef d1 |
#endif |
return d.d; |
} |
|
_Bigint * |
_DEFUN (d2b, |
(ptr, _d, e, bits), |
struct _reent * ptr _AND |
double _d _AND |
int *e _AND |
int *bits) |
|
{ |
union double_union d; |
_Bigint *b; |
int de, i, k; |
__ULong *x, y, z; |
#ifdef VAX |
__ULong d0, d1; |
#endif |
d.d = _d; |
#ifdef VAX |
d0 = word0 (d) >> 16 | word0 (d) << 16; |
d1 = word1 (d) >> 16 | word1 (d) << 16; |
#else |
#define d0 word0(d) |
#define d1 word1(d) |
d.d = _d; |
#endif |
|
#ifdef Pack_32 |
b = Balloc (ptr, 1); |
#else |
b = Balloc (ptr, 2); |
#endif |
x = b->_x; |
|
z = d0 & Frac_mask; |
d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ |
#ifdef Sudden_Underflow |
de = (int) (d0 >> Exp_shift); |
#ifndef IBM |
z |= Exp_msk11; |
#endif |
#else |
if ((de = (int) (d0 >> Exp_shift)) != 0) |
z |= Exp_msk1; |
#endif |
#ifdef Pack_32 |
#ifndef _DOUBLE_IS_32BITS |
if (d1) |
{ |
y = d1; |
k = lo0bits (&y); |
if (k) |
{ |
x[0] = y | z << (32 - k); |
z >>= k; |
} |
else |
x[0] = y; |
i = b->_wds = (x[1] = z) ? 2 : 1; |
} |
else |
#endif |
{ |
#ifdef DEBUG |
if (!z) |
Bug ("Zero passed to d2b"); |
#endif |
k = lo0bits (&z); |
x[0] = z; |
i = b->_wds = 1; |
#ifndef _DOUBLE_IS_32BITS |
k += 32; |
#endif |
} |
#else |
if (d1) |
{ |
y = d1; |
k = lo0bits (&y); |
if (k) |
if (k >= 16) |
{ |
x[0] = y | z << 32 - k & 0xffff; |
x[1] = z >> k - 16 & 0xffff; |
x[2] = z >> k; |
i = 2; |
} |
else |
{ |
x[0] = y & 0xffff; |
x[1] = y >> 16 | z << 16 - k & 0xffff; |
x[2] = z >> k & 0xffff; |
x[3] = z >> k + 16; |
i = 3; |
} |
else |
{ |
x[0] = y & 0xffff; |
x[1] = y >> 16; |
x[2] = z & 0xffff; |
x[3] = z >> 16; |
i = 3; |
} |
} |
else |
{ |
#ifdef DEBUG |
if (!z) |
Bug ("Zero passed to d2b"); |
#endif |
k = lo0bits (&z); |
if (k >= 16) |
{ |
x[0] = z; |
i = 0; |
} |
else |
{ |
x[0] = z & 0xffff; |
x[1] = z >> 16; |
i = 1; |
} |
k += 32; |
} |
while (!x[i]) |
--i; |
b->_wds = i + 1; |
#endif |
#ifndef Sudden_Underflow |
if (de) |
{ |
#endif |
#ifdef IBM |
*e = (de - Bias - (P - 1) << 2) + k; |
*bits = 4 * P + 8 - k - hi0bits (word0 (d) & Frac_mask); |
#else |
*e = de - Bias - (P - 1) + k; |
*bits = P - k; |
#endif |
#ifndef Sudden_Underflow |
} |
else |
{ |
*e = de - Bias - (P - 1) + 1 + k; |
#ifdef Pack_32 |
*bits = 32 * i - hi0bits (x[i - 1]); |
#else |
*bits = (i + 2) * 16 - hi0bits (x[i]); |
#endif |
} |
#endif |
return b; |
} |
#undef d0 |
#undef d1 |
|
double |
_DEFUN (ratio, (a, b), _Bigint * a _AND _Bigint * b) |
|
{ |
union double_union da, db; |
int k, ka, kb; |
|
da.d = b2d (a, &ka); |
db.d = b2d (b, &kb); |
#ifdef Pack_32 |
k = ka - kb + 32 * (a->_wds - b->_wds); |
#else |
k = ka - kb + 16 * (a->_wds - b->_wds); |
#endif |
#ifdef IBM |
if (k > 0) |
{ |
word0 (da) += (k >> 2) * Exp_msk1; |
if (k &= 3) |
da.d *= 1 << k; |
} |
else |
{ |
k = -k; |
word0 (db) += (k >> 2) * Exp_msk1; |
if (k &= 3) |
db.d *= 1 << k; |
} |
#else |
if (k > 0) |
word0 (da) += k * Exp_msk1; |
else |
{ |
k = -k; |
word0 (db) += k * Exp_msk1; |
} |
#endif |
return da.d / db.d; |
} |
|
|
_CONST double |
tens[] = |
{ |
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, |
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, |
1e20, 1e21, 1e22, 1e23, 1e24 |
|
}; |
|
#if !defined(_DOUBLE_IS_32BITS) && !defined(__v800) |
_CONST double bigtens[] = |
{1e16, 1e32, 1e64, 1e128, 1e256}; |
|
_CONST double tinytens[] = |
{1e-16, 1e-32, 1e-64, 1e-128, 1e-256}; |
#else |
_CONST double bigtens[] = |
{1e16, 1e32}; |
|
_CONST double tinytens[] = |
{1e-16, 1e-32}; |
#endif |
|
|
double |
_DEFUN (_mprec_log10, (dig), |
int dig) |
{ |
double v = 1.0; |
if (dig < 24) |
return tens[dig]; |
while (dig > 0) |
{ |
v *= 10; |
dig--; |
} |
return v; |
} |
/malloc.c
0,0 → 1,206
/* VxWorks provides its own version of malloc, and we can't use this |
one because VxWorks does not provide sbrk. So we have a hook to |
not compile this code. */ |
|
/* The routines here are simple cover fns to the routines that do the real |
work (the reentrant versions). */ |
/* FIXME: Does the warning below (see WARNINGS) about non-reentrancy still |
apply? A first guess would be "no", but how about reentrancy in the *same* |
thread? */ |
|
#ifdef MALLOC_PROVIDED |
|
int _dummy_malloc = 1; |
|
#else |
|
/* |
FUNCTION |
<<malloc>>, <<realloc>>, <<free>>---manage memory |
|
INDEX |
malloc |
INDEX |
realloc |
INDEX |
free |
INDEX |
memalign |
INDEX |
malloc_usable_size |
INDEX |
_malloc_r |
INDEX |
_realloc_r |
INDEX |
_free_r |
INDEX |
_memalign_r |
INDEX |
_malloc_usable_size_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
void *malloc(size_t <[nbytes]>); |
void *realloc(void *<[aptr]>, size_t <[nbytes]>); |
void free(void *<[aptr]>); |
|
void *memalign(size_t <[align]>, size_t <[nbytes]>); |
|
size_t malloc_usable_size(void *<[aptr]>); |
|
void *_malloc_r(void *<[reent]>, size_t <[nbytes]>); |
void *_realloc_r(void *<[reent]>, |
void *<[aptr]>, size_t <[nbytes]>); |
void _free_r(void *<[reent]>, void *<[aptr]>); |
|
void *_memalign_r(void *<[reent]>, |
size_t <[align]>, size_t <[nbytes]>); |
|
size_t _malloc_usable_size_r(void *<[reent]>, void *<[aptr]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
char *malloc(<[nbytes]>) |
size_t <[nbytes]>; |
|
char *realloc(<[aptr]>, <[nbytes]>) |
char *<[aptr]>; |
size_t <[nbytes]>; |
|
void free(<[aptr]>) |
char *<[aptr]>; |
|
char *memalign(<[align]>, <[nbytes]>) |
size_t <[align]>; |
size_t <[nbytes]>; |
|
size_t malloc_usable_size(<[aptr]>) |
char *<[aptr]>; |
|
char *_malloc_r(<[reent]>,<[nbytes]>) |
char *<[reent]>; |
size_t <[nbytes]>; |
|
char *_realloc_r(<[reent]>, <[aptr]>, <[nbytes]>) |
char *<[reent]>; |
char *<[aptr]>; |
size_t <[nbytes]>; |
|
void _free_r(<[reent]>, <[aptr]>) |
char *<[reent]>; |
char *<[aptr]>; |
|
char *_memalign_r(<[reent]>, <[align]>, <[nbytes]>) |
char *<[reent]>; |
size_t <[align]>; |
size_t <[nbytes]>; |
|
size_t malloc_usable_size(<[reent]>, <[aptr]>) |
char *<[reent]>; |
char *<[aptr]>; |
|
DESCRIPTION |
These functions manage a pool of system memory. |
|
Use <<malloc>> to request allocation of an object with at least |
<[nbytes]> bytes of storage available. If the space is available, |
<<malloc>> returns a pointer to a newly allocated block as its result. |
|
If you already have a block of storage allocated by <<malloc>>, but |
you no longer need all the space allocated to it, you can make it |
smaller by calling <<realloc>> with both the object pointer and the |
new desired size as arguments. <<realloc>> guarantees that the |
contents of the smaller object match the beginning of the original object. |
|
Similarly, if you need more space for an object, use <<realloc>> to |
request the larger size; again, <<realloc>> guarantees that the |
beginning of the new, larger object matches the contents of the |
original object. |
|
When you no longer need an object originally allocated by <<malloc>> |
or <<realloc>> (or the related function <<calloc>>), return it to the |
memory storage pool by calling <<free>> with the address of the object |
as the argument. You can also use <<realloc>> for this purpose by |
calling it with <<0>> as the <[nbytes]> argument. |
|
The <<memalign>> function returns a block of size <[nbytes]> aligned |
to a <[align]> boundary. The <[align]> argument must be a power of |
two. |
|
The <<malloc_usable_size>> function takes a pointer to a block |
allocated by <<malloc>>. It returns the amount of space that is |
available in the block. This may or may not be more than the size |
requested from <<malloc>>, due to alignment or minimum size |
constraints. |
|
The alternate functions <<_malloc_r>>, <<_realloc_r>>, <<_free_r>>, |
<<_memalign_r>>, and <<_malloc_usable_size_r>> are reentrant versions. |
The extra argument <[reent]> is a pointer to a reentrancy structure. |
|
If you have multiple threads of execution which may call any of these |
routines, or if any of these routines may be called reentrantly, then |
you must provide implementations of the <<__malloc_lock>> and |
<<__malloc_unlock>> functions for your system. See the documentation |
for those functions. |
|
These functions operate by calling the function <<_sbrk_r>> or |
<<sbrk>>, which allocates space. You may need to provide one of these |
functions for your system. <<_sbrk_r>> is called with a positive |
value to allocate more space, and with a negative value to release |
previously allocated space if it is no longer required. |
@xref{Stubs}. |
|
RETURNS |
<<malloc>> returns a pointer to the newly allocated space, if |
successful; otherwise it returns <<NULL>>. If your application needs |
to generate empty objects, you may use <<malloc(0)>> for this purpose. |
|
<<realloc>> returns a pointer to the new block of memory, or <<NULL>> |
if a new block could not be allocated. <<NULL>> is also the result |
when you use `<<realloc(<[aptr]>,0)>>' (which has the same effect as |
`<<free(<[aptr]>)>>'). You should always check the result of |
<<realloc>>; successful reallocation is not guaranteed even when |
you request a smaller object. |
|
<<free>> does not return a result. |
|
<<memalign>> returns a pointer to the newly allocated space. |
|
<<malloc_usable_size>> returns the usable size. |
|
PORTABILITY |
<<malloc>>, <<realloc>>, and <<free>> are specified by the ANSI C |
standard, but other conforming implementations of <<malloc>> may |
behave differently when <[nbytes]> is zero. |
|
<<memalign>> is part of SVR4. |
|
<<malloc_usable_size>> is not portable. |
|
Supporting OS subroutines required: <<sbrk>>. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
|
#ifndef _REENT_ONLY |
|
_PTR |
_DEFUN (malloc, (nbytes), |
size_t nbytes) /* get a block */ |
{ |
return _malloc_r (_REENT, nbytes); |
} |
|
void |
_DEFUN (free, (aptr), |
_PTR aptr) |
{ |
_free_r (_REENT, aptr); |
} |
|
#endif |
|
#endif /* ! defined (MALLOC_PROVIDED) */ |
/bsearch.c
0,0 → 1,100
/* |
* bsearch.c |
* Original Author: G. Haley |
* Rewritten by: G. Noer |
* |
* Searches an array of nmemb members, the initial member of which is pointed |
* to by base, for a member that matches the object pointed to by key. The |
* contents of the array shall be in ascending order according to a comparison |
* function pointed to by compar. The function shall return an integer less |
* than, equal to or greater than zero if the first argument is considered to be |
* respectively less than, equal to or greater than the second. Returns a |
* pointer to the matching member of the array, or a null pointer if no match |
* is found. |
*/ |
|
/* |
FUNCTION |
<<bsearch>>---binary search |
|
INDEX |
bsearch |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
void *bsearch(const void *<[key]>, const void *<[base]>, |
size_t <[nmemb]>, size_t <[size]>, |
int (*<[compar]>)(const void *, const void *)); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
char *bsearch(<[key]>, <[base]>, <[nmemb]>, <[size]>, <[compar]>) |
char *<[key]>; |
char *<[base]>; |
size_t <[nmemb]>, <[size]>; |
int (*<[compar]>)(); |
|
DESCRIPTION |
<<bsearch>> searches an array beginning at <[base]> for any element |
that matches <[key]>, using binary search. <[nmemb]> is the element |
count of the array; <[size]> is the size of each element. |
|
The array must be sorted in ascending order with respect to the |
comparison function <[compar]> (which you supply as the last argument of |
<<bsearch>>). |
|
You must define the comparison function <<(*<[compar]>)>> to have two |
arguments; its result must be negative if the first argument is |
less than the second, zero if the two arguments match, and |
positive if the first argument is greater than the second (where |
``less than'' and ``greater than'' refer to whatever arbitrary |
ordering is appropriate). |
|
RETURNS |
Returns a pointer to an element of <[array]> that matches <[key]>. If |
more than one matching element is available, the result may point to |
any of them. |
|
PORTABILITY |
<<bsearch>> is ANSI. |
|
No supporting OS subroutines are required. |
*/ |
|
#include <stdlib.h> |
|
_PTR |
_DEFUN (bsearch, (key, base, nmemb, size, compar), |
_CONST _PTR key _AND |
_CONST _PTR base _AND |
size_t nmemb _AND |
size_t size _AND |
int _EXFUN ((*compar), (const _PTR, const _PTR))) |
{ |
_PTR current; |
size_t lower = 0; |
size_t upper = nmemb; |
size_t index; |
int result; |
|
if (nmemb == 0 || size == 0) |
return NULL; |
|
while (lower < upper) |
{ |
index = (lower + upper) / 2; |
current = (_PTR) (((char *) base) + (index * size)); |
|
result = compar (key, current); |
|
if (result < 0) |
upper = index; |
else if (result > 0) |
lower = index + 1; |
else |
return current; |
} |
|
return NULL; |
} |
|
/mstats.c
0,0 → 1,151
/* VxWorks provides its own version of malloc, and we can't use this |
one because VxWorks does not provide sbrk. So we have a hook to |
not compile this code. */ |
|
#ifdef MALLOC_PROVIDED |
|
int _dummy_mstats = 1; |
|
#else |
|
/* |
FUNCTION |
<<mallinfo>>, <<malloc_stats>>, <<mallopt>>--malloc support |
|
INDEX |
mallinfo |
INDEX |
malloc_stats |
INDEX |
mallopt |
INDEX |
_mallinfo_r |
INDEX |
_malloc_stats_r |
INDEX |
_mallopt_r |
|
ANSI_SYNOPSIS |
#include <malloc.h> |
struct mallinfo mallinfo(void); |
void malloc_stats(void); |
int mallopt(int <[parameter]>, <[value]>); |
|
struct mallinfo _mallinfo_r(void *<[reent]>); |
void _malloc_stats_r(void *<[reent]>); |
int _mallopt_r(void *<[reent]>, int <[parameter]>, <[value]>); |
|
TRAD_SYNOPSIS |
#include <malloc.h> |
struct mallinfo mallinfo(); |
|
void malloc_stats(); |
|
int mallopt(<[parameter]>, <[value]>) |
int <[parameter]>; |
int <[value]>; |
|
struct mallinfo _mallinfo_r(<[reent]>); |
char *<[reent]>; |
|
void _malloc_stats_r(<[reent]>); |
char *<[reent]>; |
|
int _mallopt_r(<[reent]>, <[parameter]>, <[value]>) |
char *<[reent]>; |
int <[parameter]>; |
int <[value]>; |
|
DESCRIPTION |
<<mallinfo>> returns a structure describing the current state of |
memory allocation. The structure is defined in malloc.h. The |
following fields are defined: <<arena>> is the total amount of space |
in the heap; <<ordblks>> is the number of chunks which are not in use; |
<<uordblks>> is the total amount of space allocated by <<malloc>>; |
<<fordblks>> is the total amount of space not in use; <<keepcost>> is |
the size of the top most memory block. |
|
<<malloc_stats>> print some statistics about memory allocation on |
standard error. |
|
<<mallopt>> takes a parameter and a value. The parameters are defined |
in malloc.h, and may be one of the following: <<M_TRIM_THRESHOLD>> |
sets the maximum amount of unused space in the top most block before |
releasing it back to the system in <<free>> (the space is released by |
calling <<_sbrk_r>> with a negative argument); <<M_TOP_PAD>> is the |
amount of padding to allocate whenever <<_sbrk_r>> is called to |
allocate more space. |
|
The alternate functions <<_mallinfo_r>>, <<_malloc_stats_r>>, and |
<<_mallopt_r>> are reentrant versions. The extra argument <[reent]> |
is a pointer to a reentrancy structure. |
|
RETURNS |
<<mallinfo>> returns a mallinfo structure. The structure is defined |
in malloc.h. |
|
<<malloc_stats>> does not return a result. |
|
<<mallopt>> returns zero if the parameter could not be set, or |
non-zero if it could be set. |
|
PORTABILITY |
<<mallinfo>> and <<mallopt>> are provided by SVR4, but <<mallopt>> |
takes different parameters on different systems. <<malloc_stats>> is |
not portable. |
|
*/ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
#include <stdio.h> |
|
#ifndef _REENT_ONLY |
|
struct mallinfo |
_DEFUN_VOID (mallinfo) |
{ |
return _mallinfo_r (_REENT); |
} |
|
void |
_DEFUN_VOID (malloc_stats) |
{ |
_malloc_stats_r (_REENT); |
} |
|
int |
_DEFUN (mallopt, (p, v), |
int p _AND |
int v) |
{ |
return _mallopt_r (_REENT, p, v); |
} |
|
#endif |
|
/* mstats is now compatibility code. It used to be real, for a |
previous version of the malloc routines. It now just calls |
malloc_stats. */ |
|
void |
_DEFUN (_mstats_r, (ptr, s), |
struct _reent *ptr _AND |
char *s) |
{ |
fiprintf (_stderr_r (ptr), "Memory allocation statistics %s\n", s); |
_malloc_stats_r (ptr); |
} |
|
#ifndef _REENT_ONLY |
void |
_DEFUN (mstats, (s), |
char *s) |
{ |
_mstats_r (_REENT, s); |
} |
|
#endif |
#endif /* ! defined (MALLOC_PROVIDED) */ |
/mprec.h
0,0 → 1,313
/**************************************************************** |
* |
* The author of this software is David M. Gay. |
* |
* Copyright (c) 1991 by AT&T. |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose without fee is hereby granted, provided that this entire notice |
* is included in all copies of any software which is or includes a copy |
* or modification of this software and in all copies of the supporting |
* documentation for such software. |
* |
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED |
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY |
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY |
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. |
* |
***************************************************************/ |
|
/* Please send bug reports to |
David M. Gay |
AT&T Bell Laboratories, Room 2C-463 |
600 Mountain Avenue |
Murray Hill, NJ 07974-2070 |
U.S.A. |
dmg@research.att.com or research!dmg |
*/ |
|
#include <ieeefp.h> |
#include <math.h> |
#include <float.h> |
#include <errno.h> |
#include <sys/config.h> |
|
#ifdef __IEEE_LITTLE_ENDIAN |
#define IEEE_8087 |
#endif |
|
#ifdef __IEEE_BIG_ENDIAN |
#define IEEE_MC68k |
#endif |
|
#ifdef __Z8000__ |
#define Just_16 |
#endif |
|
#ifdef DEBUG |
#include "stdio.h" |
#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} |
#endif |
|
#ifdef Unsigned_Shifts |
#define Sign_Extend(a,b) if (b < 0) a |= (__uint32_t)0xffff0000; |
#else |
#define Sign_Extend(a,b) /*no-op*/ |
#endif |
|
#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 |
Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. |
#endif |
|
/* If we are going to examine or modify specific bits in a double using |
the word0 and/or word1 macros, then we must wrap the double inside |
a union. This is necessary to avoid undefined behavior according to |
the ANSI C spec. */ |
union double_union |
{ |
double d; |
__uint32_t i[2]; |
}; |
|
#ifdef IEEE_8087 |
#define word0(x) (x.i[1]) |
#define word1(x) (x.i[0]) |
#else |
#define word0(x) (x.i[0]) |
#define word1(x) (x.i[1]) |
#endif |
|
/* The following definition of Storeinc is appropriate for MIPS processors. |
* An alternative that might be better on some machines is |
* #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) |
*/ |
#if defined (__IEEE_BYTES_LITTLE_ENDIAN) + defined (IEEE_8087) + defined (VAX) |
#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ |
((unsigned short *)a)[0] = (unsigned short)c, a++) |
#else |
#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ |
((unsigned short *)a)[1] = (unsigned short)c, a++) |
#endif |
|
/* #define P DBL_MANT_DIG */ |
/* Ten_pmax = floor(P*log(2)/log(5)) */ |
/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ |
/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ |
/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ |
|
#if defined(IEEE_8087) + defined(IEEE_MC68k) |
#if defined (_DOUBLE_IS_32BITS) |
#define Exp_shift 23 |
#define Exp_shift1 23 |
#define Exp_msk1 ((__uint32_t)0x00800000L) |
#define Exp_msk11 ((__uint32_t)0x00800000L) |
#define Exp_mask ((__uint32_t)0x7f800000L) |
#define P 24 |
#define Bias 127 |
#if 0 |
#define IEEE_Arith /* it is, but the code doesn't handle IEEE singles yet */ |
#endif |
#define Emin (-126) |
#define Exp_1 ((__uint32_t)0x3f800000L) |
#define Exp_11 ((__uint32_t)0x3f800000L) |
#define Ebits 8 |
#define Frac_mask ((__uint32_t)0x007fffffL) |
#define Frac_mask1 ((__uint32_t)0x007fffffL) |
#define Ten_pmax 10 |
#define Sign_bit ((__uint32_t)0x80000000L) |
#define Ten_pmax 10 |
#define Bletch 2 |
#define Bndry_mask ((__uint32_t)0x007fffffL) |
#define Bndry_mask1 ((__uint32_t)0x007fffffL) |
#define LSB 1 |
#define Sign_bit ((__uint32_t)0x80000000L) |
#define Log2P 1 |
#define Tiny0 0 |
#define Tiny1 1 |
#define Quick_max 5 |
#define Int_max 6 |
#define Infinite(x) (word0(x) == ((__uint32_t)0x7f800000L)) |
#undef word0 |
#undef word1 |
|
#define word0(x) (x.i[0]) |
#define word1(x) 0 |
#else |
|
#define Exp_shift 20 |
#define Exp_shift1 20 |
#define Exp_msk1 ((__uint32_t)0x100000L) |
#define Exp_msk11 ((__uint32_t)0x100000L) |
#define Exp_mask ((__uint32_t)0x7ff00000L) |
#define P 53 |
#define Bias 1023 |
#define IEEE_Arith |
#define Emin (-1022) |
#define Exp_1 ((__uint32_t)0x3ff00000L) |
#define Exp_11 ((__uint32_t)0x3ff00000L) |
#define Ebits 11 |
#define Frac_mask ((__uint32_t)0xfffffL) |
#define Frac_mask1 ((__uint32_t)0xfffffL) |
#define Ten_pmax 22 |
#define Bletch 0x10 |
#define Bndry_mask ((__uint32_t)0xfffffL) |
#define Bndry_mask1 ((__uint32_t)0xfffffL) |
#define LSB 1 |
#define Sign_bit ((__uint32_t)0x80000000L) |
#define Log2P 1 |
#define Tiny0 0 |
#define Tiny1 1 |
#define Quick_max 14 |
#define Int_max 14 |
#define Infinite(x) (word0(x) == ((__uint32_t)0x7ff00000L)) /* sufficient test for here */ |
#endif |
|
#else |
#undef Sudden_Underflow |
#define Sudden_Underflow |
#ifdef IBM |
#define Exp_shift 24 |
#define Exp_shift1 24 |
#define Exp_msk1 ((__uint32_t)0x1000000L) |
#define Exp_msk11 ((__uint32_t)0x1000000L) |
#define Exp_mask ((__uint32_t)0x7f000000L) |
#define P 14 |
#define Bias 65 |
#define Exp_1 ((__uint32_t)0x41000000L) |
#define Exp_11 ((__uint32_t)0x41000000L) |
#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ |
#define Frac_mask ((__uint32_t)0xffffffL) |
#define Frac_mask1 ((__uint32_t)0xffffffL) |
#define Bletch 4 |
#define Ten_pmax 22 |
#define Bndry_mask ((__uint32_t)0xefffffL) |
#define Bndry_mask1 ((__uint32_t)0xffffffL) |
#define LSB 1 |
#define Sign_bit ((__uint32_t)0x80000000L) |
#define Log2P 4 |
#define Tiny0 ((__uint32_t)0x100000L) |
#define Tiny1 0 |
#define Quick_max 14 |
#define Int_max 15 |
#else /* VAX */ |
#define Exp_shift 23 |
#define Exp_shift1 7 |
#define Exp_msk1 0x80 |
#define Exp_msk11 ((__uint32_t)0x800000L) |
#define Exp_mask ((__uint32_t)0x7f80L) |
#define P 56 |
#define Bias 129 |
#define Exp_1 ((__uint32_t)0x40800000L) |
#define Exp_11 ((__uint32_t)0x4080L) |
#define Ebits 8 |
#define Frac_mask ((__uint32_t)0x7fffffL) |
#define Frac_mask1 ((__uint32_t)0xffff007fL) |
#define Ten_pmax 24 |
#define Bletch 2 |
#define Bndry_mask ((__uint32_t)0xffff007fL) |
#define Bndry_mask1 ((__uint32_t)0xffff007fL) |
#define LSB ((__uint32_t)0x10000L) |
#define Sign_bit ((__uint32_t)0x8000L) |
#define Log2P 1 |
#define Tiny0 0x80 |
#define Tiny1 0 |
#define Quick_max 15 |
#define Int_max 15 |
#endif |
#endif |
|
#ifndef IEEE_Arith |
#define ROUND_BIASED |
#endif |
|
#ifdef RND_PRODQUOT |
#define rounded_product(a,b) a = rnd_prod(a, b) |
#define rounded_quotient(a,b) a = rnd_quot(a, b) |
#ifdef KR_headers |
extern double rnd_prod(), rnd_quot(); |
#else |
extern double rnd_prod(double, double), rnd_quot(double, double); |
#endif |
#else |
#define rounded_product(a,b) a *= b |
#define rounded_quotient(a,b) a /= b |
#endif |
|
#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) |
#define Big1 ((__uint32_t)0xffffffffL) |
|
#ifndef Just_16 |
/* When Pack_32 is not defined, we store 16 bits per 32-bit long. |
* This makes some inner loops simpler and sometimes saves work |
* during multiplications, but it often seems to make things slightly |
* slower. Hence the default is now to store 32 bits per long. |
*/ |
|
#ifndef Pack_32 |
#define Pack_32 |
#endif |
#endif |
|
|
#ifdef __cplusplus |
extern "C" double strtod(const char *s00, char **se); |
extern "C" char *dtoa(double d, int mode, int ndigits, |
int *decpt, int *sign, char **rve); |
#endif |
|
|
typedef struct _Bigint _Bigint; |
|
#define Balloc _Balloc |
#define Bfree _Bfree |
#define multadd _multadd |
#define s2b _s2b |
#define lo0bits _lo0bits |
#define hi0bits _hi0bits |
#define i2b _i2b |
#define mult _multiply |
#define pow5mult _pow5mult |
#define lshift _lshift |
#define cmp __mcmp |
#define diff __mdiff |
#define ulp _ulp |
#define b2d _b2d |
#define d2b _d2b |
#define ratio _ratio |
|
#define tens __mprec_tens |
#define bigtens __mprec_bigtens |
#define tinytens __mprec_tinytens |
|
struct _reent ; |
double _EXFUN(ulp,(double x)); |
double _EXFUN(b2d,(_Bigint *a , int *e)); |
_Bigint * _EXFUN(Balloc,(struct _reent *p, int k)); |
void _EXFUN(Bfree,(struct _reent *p, _Bigint *v)); |
_Bigint * _EXFUN(multadd,(struct _reent *p, _Bigint *, int, int)); |
_Bigint * _EXFUN(s2b,(struct _reent *, const char*, int, int, __ULong)); |
_Bigint * _EXFUN(i2b,(struct _reent *,int)); |
_Bigint * _EXFUN(mult, (struct _reent *, _Bigint *, _Bigint *)); |
_Bigint * _EXFUN(pow5mult, (struct _reent *, _Bigint *, int k)); |
int _EXFUN(hi0bits,(__ULong)); |
int _EXFUN(lo0bits,(__ULong *)); |
_Bigint * _EXFUN(d2b,(struct _reent *p, double d, int *e, int *bits)); |
_Bigint * _EXFUN(lshift,(struct _reent *p, _Bigint *b, int k)); |
_Bigint * _EXFUN(diff,(struct _reent *p, _Bigint *a, _Bigint *b)); |
int _EXFUN(cmp,(_Bigint *a, _Bigint *b)); |
|
double _EXFUN(ratio,(_Bigint *a, _Bigint *b)); |
#define Bcopy(x,y) memcpy((char *)&x->_sign, (char *)&y->_sign, y->_wds*sizeof(__Long) + 2*sizeof(int)) |
|
#if defined(_DOUBLE_IS_32BITS) && defined(__v800) |
#define n_bigtens 2 |
#else |
#define n_bigtens 5 |
#endif |
|
extern _CONST double tinytens[]; |
extern _CONST double bigtens[]; |
extern _CONST double tens[]; |
|
|
double _EXFUN(_mprec_log10,(int)); |
/strtoul.c
0,0 → 1,206
/* |
FUNCTION |
<<strtoul>>---string to unsigned long |
|
INDEX |
strtoul |
INDEX |
_strtoul_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
unsigned long strtoul(const char *<[s]>, char **<[ptr]>, |
int <[base]>); |
|
unsigned long _strtoul_r(void *<[reent]>, const char *<[s]>, |
char **<[ptr]>, int <[base]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
unsigned long strtoul(<[s]>, <[ptr]>, <[base]>) |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
unsigned long _strtoul_r(<[reent]>, <[s]>, <[ptr]>, <[base]>) |
char *<[reent]>; |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
DESCRIPTION |
The function <<strtoul>> converts the string <<*<[s]>>> to |
an <<unsigned long>>. First, it breaks down the string into three parts: |
leading whitespace, which is ignored; a subject string consisting |
of the digits meaningful in the radix specified by <[base]> |
(for example, <<0>> through <<7>> if the value of <[base]> is 8); |
and a trailing portion consisting of one or more unparseable characters, |
which always includes the terminating null character. Then, it attempts |
to convert the subject string into an unsigned long integer, and returns the |
result. |
|
If the value of <[base]> is zero, the subject string is expected to look |
like a normal C integer constant (save that no optional sign is permitted): |
a possible <<0x>> indicating hexadecimal radix, and a number. |
If <[base]> is between 2 and 36, the expected form of the subject is a |
sequence of digits (which may include letters, depending on the |
base) representing an integer in the radix specified by <[base]>. |
The letters <<a>>--<<z>> (or <<A>>--<<Z>>) are used as digits valued from |
10 to 35. If <[base]> is 16, a leading <<0x>> is permitted. |
|
The subject sequence is the longest initial sequence of the input |
string that has the expected form, starting with the first |
non-whitespace character. If the string is empty or consists entirely |
of whitespace, or if the first non-whitespace character is not a |
permissible digit, the subject string is empty. |
|
If the subject string is acceptable, and the value of <[base]> is zero, |
<<strtoul>> attempts to determine the radix from the input string. A |
string with a leading <<0x>> is treated as a hexadecimal value; a string with |
a leading <<0>> and no <<x>> is treated as octal; all other strings are |
treated as decimal. If <[base]> is between 2 and 36, it is used as the |
conversion radix, as described above. Finally, a pointer to the first |
character past the converted subject string is stored in <[ptr]>, if |
<[ptr]> is not <<NULL>>. |
|
If the subject string is empty (that is, if <<*>><[s]> does not start |
with a substring in acceptable form), no conversion |
is performed and the value of <[s]> is stored in <[ptr]> (if <[ptr]> is |
not <<NULL>>). |
|
The alternate function <<_strtoul_r>> is a reentrant version. The |
extra argument <[reent]> is a pointer to a reentrancy structure. |
|
|
RETURNS |
<<strtoul>> returns the converted value, if any. If no conversion was |
made, <<0>> is returned. |
|
<<strtoul>> returns <<ULONG_MAX>> if the magnitude of the converted |
value is too large, and sets <<errno>> to <<ERANGE>>. |
|
PORTABILITY |
<<strtoul>> is ANSI. |
|
<<strtoul>> requires no supporting OS subroutines. |
*/ |
|
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#include <_ansi.h> |
#include <limits.h> |
#include <ctype.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <reent.h> |
|
/* |
* Convert a string to an unsigned long integer. |
* |
* Ignores `locale' stuff. Assumes that the upper and lower case |
* alphabets and digits are each contiguous. |
*/ |
unsigned long |
_DEFUN (_strtoul_r, (rptr, nptr, endptr, base), |
struct _reent *rptr _AND |
_CONST char *nptr _AND |
char **endptr _AND |
int base) |
{ |
register const char *s = nptr; |
register unsigned long acc; |
register int c; |
register unsigned long cutoff; |
register int neg = 0, any, cutlim; |
|
/* |
* See strtol for comments as to the logic used. |
*/ |
do { |
c = *s++; |
} while (isspace(c)); |
if (c == '-') { |
neg = 1; |
c = *s++; |
} else if (c == '+') |
c = *s++; |
if ((base == 0 || base == 16) && |
c == '0' && (*s == 'x' || *s == 'X')) { |
c = s[1]; |
s += 2; |
base = 16; |
} |
if (base == 0) |
base = c == '0' ? 8 : 10; |
cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; |
cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; |
for (acc = 0, any = 0;; c = *s++) { |
if (isdigit(c)) |
c -= '0'; |
else if (isalpha(c)) |
c -= isupper(c) ? 'A' - 10 : 'a' - 10; |
else |
break; |
if (c >= base) |
break; |
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) |
any = -1; |
else { |
any = 1; |
acc *= base; |
acc += c; |
} |
} |
if (any < 0) { |
acc = ULONG_MAX; |
rptr->_errno = ERANGE; |
} else if (neg) |
acc = -acc; |
if (endptr != 0) |
*endptr = (char *) (any ? s - 1 : nptr); |
return (acc); |
} |
|
#ifndef _REENT_ONLY |
|
unsigned long |
_DEFUN (strtoul, (s, ptr, base), |
_CONST char *s _AND |
char **ptr _AND |
int base) |
{ |
return _strtoul_r (_REENT, s, ptr, base); |
} |
|
#endif |
/efgcvt.c
0,0 → 1,202
/* |
FUNCTION |
<<ecvt>>,<<ecvtf>>,<<fcvt>>,<<fcvtf>>---double or float to string |
|
INDEX |
ecvt |
INDEX |
fcvt |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
|
char *ecvt(double <[val]>, int <[chars]>, int *<[decpt]>, int *<[sgn]>); |
char *ecvtf(float <[val]>, int <[chars]>, int *<[decpt]>, int *<[sgn]>); |
|
char *fcvt(double <[val]>, int <[decimals]>, |
int *<[decpt]>, int *<[sgn]>); |
char *fcvtf(float <[val]>, int <[decimals]>, |
int *<[decpt]>, int *<[sgn]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
|
char *ecvt(<[val]>, <[chars]>, <[decpt]>, <[sgn]>); |
double <[val]>; |
int <[chars]>; |
int *<[decpt]>; |
int *<[sgn]>; |
char *ecvtf(<[val]>, <[chars]>, <[decpt]>, <[sgn]>); |
float <[val]>; |
int <[chars]>; |
int *<[decpt]>; |
int *<[sgn]>; |
|
char *fcvt(<[val]>, <[decimals]>, <[decpt]>, <[sgn]>); |
double <[val]>; |
int <[decimals]>; |
int *<[decpt]>; |
int *<[sgn]>; |
char *fcvtf(<[val]>, <[decimals]>, <[decpt]>, <[sgn]>); |
float <[val]>; |
int <[decimals]>; |
int *<[decpt]>; |
int *<[sgn]>; |
|
DESCRIPTION |
<<ecvt>> and <<fcvt>> produce (null-terminated) strings of digits |
representating the <<double>> number <[val]>. |
<<ecvtf>> and <<fcvtf>> produce the corresponding character |
representations of <<float>> numbers. |
|
(The <<stdlib>> functions <<ecvtbuf>> and <<fcvtbuf>> are reentrant |
versions of <<ecvt>> and <<fcvt>>.) |
|
The only difference between <<ecvt>> and <<fcvt>> is the |
interpretation of the second argument (<[chars]> or <[decimals]>). |
For <<ecvt>>, the second argument <[chars]> specifies the total number |
of characters to write (which is also the number of significant digits |
in the formatted string, since these two functions write only digits). |
For <<fcvt>>, the second argument <[decimals]> specifies the number of |
characters to write after the decimal point; all digits for the integer |
part of <[val]> are always included. |
|
Since <<ecvt>> and <<fcvt>> write only digits in the output string, |
they record the location of the decimal point in <<*<[decpt]>>>, and |
the sign of the number in <<*<[sgn]>>>. After formatting a number, |
<<*<[decpt]>>> contains the number of digits to the left of the |
decimal point. <<*<[sgn]>>> contains <<0>> if the number is positive, |
and <<1>> if it is negative. |
|
RETURNS |
All four functions return a pointer to the new string containing a |
character representation of <[val]>. |
|
PORTABILITY |
None of these functions are ANSI C. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
|
NEWPAGE |
FUNCTION |
<<gvcvt>>, <<gcvtf>>---format double or float as string |
|
INDEX |
gcvt |
INDEX |
gcvtf |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
|
char *gcvt(double <[val]>, int <[precision]>, char *<[buf]>); |
char *gcvtf(float <[val]>, int <[precision]>, char *<[buf]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
|
char *gcvt(<[val]>, <[precision]>, <[buf]>); |
double <[val]>; |
int <[precision]>; |
char *<[buf]>; |
char *gcvtf(<[val]>, <[precision]>, <[buf]>); |
float <[val]>; |
int <[precision]>; |
char *<[buf]>; |
|
DESCRIPTION |
<<gcvt>> writes a fully formatted number as a null-terminated |
string in the buffer <<*<[buf]>>>. <<gdvtf>> produces corresponding |
character representations of <<float>> numbers. |
|
<<gcvt>> uses the same rules as the <<printf>> format |
`<<%.<[precision]>g>>'---only negative values are signed (with |
`<<->>'), and either exponential or ordinary decimal-fraction format |
is chosen depending on the number of significant digits (specified by |
<[precision]>). |
|
RETURNS |
The result is a pointer to the formatted representation of <[val]> |
(the same as the argument <[buf]>). |
|
PORTABILITY |
Neither function is ANSI C. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include "local.h" |
|
char * |
_DEFUN (fcvt, (d, ndigit, decpt, sign), |
double d _AND |
int ndigit _AND |
int *decpt _AND |
int *sign) |
{ |
return fcvtbuf (d, ndigit, decpt, sign, NULL); |
} |
|
char * |
_DEFUN (fcvtf, (d, ndigit, decpt, sign), |
float d _AND |
int ndigit _AND |
int *decpt _AND |
int *sign) |
{ |
return fcvt ((float) d, ndigit, decpt, sign); |
} |
|
|
char * |
_DEFUN (gcvtf, (d, ndigit, buf), |
float d _AND |
int ndigit _AND |
char *buf) |
{ |
double asd = d; |
return gcvt (asd, ndigit, buf); |
} |
|
|
char * |
_DEFUN (ecvt, (d, ndigit, decpt, sign), |
double d _AND |
int ndigit _AND |
int *decpt _AND |
int *sign) |
{ |
return ecvtbuf (d, ndigit, decpt, sign, NULL); |
} |
|
char * |
_DEFUN (ecvtf, (d, ndigit, decpt, sign), |
float d _AND |
int ndigit _AND |
int *decpt _AND |
int *sign) |
{ |
return ecvt ((double) d, ndigit, decpt, sign); |
} |
|
|
char * |
_DEFUN (gcvt, (d, ndigit, buf), |
double d _AND |
int ndigit _AND |
char *buf) |
{ |
char *tbuf = buf; |
if (d < 0) { |
*buf = '-'; |
buf++; |
ndigit--; |
} |
return (_gcvt (_REENT, d, ndigit, buf, 'g', 0) ? tbuf : 0); |
} |
/environ.c
0,0 → 1,23
/* Copyright (c) 1995, 1996 Cygnus Support. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that the above copyright notice and this paragraph are |
* duplicated in all such forms and that any documentation, |
* advertising materials, and other materials related to such |
* distribution and use acknowledge that the software was developed |
* at Cygnus Support, Inc. Cygnus Support, Inc. may not be used to |
* endorse or promote products derived from this software without |
* specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
/* Provide a definition of `environ' if crt0.o doesn't. */ |
|
static char *initial_env[] = { 0 }; |
|
/* Posix says `environ' is a pointer to a null terminated list of pointers. |
Hence `environ' itself is never NULL. */ |
char **environ = &initial_env[0]; |
/strtoll_r.c
0,0 → 1,140
/* |
This code is based on strtoul.c which has the following copyright. |
It is used to convert a string into a signed long long. |
|
long long _strtoll_r (struct _reent *rptr, const char *s, |
char **ptr, int base); |
*/ |
|
/*- |
* Copyright (c) 1990 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#ifdef __GNUC__ |
|
#define _GNU_SOURCE |
#include <_ansi.h> |
#include <limits.h> |
#include <ctype.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <reent.h> |
|
/* |
* Convert a string to a long long integer. |
* |
* Ignores `locale' stuff. Assumes that the upper and lower case |
* alphabets and digits are each contiguous. |
*/ |
long long |
_DEFUN (_strtoll_r, (rptr, nptr, endptr, base), |
struct _reent *rptr _AND |
_CONST char *nptr _AND |
char **endptr _AND |
int base) |
{ |
register const char *s = nptr; |
register unsigned long long acc; |
register int c; |
register unsigned long long cutoff; |
register int neg = 0, any, cutlim; |
|
/* |
* Skip white space and pick up leading +/- sign if any. |
* If base is 0, allow 0x for hex and 0 for octal, else |
* assume decimal; if base is already 16, allow 0x. |
*/ |
do { |
c = *s++; |
} while (isspace(c)); |
if (c == '-') { |
neg = 1; |
c = *s++; |
} else if (c == '+') |
c = *s++; |
if ((base == 0 || base == 16) && |
c == '0' && (*s == 'x' || *s == 'X')) { |
c = s[1]; |
s += 2; |
base = 16; |
} |
if (base == 0) |
base = c == '0' ? 8 : 10; |
|
/* |
* Compute the cutoff value between legal numbers and illegal |
* numbers. That is the largest legal value, divided by the |
* base. An input number that is greater than this value, if |
* followed by a legal input character, is too big. One that |
* is equal to this value may be valid or not; the limit |
* between valid and invalid numbers is then based on the last |
* digit. For instance, if the range for longs is |
* [-2147483648..2147483647] and the input base is 10, |
* cutoff will be set to 214748364 and cutlim to either |
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated |
* a value > 214748364, or equal but the next digit is > 7 (or 8), |
* the number is too big, and we will return a range error. |
* |
* Set any if any `digits' consumed; make it negative to indicate |
* overflow. |
*/ |
cutoff = neg ? -(unsigned long long)LONG_LONG_MIN : LONG_LONG_MAX; |
cutlim = cutoff % (unsigned long long)base; |
cutoff /= (unsigned long long)base; |
for (acc = 0, any = 0;; c = *s++) { |
if (isdigit(c)) |
c -= '0'; |
else if (isalpha(c)) |
c -= isupper(c) ? 'A' - 10 : 'a' - 10; |
else |
break; |
if (c >= base) |
break; |
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) |
any = -1; |
else { |
any = 1; |
acc *= base; |
acc += c; |
} |
} |
if (any < 0) { |
acc = neg ? LONG_LONG_MIN : LONG_LONG_MAX; |
rptr->_errno = ERANGE; |
} else if (neg) |
acc = -acc; |
if (endptr != 0) |
*endptr = (char *) (any ? s - 1 : nptr); |
return (acc); |
} |
|
#endif /* __GNUC__ */ |
/system.c
0,0 → 1,186
/* |
FUNCTION |
<<system>>---execute command string |
|
INDEX |
system |
INDEX |
_system_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int system(char *<[s]>); |
|
int _system_r(void *<[reent]>, char *<[s]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int system(<[s]>) |
char *<[s]>; |
|
int _system_r(<[reent]>, <[s]>) |
char *<[reent]>; |
char *<[s]>; |
|
DESCRIPTION |
|
Use <<system>> to pass a command string <<*<[s]>>> to <</bin/sh>> on |
your system, and wait for it to finish executing. |
|
Use ``<<system(NULL)>>'' to test whether your system has <</bin/sh>> |
available. |
|
The alternate function <<_system_r>> is a reentrant version. The |
extra argument <[reent]> is a pointer to a reentrancy structure. |
|
RETURNS |
<<system(NULL)>> returns a non-zero value if <</bin/sh>> is available, and |
<<0>> if it is not. |
|
With a command argument, the result of <<system>> is the exit status |
returned by <</bin/sh>>. |
|
PORTABILITY |
ANSI C requires <<system>>, but leaves the nature and effects of a |
command processor undefined. ANSI C does, however, specify that |
<<system(NULL)>> return zero or nonzero to report on the existence of |
a command processor. |
|
POSIX.2 requires <<system>>, and requires that it invoke a <<sh>>. |
Where <<sh>> is found is left unspecified. |
|
Supporting OS subroutines required: <<_exit>>, <<_execve>>, <<_fork_r>>, |
<<_wait_r>>. |
*/ |
|
#include <errno.h> |
#include <stddef.h> |
#include <stdlib.h> |
#include <unistd.h> |
#include <_syslist.h> |
#include <reent.h> |
|
#if defined (unix) || defined (__CYGWIN__) |
static int do_system (); |
#endif |
|
int |
_system_r (ptr, s) |
struct _reent *ptr; |
_CONST char *s; |
{ |
#ifdef NO_EXEC |
if (s == NULL) |
return 0; |
errno = ENOSYS; |
return -1; |
#else |
|
/* ??? How to handle (s == NULL) here is not exactly clear. |
If _fork_r fails, that's not really a justification for returning 0. |
For now we always return 0 and leave it to each target to explicitly |
handle otherwise (this can always be relaxed in the future). */ |
|
#if defined (unix) || defined (__CYGWIN__) |
if (s == NULL) |
return 1; |
return do_system (ptr, s); |
#else |
if (s == NULL) |
return 0; |
errno = ENOSYS; |
return -1; |
#endif |
|
#endif |
} |
|
#ifndef _REENT_ONLY |
|
int |
system (s) |
_CONST char *s; |
{ |
return _system_r (_REENT, s); |
} |
|
#endif |
|
#if defined (unix) && !defined (__CYGWIN__) && !defined(__rtems__) |
extern char **environ; |
|
/* Only deal with a pointer to environ, to work around subtle bugs with shared |
libraries and/or small data systems where the user declares his own |
'environ'. */ |
static char ***p_environ = &environ; |
|
static int |
do_system (ptr, s) |
struct _reent *ptr; |
_CONST char *s; |
{ |
char *argv[4]; |
int pid, status; |
|
argv[0] = "sh"; |
argv[1] = "-c"; |
argv[2] = (char *) s; |
argv[3] = NULL; |
|
if ((pid = _fork_r (ptr)) == 0) |
{ |
_execve ("/bin/sh", argv, *p_environ); |
exit (100); |
} |
else if (pid == -1) |
return -1; |
else |
{ |
int rc = _wait_r (ptr, &status); |
if (rc == -1) |
return -1; |
status = (status >> 8) & 0xff; |
return status; |
} |
} |
#endif |
|
#if defined (__CYGWIN__) |
static int |
do_system (ptr, s) |
struct _reent *ptr; |
_CONST char *s; |
{ |
char *argv[4]; |
int pid, status; |
|
argv[0] = "sh"; |
argv[1] = "-c"; |
argv[2] = (char *) s; |
argv[3] = NULL; |
|
if ((pid = vfork ()) == 0) |
{ |
/* ??? It's not clear what's the right path to take (pun intended :-). |
There won't be an "sh" in any fixed location so we need each user |
to be able to say where to find "sh". That suggests using an |
environment variable, but after a few more such situations we may |
have too many of them. */ |
char *sh = getenv ("SH_PATH"); |
if (sh == NULL) |
sh = "/bin/sh"; |
_execve (sh, argv, environ); |
exit (100); |
} |
else if (pid == -1) |
return -1; |
else |
{ |
int rc = _wait (&status); |
if (rc == -1) |
return -1; |
status = (status >> 8) & 0xff; |
return status; |
} |
} |
#endif |
/dtoastub.c
0,0 → 1,23
#include <_ansi.h> |
#include <stdlib.h> |
#include <reent.h> |
#include <string.h> |
|
/* Nothing in newlib actually *calls* dtoa, they all call _dtoa_r, so this |
is a safe way of providing it to the user. */ |
#ifndef NO_REENT |
|
char * |
_DEFUN (__dtoa, |
(d, mode, ndigits, decpt, sign, rve), |
double d _AND |
int mode _AND |
int ndigits _AND |
int *decpt _AND |
int *sign _AND |
char **rve) |
{ |
return _dtoa_r (_REENT, d, mode, ndigits, decpt, sign, rve); |
} |
|
#endif |
/dtoa.c
0,0 → 1,853
/**************************************************************** |
* |
* The author of this software is David M. Gay. |
* |
* Copyright (c) 1991 by AT&T. |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose without fee is hereby granted, provided that this entire notice |
* is included in all copies of any software which is or includes a copy |
* or modification of this software and in all copies of the supporting |
* documentation for such software. |
* |
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED |
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY |
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY |
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. |
* |
***************************************************************/ |
|
/* Please send bug reports to |
David M. Gay |
AT&T Bell Laboratories, Room 2C-463 |
600 Mountain Avenue |
Murray Hill, NJ 07974-2070 |
U.S.A. |
dmg@research.att.com or research!dmg |
*/ |
|
#include <_ansi.h> |
#include <stdlib.h> |
#include <reent.h> |
#include <string.h> |
#include "mprec.h" |
|
static int |
_DEFUN (quorem, |
(b, S), |
_Bigint * b _AND _Bigint * S) |
{ |
int n; |
__Long borrow, y; |
__ULong carry, q, ys; |
__ULong *bx, *bxe, *sx, *sxe; |
#ifdef Pack_32 |
__Long z; |
__ULong si, zs; |
#endif |
|
n = S->_wds; |
#ifdef DEBUG |
/*debug*/ if (b->_wds > n) |
/*debug*/ Bug ("oversize b in quorem"); |
#endif |
if (b->_wds < n) |
return 0; |
sx = S->_x; |
sxe = sx + --n; |
bx = b->_x; |
bxe = bx + n; |
q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ |
#ifdef DEBUG |
/*debug*/ if (q > 9) |
/*debug*/ Bug ("oversized quotient in quorem"); |
#endif |
if (q) |
{ |
borrow = 0; |
carry = 0; |
do |
{ |
#ifdef Pack_32 |
si = *sx++; |
ys = (si & 0xffff) * q + carry; |
zs = (si >> 16) * q + (ys >> 16); |
carry = zs >> 16; |
y = (*bx & 0xffff) - (ys & 0xffff) + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
z = (*bx >> 16) - (zs & 0xffff) + borrow; |
borrow = z >> 16; |
Sign_Extend (borrow, z); |
Storeinc (bx, z, y); |
#else |
ys = *sx++ * q + carry; |
carry = ys >> 16; |
y = *bx - (ys & 0xffff) + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
*bx++ = y & 0xffff; |
#endif |
} |
while (sx <= sxe); |
if (!*bxe) |
{ |
bx = b->_x; |
while (--bxe > bx && !*bxe) |
--n; |
b->_wds = n; |
} |
} |
if (cmp (b, S) >= 0) |
{ |
q++; |
borrow = 0; |
carry = 0; |
bx = b->_x; |
sx = S->_x; |
do |
{ |
#ifdef Pack_32 |
si = *sx++; |
ys = (si & 0xffff) + carry; |
zs = (si >> 16) + (ys >> 16); |
carry = zs >> 16; |
y = (*bx & 0xffff) - (ys & 0xffff) + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
z = (*bx >> 16) - (zs & 0xffff) + borrow; |
borrow = z >> 16; |
Sign_Extend (borrow, z); |
Storeinc (bx, z, y); |
#else |
ys = *sx++ + carry; |
carry = ys >> 16; |
y = *bx - (ys & 0xffff) + borrow; |
borrow = y >> 16; |
Sign_Extend (borrow, y); |
*bx++ = y & 0xffff; |
#endif |
} |
while (sx <= sxe); |
bx = b->_x; |
bxe = bx + n; |
if (!*bxe) |
{ |
while (--bxe > bx && !*bxe) |
--n; |
b->_wds = n; |
} |
} |
return q; |
} |
|
/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. |
* |
* Inspired by "How to Print Floating-Point Numbers Accurately" by |
* Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. |
* |
* Modifications: |
* 1. Rather than iterating, we use a simple numeric overestimate |
* to determine k = floor(log10(d)). We scale relevant |
* quantities using O(log2(k)) rather than O(k) multiplications. |
* 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't |
* try to generate digits strictly left to right. Instead, we |
* compute with fewer bits and propagate the carry if necessary |
* when rounding the final digit up. This is often faster. |
* 3. Under the assumption that input will be rounded nearest, |
* mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. |
* That is, we allow equality in stopping tests when the |
* round-nearest rule will give the same floating-point value |
* as would satisfaction of the stopping test with strict |
* inequality. |
* 4. We remove common factors of powers of 2 from relevant |
* quantities. |
* 5. When converting floating-point integers less than 1e16, |
* we use floating-point arithmetic rather than resorting |
* to multiple-precision integers. |
* 6. When asked to produce fewer than 15 digits, we first try |
* to get by with floating-point arithmetic; we resort to |
* multiple-precision integer arithmetic only if we cannot |
* guarantee that the floating-point calculation has given |
* the correctly rounded result. For k requested digits and |
* "uniformly" distributed input, the probability is |
* something like 10^(k-15) that we must resort to the long |
* calculation. |
*/ |
|
|
char * |
_DEFUN (_dtoa_r, |
(ptr, _d, mode, ndigits, decpt, sign, rve), |
struct _reent *ptr _AND |
double _d _AND |
int mode _AND |
int ndigits _AND |
int *decpt _AND |
int *sign _AND |
char **rve) |
{ |
/* Arguments ndigits, decpt, sign are similar to those |
of ecvt and fcvt; trailing zeros are suppressed from |
the returned string. If not null, *rve is set to point |
to the end of the return value. If d is +-Infinity or NaN, |
then *decpt is set to 9999. |
|
mode: |
0 ==> shortest string that yields d when read in |
and rounded to nearest. |
1 ==> like 0, but with Steele & White stopping rule; |
e.g. with IEEE P754 arithmetic , mode 0 gives |
1e23 whereas mode 1 gives 9.999999999999999e22. |
2 ==> max(1,ndigits) significant digits. This gives a |
return value similar to that of ecvt, except |
that trailing zeros are suppressed. |
3 ==> through ndigits past the decimal point. This |
gives a return value similar to that from fcvt, |
except that trailing zeros are suppressed, and |
ndigits can be negative. |
4-9 should give the same return values as 2-3, i.e., |
4 <= mode <= 9 ==> same return as mode |
2 + (mode & 1). These modes are mainly for |
debugging; often they run slower but sometimes |
faster than modes 2-3. |
4,5,8,9 ==> left-to-right digit generation. |
6-9 ==> don't try fast floating-point estimate |
(if applicable). |
|
Values of mode other than 0-9 are treated as mode 0. |
|
Sufficient space is allocated to the return value |
to hold the suppressed trailing zeros. |
*/ |
|
int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, |
k_check, leftright, m2, m5, s2, s5, spec_case, try_quick; |
union double_union d, d2, eps; |
__Long L; |
#ifndef Sudden_Underflow |
int denorm; |
__ULong x; |
#endif |
_Bigint *b, *b1, *delta, *mlo, *mhi, *S; |
double ds; |
char *s, *s0; |
|
d.d = _d; |
|
if (ptr->_result) |
{ |
ptr->_result->_k = ptr->_result_k; |
ptr->_result->_maxwds = 1 << ptr->_result_k; |
Bfree (ptr, ptr->_result); |
ptr->_result = 0; |
} |
|
if (word0 (d) & Sign_bit) |
{ |
/* set sign for everything, including 0's and NaNs */ |
*sign = 1; |
word0 (d) &= ~Sign_bit; /* clear sign bit */ |
} |
else |
*sign = 0; |
|
#if defined(IEEE_Arith) + defined(VAX) |
#ifdef IEEE_Arith |
if ((word0 (d) & Exp_mask) == Exp_mask) |
#else |
if (word0 (d) == 0x8000) |
#endif |
{ |
/* Infinity or NaN */ |
*decpt = 9999; |
s = |
#ifdef IEEE_Arith |
!word1 (d) && !(word0 (d) & 0xfffff) ? "Infinity" : |
#endif |
"NaN"; |
if (rve) |
*rve = |
#ifdef IEEE_Arith |
s[3] ? s + 8 : |
#endif |
s + 3; |
return s; |
} |
#endif |
#ifdef IBM |
d.d += 0; /* normalize */ |
#endif |
if (!d.d) |
{ |
*decpt = 1; |
s = "0"; |
if (rve) |
*rve = s + 1; |
return s; |
} |
|
b = d2b (ptr, d.d, &be, &bbits); |
#ifdef Sudden_Underflow |
i = (int) (word0 (d) >> Exp_shift1 & (Exp_mask >> Exp_shift1)); |
#else |
if ((i = (int) (word0 (d) >> Exp_shift1 & (Exp_mask >> Exp_shift1))) != 0) |
{ |
#endif |
d2.d = d.d; |
word0 (d2) &= Frac_mask1; |
word0 (d2) |= Exp_11; |
#ifdef IBM |
if (j = 11 - hi0bits (word0 (d2) & Frac_mask)) |
d2.d /= 1 << j; |
#endif |
|
/* log(x) ~=~ log(1.5) + (x-1.5)/1.5 |
* log10(x) = log(x) / log(10) |
* ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) |
* log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) |
* |
* This suggests computing an approximation k to log10(d) by |
* |
* k = (i - Bias)*0.301029995663981 |
* + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); |
* |
* We want k to be too large rather than too small. |
* The error in the first-order Taylor series approximation |
* is in our favor, so we just round up the constant enough |
* to compensate for any error in the multiplication of |
* (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, |
* and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, |
* adding 1e-13 to the constant term more than suffices. |
* Hence we adjust the constant term to 0.1760912590558. |
* (We could get a more accurate k by invoking log10, |
* but this is probably not worthwhile.) |
*/ |
|
i -= Bias; |
#ifdef IBM |
i <<= 2; |
i += j; |
#endif |
#ifndef Sudden_Underflow |
denorm = 0; |
} |
else |
{ |
/* d is denormalized */ |
|
i = bbits + be + (Bias + (P - 1) - 1); |
x = (i > 32) ? (word0 (d) << (64 - i)) | (word1 (d) >> (i - 32)) |
: (word1 (d) << (32 - i)); |
d2.d = x; |
word0 (d2) -= 31 * Exp_msk1; /* adjust exponent */ |
i -= (Bias + (P - 1) - 1) + 1; |
denorm = 1; |
} |
#endif |
ds = (d2.d - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981; |
k = (int) ds; |
if (ds < 0. && ds != k) |
k--; /* want k = floor(ds) */ |
k_check = 1; |
if (k >= 0 && k <= Ten_pmax) |
{ |
if (d.d < tens[k]) |
k--; |
k_check = 0; |
} |
j = bbits - i - 1; |
if (j >= 0) |
{ |
b2 = 0; |
s2 = j; |
} |
else |
{ |
b2 = -j; |
s2 = 0; |
} |
if (k >= 0) |
{ |
b5 = 0; |
s5 = k; |
s2 += k; |
} |
else |
{ |
b2 -= k; |
b5 = -k; |
s5 = 0; |
} |
if (mode < 0 || mode > 9) |
mode = 0; |
try_quick = 1; |
if (mode > 5) |
{ |
mode -= 4; |
try_quick = 0; |
} |
leftright = 1; |
ilim = ilim1 = -1; |
switch (mode) |
{ |
case 0: |
case 1: |
i = 18; |
ndigits = 0; |
break; |
case 2: |
leftright = 0; |
/* no break */ |
case 4: |
if (ndigits <= 0) |
ndigits = 1; |
ilim = ilim1 = i = ndigits; |
break; |
case 3: |
leftright = 0; |
/* no break */ |
case 5: |
i = ndigits + k + 1; |
ilim = i; |
ilim1 = i - 1; |
if (i <= 0) |
i = 1; |
} |
j = sizeof (__ULong); |
for (ptr->_result_k = 0; sizeof (_Bigint) - sizeof (__ULong) + j <= i; |
j <<= 1) |
ptr->_result_k++; |
ptr->_result = Balloc (ptr, ptr->_result_k); |
s = s0 = (char *) ptr->_result; |
|
if (ilim >= 0 && ilim <= Quick_max && try_quick) |
{ |
/* Try to get by with floating-point arithmetic. */ |
|
i = 0; |
d2.d = d.d; |
k0 = k; |
ilim0 = ilim; |
ieps = 2; /* conservative */ |
if (k > 0) |
{ |
ds = tens[k & 0xf]; |
j = k >> 4; |
if (j & Bletch) |
{ |
/* prevent overflows */ |
j &= Bletch - 1; |
d.d /= bigtens[n_bigtens - 1]; |
ieps++; |
} |
for (; j; j >>= 1, i++) |
if (j & 1) |
{ |
ieps++; |
ds *= bigtens[i]; |
} |
d.d /= ds; |
} |
else if ((j1 = -k) != 0) |
{ |
d.d *= tens[j1 & 0xf]; |
for (j = j1 >> 4; j; j >>= 1, i++) |
if (j & 1) |
{ |
ieps++; |
d.d *= bigtens[i]; |
} |
} |
if (k_check && d.d < 1. && ilim > 0) |
{ |
if (ilim1 <= 0) |
goto fast_failed; |
ilim = ilim1; |
k--; |
d.d *= 10.; |
ieps++; |
} |
eps.d = ieps * d.d + 7.; |
word0 (eps) -= (P - 1) * Exp_msk1; |
if (ilim == 0) |
{ |
S = mhi = 0; |
d.d -= 5.; |
if (d.d > eps.d) |
goto one_digit; |
if (d.d < -eps.d) |
goto no_digits; |
goto fast_failed; |
} |
#ifndef No_leftright |
if (leftright) |
{ |
/* Use Steele & White method of only |
* generating digits needed. |
*/ |
eps.d = 0.5 / tens[ilim - 1] - eps.d; |
for (i = 0;;) |
{ |
L = d.d; |
d.d -= L; |
*s++ = '0' + (int) L; |
if (d.d < eps.d) |
goto ret1; |
if (1. - d.d < eps.d) |
goto bump_up; |
if (++i >= ilim) |
break; |
eps.d *= 10.; |
d.d *= 10.; |
} |
} |
else |
{ |
#endif |
/* Generate ilim digits, then fix them up. */ |
eps.d *= tens[ilim - 1]; |
for (i = 1;; i++, d.d *= 10.) |
{ |
L = d.d; |
d.d -= L; |
*s++ = '0' + (int) L; |
if (i == ilim) |
{ |
if (d.d > 0.5 + eps.d) |
goto bump_up; |
else if (d.d < 0.5 - eps.d) |
{ |
while (*--s == '0'); |
s++; |
goto ret1; |
} |
break; |
} |
} |
#ifndef No_leftright |
} |
#endif |
fast_failed: |
s = s0; |
d.d = d2.d; |
k = k0; |
ilim = ilim0; |
} |
|
/* Do we have a "small" integer? */ |
|
if (be >= 0 && k <= Int_max) |
{ |
/* Yes. */ |
ds = tens[k]; |
if (ndigits < 0 && ilim <= 0) |
{ |
S = mhi = 0; |
if (ilim < 0 || d.d <= 5 * ds) |
goto no_digits; |
goto one_digit; |
} |
for (i = 1;; i++) |
{ |
L = d.d / ds; |
d.d -= L * ds; |
#ifdef Check_FLT_ROUNDS |
/* If FLT_ROUNDS == 2, L will usually be high by 1 */ |
if (d.d < 0) |
{ |
L--; |
d.d += ds; |
} |
#endif |
*s++ = '0' + (int) L; |
if (i == ilim) |
{ |
d.d += d.d; |
if ((d.d > ds) || ((d.d == ds) && (L & 1))) |
{ |
bump_up: |
while (*--s == '9') |
if (s == s0) |
{ |
k++; |
*s = '0'; |
break; |
} |
++*s++; |
} |
break; |
} |
if (!(d.d *= 10.)) |
break; |
} |
goto ret1; |
} |
|
m2 = b2; |
m5 = b5; |
mhi = mlo = 0; |
if (leftright) |
{ |
if (mode < 2) |
{ |
i = |
#ifndef Sudden_Underflow |
denorm ? be + (Bias + (P - 1) - 1 + 1) : |
#endif |
#ifdef IBM |
1 + 4 * P - 3 - bbits + ((bbits + be - 1) & 3); |
#else |
1 + P - bbits; |
#endif |
} |
else |
{ |
j = ilim - 1; |
if (m5 >= j) |
m5 -= j; |
else |
{ |
s5 += j -= m5; |
b5 += j; |
m5 = 0; |
} |
if ((i = ilim) < 0) |
{ |
m2 -= i; |
i = 0; |
} |
} |
b2 += i; |
s2 += i; |
mhi = i2b (ptr, 1); |
} |
if (m2 > 0 && s2 > 0) |
{ |
i = m2 < s2 ? m2 : s2; |
b2 -= i; |
m2 -= i; |
s2 -= i; |
} |
if (b5 > 0) |
{ |
if (leftright) |
{ |
if (m5 > 0) |
{ |
mhi = pow5mult (ptr, mhi, m5); |
b1 = mult (ptr, mhi, b); |
Bfree (ptr, b); |
b = b1; |
} |
if ((j = b5 - m5) != 0) |
b = pow5mult (ptr, b, j); |
} |
else |
b = pow5mult (ptr, b, b5); |
} |
S = i2b (ptr, 1); |
if (s5 > 0) |
S = pow5mult (ptr, S, s5); |
|
/* Check for special case that d is a normalized power of 2. */ |
|
spec_case = 0; |
if (mode < 2) |
{ |
if (!word1 (d) && !(word0 (d) & Bndry_mask) |
#ifndef Sudden_Underflow |
&& word0 (d) & Exp_mask |
#endif |
) |
{ |
/* The special case */ |
b2 += Log2P; |
s2 += Log2P; |
spec_case = 1; |
} |
} |
|
/* Arrange for convenient computation of quotients: |
* shift left if necessary so divisor has 4 leading 0 bits. |
* |
* Perhaps we should just compute leading 28 bits of S once |
* and for all and pass them and a shift to quorem, so it |
* can do shifts and ors to compute the numerator for q. |
*/ |
|
#ifdef Pack_32 |
if ((i = ((s5 ? 32 - hi0bits (S->_x[S->_wds - 1]) : 1) + s2) & 0x1f) != 0) |
i = 32 - i; |
#else |
if ((i = ((s5 ? 32 - hi0bits (S->_x[S->_wds - 1]) : 1) + s2) & 0xf) != 0) |
i = 16 - i; |
#endif |
if (i > 4) |
{ |
i -= 4; |
b2 += i; |
m2 += i; |
s2 += i; |
} |
else if (i < 4) |
{ |
i += 28; |
b2 += i; |
m2 += i; |
s2 += i; |
} |
if (b2 > 0) |
b = lshift (ptr, b, b2); |
if (s2 > 0) |
S = lshift (ptr, S, s2); |
if (k_check) |
{ |
if (cmp (b, S) < 0) |
{ |
k--; |
b = multadd (ptr, b, 10, 0); /* we botched the k estimate */ |
if (leftright) |
mhi = multadd (ptr, mhi, 10, 0); |
ilim = ilim1; |
} |
} |
if (ilim <= 0 && mode > 2) |
{ |
if (ilim < 0 || cmp (b, S = multadd (ptr, S, 5, 0)) <= 0) |
{ |
/* no digits, fcvt style */ |
no_digits: |
k = -1 - ndigits; |
goto ret; |
} |
one_digit: |
*s++ = '1'; |
k++; |
goto ret; |
} |
if (leftright) |
{ |
if (m2 > 0) |
mhi = lshift (ptr, mhi, m2); |
|
/* Compute mlo -- check for special case |
* that d is a normalized power of 2. |
*/ |
|
mlo = mhi; |
if (spec_case) |
{ |
mhi = Balloc (ptr, mhi->_k); |
Bcopy (mhi, mlo); |
mhi = lshift (ptr, mhi, Log2P); |
} |
|
for (i = 1;; i++) |
{ |
dig = quorem (b, S) + '0'; |
/* Do we yet have the shortest decimal string |
* that will round to d? |
*/ |
j = cmp (b, mlo); |
delta = diff (ptr, S, mhi); |
j1 = delta->_sign ? 1 : cmp (b, delta); |
Bfree (ptr, delta); |
#ifndef ROUND_BIASED |
if (j1 == 0 && !mode && !(word1 (d) & 1)) |
{ |
if (dig == '9') |
goto round_9_up; |
if (j > 0) |
dig++; |
*s++ = dig; |
goto ret; |
} |
#endif |
if ((j < 0) || ((j == 0) && !mode |
#ifndef ROUND_BIASED |
&& !(word1 (d) & 1) |
#endif |
)) |
{ |
if (j1 > 0) |
{ |
b = lshift (ptr, b, 1); |
j1 = cmp (b, S); |
if (((j1 > 0) || ((j1 == 0) && (dig & 1))) |
&& dig++ == '9') |
goto round_9_up; |
} |
*s++ = dig; |
goto ret; |
} |
if (j1 > 0) |
{ |
if (dig == '9') |
{ /* possible if i == 1 */ |
round_9_up: |
*s++ = '9'; |
goto roundoff; |
} |
*s++ = dig + 1; |
goto ret; |
} |
*s++ = dig; |
if (i == ilim) |
break; |
b = multadd (ptr, b, 10, 0); |
if (mlo == mhi) |
mlo = mhi = multadd (ptr, mhi, 10, 0); |
else |
{ |
mlo = multadd (ptr, mlo, 10, 0); |
mhi = multadd (ptr, mhi, 10, 0); |
} |
} |
} |
else |
for (i = 1;; i++) |
{ |
*s++ = dig = quorem (b, S) + '0'; |
if (i >= ilim) |
break; |
b = multadd (ptr, b, 10, 0); |
} |
|
/* Round off last digit */ |
|
b = lshift (ptr, b, 1); |
j = cmp (b, S); |
if ((j > 0) || ((j == 0) && (dig & 1))) |
{ |
roundoff: |
while (*--s == '9') |
if (s == s0) |
{ |
k++; |
*s++ = '1'; |
goto ret; |
} |
++*s++; |
} |
else |
{ |
while (*--s == '0'); |
s++; |
} |
ret: |
Bfree (ptr, S); |
if (mhi) |
{ |
if (mlo && mlo != mhi) |
Bfree (ptr, mlo); |
Bfree (ptr, mhi); |
} |
ret1: |
Bfree (ptr, b); |
*s = 0; |
*decpt = k + 1; |
if (rve) |
*rve = s; |
return s0; |
} |
/mtrim.c
0,0 → 1,17
/* mtrim.c -- a wrapper for malloc_trim. */ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <stdlib.h> |
#include <malloc.h> |
|
#ifndef _REENT_ONLY |
|
int |
_DEFUN (malloc_trim, (pad), |
size_t pad) |
{ |
return _malloc_trim_r (_REENT, pad); |
} |
|
#endif |
/strtoull.c
0,0 → 1,139
/* |
FUNCTION |
<<strtoull>>---string to unsigned long long |
|
INDEX |
strtoull |
INDEX |
_strtoull_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
unsigned long long strtoull(const char *<[s]>, char **<[ptr]>, |
int <[base]>); |
|
unsigned long long _strtoull_r(void *<[reent]>, const char *<[s]>, |
char **<[ptr]>, int <[base]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
unsigned long long strtoull(<[s]>, <[ptr]>, <[base]>) |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
unsigned long long _strtoull_r(<[reent]>, <[s]>, <[ptr]>, <[base]>) |
char *<[reent]>; |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
DESCRIPTION |
The function <<strtoull>> converts the string <<*<[s]>>> to |
an <<unsigned long long>>. First, it breaks down the string into three parts: |
leading whitespace, which is ignored; a subject string consisting |
of the digits meaningful in the radix specified by <[base]> |
(for example, <<0>> through <<7>> if the value of <[base]> is 8); |
and a trailing portion consisting of one or more unparseable characters, |
which always includes the terminating null character. Then, it attempts |
to convert the subject string into an unsigned long long integer, and returns the |
result. |
|
If the value of <[base]> is zero, the subject string is expected to look |
like a normal C integer constant (save that no optional sign is permitted): |
a possible <<0x>> indicating hexadecimal radix, and a number. |
If <[base]> is between 2 and 36, the expected form of the subject is a |
sequence of digits (which may include letters, depending on the |
base) representing an integer in the radix specified by <[base]>. |
The letters <<a>>--<<z>> (or <<A>>--<<Z>>) are used as digits valued from |
10 to 35. If <[base]> is 16, a leading <<0x>> is permitted. |
|
The subject sequence is the longest initial sequence of the input |
string that has the expected form, starting with the first |
non-whitespace character. If the string is empty or consists entirely |
of whitespace, or if the first non-whitespace character is not a |
permissible digit, the subject string is empty. |
|
If the subject string is acceptable, and the value of <[base]> is zero, |
<<strtoull>> attempts to determine the radix from the input string. A |
string with a leading <<0x>> is treated as a hexadecimal value; a string with |
a leading <<0>> and no <<x>> is treated as octal; all other strings are |
treated as decimal. If <[base]> is between 2 and 36, it is used as the |
conversion radix, as described above. Finally, a pointer to the first |
character past the converted subject string is stored in <[ptr]>, if |
<[ptr]> is not <<NULL>>. |
|
If the subject string is empty (that is, if <<*>><[s]> does not start |
with a substring in acceptable form), no conversion |
is performed and the value of <[s]> is stored in <[ptr]> (if <[ptr]> is |
not <<NULL>>). |
|
The alternate function <<_strtoull_r>> is a reentrant version. The |
extra argument <[reent]> is a pointer to a reentrancy structure. |
|
|
RETURNS |
<<strtoull>> returns the converted value, if any. If no conversion was |
made, <<0>> is returned. |
|
<<strtoull>> returns <<ULONG_LONG_MAX>> if the magnitude of the converted |
value is too large, and sets <<errno>> to <<ERANGE>>. |
|
PORTABILITY |
<<strtoull>> is nonstandard. |
|
<<strtoull>> requires no supporting OS subroutines. |
*/ |
|
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#include <_ansi.h> |
#include <limits.h> |
#include <ctype.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <reent.h> |
|
#ifndef _REENT_ONLY |
|
unsigned long long |
_DEFUN (strtoull, (s, ptr, base), |
_CONST char *s _AND |
char **ptr _AND |
int base) |
{ |
return _strtoull_r (_REENT, s, ptr, base); |
} |
|
#endif |
/seed48.c
0,0 → 1,43
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
unsigned short * |
_DEFUN (_seed48_r, (r, xseed), |
struct _reent *r _AND |
unsigned short xseed[3]) |
{ |
static unsigned short sseed[3]; |
|
sseed[0] = __rand48_seed[0]; |
sseed[1] = __rand48_seed[1]; |
sseed[2] = __rand48_seed[2]; |
__rand48_seed[0] = xseed[0]; |
__rand48_seed[1] = xseed[1]; |
__rand48_seed[2] = xseed[2]; |
__rand48_mult[0] = _RAND48_MULT_0; |
__rand48_mult[1] = _RAND48_MULT_1; |
__rand48_mult[2] = _RAND48_MULT_2; |
__rand48_add = _RAND48_ADD; |
return sseed; |
} |
|
#ifndef _REENT_ONLY |
unsigned short * |
_DEFUN (seed48, (xseed), |
unsigned short xseed[3]) |
{ |
return _seed48_r (_REENT, xseed); |
} |
#endif /* !_REENT_ONLY */ |
/ldiv.c
0,0 → 1,109
/* |
FUNCTION |
<<ldiv>>---divide two long integers |
|
INDEX |
ldiv |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
ldiv_t ldiv(long <[n]>, long <[d]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
ldiv_t ldiv(<[n]>, <[d]>) |
long <[n]>, <[d]>; |
|
DESCRIPTION |
Divide |
@tex |
$n/d$, |
@end tex |
@ifinfo |
<[n]>/<[d]>, |
@end ifinfo |
returning quotient and remainder as two long integers in a structure <<ldiv_t>>. |
|
RETURNS |
The result is represented with the structure |
|
. typedef struct |
. { |
. long quot; |
. long rem; |
. } ldiv_t; |
|
where the <<quot>> field represents the quotient, and <<rem>> the |
remainder. For nonzero <[d]>, if `<<<[r]> = ldiv(<[n]>,<[d]>);>>' then |
<[n]> equals `<<<[r]>.rem + <[d]>*<[r]>.quot>>'. |
|
To divide <<int>> rather than <<long>> values, use the similar |
function <<div>>. |
|
PORTABILITY |
<<ldiv>> is ANSI. |
|
No supporting OS subroutines are required. |
*/ |
|
|
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* This code is derived from software contributed to Berkeley by |
* Chris Torek. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#include <_ansi.h> |
#include <stdlib.h> /* ldiv_t */ |
|
ldiv_t |
_DEFUN (ldiv, (num, denom), |
long num _AND |
long denom) |
{ |
ldiv_t r; |
|
/* see div.c for comments */ |
|
r.quot = num / denom; |
r.rem = num % denom; |
if (num >= 0 && r.rem < 0) { |
++r.quot; |
r.rem -= denom; |
} |
else if (num < 0 && r.rem > 0) { |
--r.quot; |
r.rem += denom; |
} |
return (r); |
} |
/atoff.c
0,0 → 1,9
#include <stdlib.h> |
#include <_ansi.h> |
|
float |
_DEFUN (atoff, (s), |
_CONST char *s) |
{ |
return strtodf (s, NULL); |
} |
/stdlib.tex
0,0 → 1,134
@node Stdlib |
@chapter Standard Utility Functions (@file{stdlib.h}) |
|
This chapter groups utility functions useful in a variety of programs. |
The corresponding declarations are in the header file @file{stdlib.h}. |
|
@menu |
* abort:: Abnormal termination of a program |
* abs:: Integer absolute value (magnitude) |
* assert:: Macro for Debugging Diagnostics |
* atexit:: Request execution of functions at program exit |
* atof:: String to double or float |
* atoi:: String to integer |
* bsearch:: Binary search |
* calloc:: Allocate space for arrays |
* div:: Divide two integers |
* ecvtbuf:: Double or float to string of digits |
* ecvt:: Double or float to string of digits (malloc result) |
* __env_lock:: Lock environment list for getenv and setenv |
* gvcvt:: Format double or float as string |
* exit:: End program execution |
* getenv:: Look up environment variable |
* labs:: Long integer absolute value (magnitude) |
* ldiv:: Divide two long integers |
* malloc:: Allocate and manage memory (malloc, realloc, free) |
* mallinfo:: Get information about allocated memory |
* __malloc_lock:: Lock memory pool for malloc and free |
* mbstowcs:: Minimal multibyte string to wide string converter |
* mblen:: Minimal multibyte length |
* mbtowc:: Minimal multibyte to wide character converter |
* qsort:: Sort an array |
* rand:: Pseudo-random numbers |
* rand48:: Uniformaly distributed pseudo-random numbers |
* strtod:: String to double or float |
* strtol:: String to long |
* strtoul:: String to unsigned long |
* system:: Execute command string |
* wcstombs:: Minimal wide string to multibyte string converter |
* wctomb:: Minimal wide character to multibyte converter |
@end menu |
|
@page |
@include stdlib/abort.def |
|
@page |
@include stdlib/abs.def |
|
@page |
@include stdlib/assert.def |
|
@page |
@include stdlib/atexit.def |
|
@page |
@include stdlib/atof.def |
|
@page |
@include stdlib/atoi.def |
|
@page |
@include stdlib/bsearch.def |
|
@page |
@include stdlib/calloc.def |
|
@page |
@include stdlib/div.def |
|
@page |
@include stdlib/efgcvt.def |
|
@page |
@include stdlib/ecvtbuf.def |
|
@page |
@include stdlib/envlock.def |
|
@page |
@include stdlib/exit.def |
|
@page |
@include stdlib/getenv.def |
|
@page |
@include stdlib/labs.def |
|
@page |
@include stdlib/ldiv.def |
|
@page |
@include stdlib/malloc.def |
|
@page |
@include stdlib/mstats.def |
|
@page |
@include stdlib/mlock.def |
|
@page |
@include stdlib/mblen.def |
|
@page |
@include stdlib/mbstowcs.def |
|
@page |
@include stdlib/mbtowc.def |
|
@page |
@include stdlib/qsort.def |
|
@page |
@include stdlib/rand.def |
|
@page |
@include stdlib/rand48.def |
|
@page |
@include stdlib/strtod.def |
|
@page |
@include stdlib/strtol.def |
|
@page |
@include stdlib/strtoul.def |
|
@page |
@include stdlib/system.def |
|
@page |
@include stdlib/wcstombs.def |
|
@page |
@include stdlib/wctomb.def |
|
/envlock.c
0,0 → 1,51
/* |
FUNCTION |
<<__env_lock>>, <<__env_unlock>>--lock environ variable |
|
INDEX |
__env_lock |
INDEX |
__env_unlock |
|
ANSI_SYNOPSIS |
#include "envlock.h" |
void __env_lock (struct _reent *<[reent]>); |
void __env_unlock (struct _reent *<[reent]>); |
|
TRAD_SYNOPSIS |
void __env_lock(<[reent]>) |
struct _reent *<[reent]>; |
|
void __env_unlock(<[reent]>) |
struct _reent *<[reent]>; |
|
DESCRIPTION |
The <<setenv>> family of routines call these functions when they need |
to modify the environ variable. The version of these routines supplied |
in the library does not do anything. If multiple threads of execution |
can call <<setenv>>, or if <<setenv>> can be called reentrantly, then |
you need to define your own versions of these functions in order to |
safely lock the memory pool during a call. If you do not, the memory |
pool may become corrupted. |
|
A call to <<setenv>> may call <<__env_lock>> recursively; that is, |
the sequence of calls may go <<__env_lock>>, <<__env_lock>>, |
<<__env_unlock>>, <<__env_unlock>>. Any implementation of these |
routines must be careful to avoid causing a thread to wait for a lock |
that it already holds. |
*/ |
|
#include "envlock.h" |
|
|
void |
__env_lock (ptr) |
struct _reent *ptr; |
{ |
} |
|
void |
__env_unlock (ptr) |
struct _reent *ptr; |
{ |
} |
/putenv_r.c
0,0 → 1,57
/* This file may have been modified by DJ Delorie (Jan 1991). If so, |
** these modifications are Copyright (C) 1991 DJ Delorie |
*/ |
|
/*- |
* Copyright (c) 1988 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that: (1) source distributions retain this entire copyright |
* notice and comment, and (2) distributions including binaries display |
* the following acknowledgement: ``This product includes software |
* developed by the University of California, Berkeley and its contributors'' |
* in the documentation or other materials provided with the distribution |
* and in all advertising materials mentioning features or use of this |
* software. Neither the name of the University nor the names of its |
* contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
#include <reent.h> |
#include <stdlib.h> |
#include <string.h> |
|
#include "envlock.h" |
|
/* _putenv_r - reentrant version of putenv that either adds |
or replaces the environment variable "name" |
with "value" which is specified by str as "name=value". */ |
int |
_DEFUN (_putenv_r, (reent_ptr, str), |
struct _reent *reent_ptr _AND |
_CONST char *str) |
{ |
register char *p, *equal; |
int rval; |
|
p = _strdup_r (reent_ptr, str); |
|
if (!p) |
return 1; |
|
if (!(equal = index (p, '='))) |
{ |
(void) _free_r (reent_ptr, p); |
return 1; |
} |
|
*equal = '\0'; |
rval = _setenv_r (reent_ptr, p, equal + 1, 1); |
(void) _free_r (reent_ptr, p); |
|
return rval; |
} |
/strtoll.c
0,0 → 1,138
/* |
FUNCTION |
<<strtoll>>---string to long long |
|
INDEX |
strtoll |
INDEX |
_strtoll_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
long long strtoll(const char *<[s]>, char **<[ptr]>,int <[base]>); |
|
long long _strtoll_r(void *<[reent]>, |
const char *<[s]>, char **<[ptr]>,int <[base]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
long strtoll (<[s]>, <[ptr]>, <[base]>) |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
long _strtoll_r (<[reent]>, <[s]>, <[ptr]>, <[base]>) |
char *<[reent]>; |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
DESCRIPTION |
The function <<strtoll>> converts the string <<*<[s]>>> to |
a <<long long>>. First, it breaks down the string into three parts: |
leading whitespace, which is ignored; a subject string consisting |
of characters resembling an integer in the radix specified by <[base]>; |
and a trailing portion consisting of zero or more unparseable characters, |
and always including the terminating null character. Then, it attempts |
to convert the subject string into a <<long long>> and returns the |
result. |
|
If the value of <[base]> is 0, the subject string is expected to look |
like a normal C integer constant: an optional sign, a possible `<<0x>>' |
indicating a hexadecimal base, and a number. If <[base]> is between |
2 and 36, the expected form of the subject is a sequence of letters |
and digits representing an integer in the radix specified by <[base]>, |
with an optional plus or minus sign. The letters <<a>>--<<z>> (or, |
equivalently, <<A>>--<<Z>>) are used to signify values from 10 to 35; |
only letters whose ascribed values are less than <[base]> are |
permitted. If <[base]> is 16, a leading <<0x>> is permitted. |
|
The subject sequence is the longest initial sequence of the input |
string that has the expected form, starting with the first |
non-whitespace character. If the string is empty or consists entirely |
of whitespace, or if the first non-whitespace character is not a |
permissible letter or digit, the subject string is empty. |
|
If the subject string is acceptable, and the value of <[base]> is zero, |
<<strtoll>> attempts to determine the radix from the input string. A |
string with a leading <<0x>> is treated as a hexadecimal value; a string with |
a leading 0 and no <<x>> is treated as octal; all other strings are |
treated as decimal. If <[base]> is between 2 and 36, it is used as the |
conversion radix, as described above. If the subject string begins with |
a minus sign, the value is negated. Finally, a pointer to the first |
character past the converted subject string is stored in <[ptr]>, if |
<[ptr]> is not <<NULL>>. |
|
If the subject string is empty (or not in acceptable form), no conversion |
is performed and the value of <[s]> is stored in <[ptr]> (if <[ptr]> is |
not <<NULL>>). |
|
The alternate function <<_strtoll_r>> is a reentrant version. The |
extra argument <[reent]> is a pointer to a reentrancy structure. |
|
RETURNS |
<<strtoll>> returns the converted value, if any. If no conversion was |
made, 0 is returned. |
|
<<strtoll>> returns <<LONG_LONG_MAX>> or <<LONG_LONG_MIN>> if the magnitude of |
the converted value is too large, and sets <<errno>> to <<ERANGE>>. |
|
PORTABILITY |
<<strtoll>> is nonstandard. |
|
No supporting OS subroutines are required. |
*/ |
|
/*- |
* Copyright (c) 1990 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
|
#include <_ansi.h> |
#include <limits.h> |
#include <ctype.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <reent.h> |
|
#ifndef _REENT_ONLY |
|
long long |
_DEFUN (strtoll, (s, ptr, base), |
_CONST char *s _AND |
char **ptr _AND |
int base) |
{ |
return _strtoll_r (_REENT, s, ptr, base); |
} |
|
#endif |
/envlock.h
0,0 → 1,15
/* envlock.h -- header file for env routines. */ |
|
#ifndef _INCLUDE_ENVLOCK_H_ |
#define _INCLUDE_ENVLOCK_H_ |
|
#include <_ansi.h> |
#include <sys/reent.h> |
|
#define ENV_LOCK __env_lock(reent_ptr) |
#define ENV_UNLOCK __env_unlock(reent_ptr) |
|
void _EXFUN(__env_lock,(struct _reent *reent)); |
void _EXFUN(__env_unlock,(struct _reent *reent)); |
|
#endif /* _INCLUDE_ENVLOCK_H_ */ |
/eprintf.c
0,0 → 1,26
/* This is an implementation of the __eprintf function which is |
compatible with the assert.h which is distributed with gcc. |
|
This function is provided because in some cases libgcc.a will not |
provide __eprintf. This will happen if inhibit_libc is defined, |
which is done because at the time that libgcc2.c is compiled, the |
correct <stdio.h> may not be available. newlib provides its own |
copy of assert.h, which calls __assert, not __eprintf. However, in |
some cases you may accidentally wind up compiling with the gcc |
assert.h. In such a case, this __eprintf will be used if there |
does not happen to be one in libgcc2.c. */ |
|
#include <stdlib.h> |
#include <stdio.h> |
|
void |
__eprintf (format, file, line, expression) |
const char *format; |
const char *file; |
unsigned int line; |
const char *expression; |
{ |
(void) fiprintf (stderr, format, file, line, expression); |
abort (); |
/*NOTREACHED*/ |
} |
/qsort.c
0,0 → 1,222
/* |
FUNCTION |
<<qsort>>---sort an array |
|
INDEX |
qsort |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
void qsort(void *<[base]>, size_t <[nmemb]>, size_t <[size]>, |
int (*<[compar]>)(const void *, const void *) ); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
qsort(<[base]>, <[nmemb]>, <[size]>, <[compar]> ) |
char *<[base]>; |
size_t <[nmemb]>; |
size_t <[size]>; |
int (*<[compar]>)(); |
|
DESCRIPTION |
<<qsort>> sorts an array (beginning at <[base]>) of <[nmemb]> objects. |
<[size]> describes the size of each element of the array. |
|
You must supply a pointer to a comparison function, using the argument |
shown as <[compar]>. (This permits sorting objects of unknown |
properties.) Define the comparison function to accept two arguments, |
each a pointer to an element of the array starting at <[base]>. The |
result of <<(*<[compar]>)>> must be negative if the first argument is |
less than the second, zero if the two arguments match, and positive if |
the first argument is greater than the second (where ``less than'' and |
``greater than'' refer to whatever arbitrary ordering is appropriate). |
|
The array is sorted in place; that is, when <<qsort>> returns, the |
array elements beginning at <[base]> have been reordered. |
|
RETURNS |
<<qsort>> does not return a result. |
|
PORTABILITY |
<<qsort>> is required by ANSI (without specifying the sorting algorithm). |
*/ |
|
/*- |
* Copyright (c) 1992, 1993 |
* The Regents of the University of California. All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#include <_ansi.h> |
#include <stdlib.h> |
|
#ifndef __GNUC__ |
#define inline |
#endif |
|
static inline char *med3 _PARAMS((char *, char *, char *, int (*)())); |
static inline void swapfunc _PARAMS((char *, char *, int, int)); |
|
#define min(a, b) (a) < (b) ? a : b |
|
/* |
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". |
*/ |
#define swapcode(TYPE, parmi, parmj, n) { \ |
long i = (n) / sizeof (TYPE); \ |
register TYPE *pi = (TYPE *) (parmi); \ |
register TYPE *pj = (TYPE *) (parmj); \ |
do { \ |
register TYPE t = *pi; \ |
*pi++ = *pj; \ |
*pj++ = t; \ |
} while (--i > 0); \ |
} |
|
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ |
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; |
|
static inline void |
_DEFUN(swapfunc, (a, b, n, swaptype), |
char *a _AND |
char *b _AND |
int n _AND |
int swaptype) |
{ |
if(swaptype <= 1) |
swapcode(long, a, b, n) |
else |
swapcode(char, a, b, n) |
} |
|
#define swap(a, b) \ |
if (swaptype == 0) { \ |
long t = *(long *)(a); \ |
*(long *)(a) = *(long *)(b); \ |
*(long *)(b) = t; \ |
} else \ |
swapfunc(a, b, es, swaptype) |
|
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) |
|
static inline char * |
_DEFUN(med3, (a, b, c, cmp), |
char *a _AND |
char *b _AND |
char *c _AND |
int (*cmp)()) |
{ |
return cmp(a, b) < 0 ? |
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) |
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); |
} |
|
void |
_DEFUN(qsort, (a, n, es, cmp), |
void *a _AND |
size_t n _AND |
size_t es _AND |
int (*cmp)()) |
{ |
char *pa, *pb, *pc, *pd, *pl, *pm, *pn; |
int d, r, swaptype, swap_cnt; |
|
loop: SWAPINIT(a, es); |
swap_cnt = 0; |
if (n < 7) { |
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) |
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; |
pl -= es) |
swap(pl, pl - es); |
return; |
} |
pm = (char *) a + (n / 2) * es; |
if (n > 7) { |
pl = a; |
pn = (char *) a + (n - 1) * es; |
if (n > 40) { |
d = (n / 8) * es; |
pl = med3(pl, pl + d, pl + 2 * d, cmp); |
pm = med3(pm - d, pm, pm + d, cmp); |
pn = med3(pn - 2 * d, pn - d, pn, cmp); |
} |
pm = med3(pl, pm, pn, cmp); |
} |
swap(a, pm); |
pa = pb = (char *) a + es; |
|
pc = pd = (char *) a + (n - 1) * es; |
for (;;) { |
while (pb <= pc && (r = cmp(pb, a)) <= 0) { |
if (r == 0) { |
swap_cnt = 1; |
swap(pa, pb); |
pa += es; |
} |
pb += es; |
} |
while (pb <= pc && (r = cmp(pc, a)) >= 0) { |
if (r == 0) { |
swap_cnt = 1; |
swap(pc, pd); |
pd -= es; |
} |
pc -= es; |
} |
if (pb > pc) |
break; |
swap(pb, pc); |
swap_cnt = 1; |
pb += es; |
pc -= es; |
} |
if (swap_cnt == 0) { /* Switch to insertion sort */ |
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) |
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; |
pl -= es) |
swap(pl, pl - es); |
return; |
} |
|
pn = (char *) a + n * es; |
r = min(pa - (char *)a, pb - pa); |
vecswap(a, pb - r, r); |
r = min(pd - pc, pn - pd - es); |
vecswap(pb, pn - r, r); |
if ((r = pb - pa) > es) |
qsort(a, r / es, es, cmp); |
if ((r = pd - pc) > es) { |
/* Iterate rather than recurse to save stack space */ |
a = pn - r; |
n = r / es; |
goto loop; |
} |
/* qsort(pn - r, r / es, es, cmp);*/ |
} |
/lcong48.c
0,0 → 1,37
/* |
* Copyright (c) 1993 Martin Birgmeier |
* All rights reserved. |
* |
* You may redistribute unmodified or modified versions of this source |
* code provided that the above copyright notice and this and the |
* following conditions are retained. |
* |
* This software is provided ``as is'', and comes with no warranties |
* of any kind. I shall in no event be liable for anything that happens |
* to anyone/anything when using this software. |
*/ |
|
#include "rand48.h" |
|
_VOID |
_DEFUN (_lcong48_r, (r, p), |
struct _reent *r _AND |
unsigned short p[7]) |
{ |
__rand48_seed[0] = p[0]; |
__rand48_seed[1] = p[1]; |
__rand48_seed[2] = p[2]; |
__rand48_mult[0] = p[3]; |
__rand48_mult[1] = p[4]; |
__rand48_mult[2] = p[5]; |
__rand48_add = p[6]; |
} |
|
#ifndef _REENT_ONLY |
_VOID |
_DEFUN (lcong48, (p), |
unsigned short p[7]) |
{ |
_lcong48_r (_REENT, p); |
} |
#endif /* !_REENT_ONLY */ |
/strtod.c
0,0 → 1,731
/* |
FUNCTION |
<<strtod>>, <<strtodf>>---string to double or float |
|
INDEX |
strtod |
INDEX |
_strtod_r |
INDEX |
strtodf |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
double strtod(const char *<[str]>, char **<[tail]>); |
float strtodf(const char *<[str]>, char **<[tail]>); |
|
double _strtod_r(void *<[reent]>, |
const char *<[str]>, char **<[tail]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
double strtod(<[str]>,<[tail]>) |
char *<[str]>; |
char **<[tail]>; |
|
float strtodf(<[str]>,<[tail]>) |
char *<[str]>; |
char **<[tail]>; |
|
double _strtod_r(<[reent]>,<[str]>,<[tail]>) |
char *<[reent]>; |
char *<[str]>; |
char **<[tail]>; |
|
DESCRIPTION |
The function <<strtod>> parses the character string <[str]>, |
producing a substring which can be converted to a double |
value. The substring converted is the longest initial |
subsequence of <[str]>, beginning with the first |
non-whitespace character, that has the format: |
.[+|-]<[digits]>[.][<[digits]>][(e|E)[+|-]<[digits]>] |
The substring contains no characters if <[str]> is empty, consists |
entirely of whitespace, or if the first non-whitespace |
character is something other than <<+>>, <<->>, <<.>>, or a |
digit. If the substring is empty, no conversion is done, and |
the value of <[str]> is stored in <<*<[tail]>>>. Otherwise, |
the substring is converted, and a pointer to the final string |
(which will contain at least the terminating null character of |
<[str]>) is stored in <<*<[tail]>>>. If you want no |
assignment to <<*<[tail]>>>, pass a null pointer as <[tail]>. |
<<strtodf>> is identical to <<strtod>> except for its return type. |
|
This implementation returns the nearest machine number to the |
input decimal string. Ties are broken by using the IEEE |
round-even rule. |
|
The alternate function <<_strtod_r>> is a reentrant version. |
The extra argument <[reent]> is a pointer to a reentrancy structure. |
|
RETURNS |
<<strtod>> returns the converted substring value, if any. If |
no conversion could be performed, 0 is returned. If the |
correct value is out of the range of representable values, |
plus or minus <<HUGE_VAL>> is returned, and <<ERANGE>> is |
stored in errno. If the correct value would cause underflow, 0 |
is returned and <<ERANGE>> is stored in errno. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
/**************************************************************** |
* |
* The author of this software is David M. Gay. |
* |
* Copyright (c) 1991 by AT&T. |
* |
* Permission to use, copy, modify, and distribute this software for any |
* purpose without fee is hereby granted, provided that this entire notice |
* is included in all copies of any software which is or includes a copy |
* or modification of this software and in all copies of the supporting |
* documentation for such software. |
* |
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED |
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY |
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY |
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. |
* |
***************************************************************/ |
|
/* Please send bug reports to |
David M. Gay |
AT&T Bell Laboratories, Room 2C-463 |
600 Mountain Avenue |
Murray Hill, NJ 07974-2070 |
U.S.A. |
dmg@research.att.com or research!dmg |
*/ |
|
#include <_ansi.h> |
#include <reent.h> |
#include <string.h> |
#include "mprec.h" |
|
double |
_DEFUN (_strtod_r, (ptr, s00, se), |
struct _reent *ptr _AND |
_CONST char *s00 _AND |
char **se) |
{ |
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e1, esign, i, j, |
k, nd, nd0, nf, nz, nz0, sign; |
long e; |
_CONST char *s, *s0, *s1; |
double aadj, aadj1, adj; |
long L; |
unsigned long z; |
__ULong y; |
union double_union rv, rv0; |
|
_Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; |
sign = nz0 = nz = 0; |
rv.d = 0.; |
for (s = s00;; s++) |
switch (*s) |
{ |
case '-': |
sign = 1; |
/* no break */ |
case '+': |
if (*++s) |
goto break2; |
/* no break */ |
case 0: |
s = s00; |
goto ret; |
case '\t': |
case '\n': |
case '\v': |
case '\f': |
case '\r': |
case ' ': |
continue; |
default: |
goto break2; |
} |
break2: |
if (*s == '0') |
{ |
nz0 = 1; |
while (*++s == '0'); |
if (!*s) |
goto ret; |
} |
s0 = s; |
y = z = 0; |
for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) |
if (nd < 9) |
y = 10 * y + c - '0'; |
else if (nd < 16) |
z = 10 * z + c - '0'; |
nd0 = nd; |
if (c == '.') |
{ |
c = *++s; |
if (!nd) |
{ |
for (; c == '0'; c = *++s) |
nz++; |
if (c > '0' && c <= '9') |
{ |
s0 = s; |
nf += nz; |
nz = 0; |
goto have_dig; |
} |
goto dig_done; |
} |
for (; c >= '0' && c <= '9'; c = *++s) |
{ |
have_dig: |
nz++; |
if (c -= '0') |
{ |
nf += nz; |
for (i = 1; i < nz; i++) |
if (nd++ < 9) |
y *= 10; |
else if (nd <= DBL_DIG + 1) |
z *= 10; |
if (nd++ < 9) |
y = 10 * y + c; |
else if (nd <= DBL_DIG + 1) |
z = 10 * z + c; |
nz = 0; |
} |
} |
} |
dig_done: |
e = 0; |
if (c == 'e' || c == 'E') |
{ |
if (!nd && !nz && !nz0) |
{ |
s = s00; |
goto ret; |
} |
s00 = s; |
esign = 0; |
switch (c = *++s) |
{ |
case '-': |
esign = 1; |
case '+': |
c = *++s; |
} |
if (c >= '0' && c <= '9') |
{ |
while (c == '0') |
c = *++s; |
if (c > '0' && c <= '9') |
{ |
e = c - '0'; |
s1 = s; |
while ((c = *++s) >= '0' && c <= '9') |
e = 10 * e + c - '0'; |
if (s - s1 > 8) |
/* Avoid confusion from exponents |
* so large that e might overflow. |
*/ |
e = 9999999L; |
if (esign) |
e = -e; |
} |
else |
e = 0; |
} |
else |
s = s00; |
} |
if (!nd) |
{ |
if (!nz && !nz0) |
s = s00; |
goto ret; |
} |
e1 = e -= nf; |
|
/* Now we have nd0 digits, starting at s0, followed by a |
* decimal point, followed by nd-nd0 digits. The number we're |
* after is the integer represented by those digits times |
* 10**e */ |
|
if (!nd0) |
nd0 = nd; |
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; |
rv.d = y; |
if (k > 9) |
rv.d = tens[k - 9] * rv.d + z; |
bd0 = 0; |
if (nd <= DBL_DIG |
#ifndef RND_PRODQUOT |
&& FLT_ROUNDS == 1 |
#endif |
) |
{ |
if (!e) |
goto ret; |
if (e > 0) |
{ |
if (e <= Ten_pmax) |
{ |
#ifdef VAX |
goto vax_ovfl_check; |
#else |
/* rv.d = */ rounded_product (rv.d, tens[e]); |
goto ret; |
#endif |
} |
i = DBL_DIG - nd; |
if (e <= Ten_pmax + i) |
{ |
/* A fancier test would sometimes let us do |
* this for larger i values. |
*/ |
e -= i; |
rv.d *= tens[i]; |
#ifdef VAX |
/* VAX exponent range is so narrow we must |
* worry about overflow here... |
*/ |
vax_ovfl_check: |
word0 (rv) -= P * Exp_msk1; |
/* rv.d = */ rounded_product (rv.d, tens[e]); |
if ((word0 (rv) & Exp_mask) |
> Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) |
goto ovfl; |
word0 (rv) += P * Exp_msk1; |
#else |
/* rv.d = */ rounded_product (rv.d, tens[e]); |
#endif |
goto ret; |
} |
} |
#ifndef Inaccurate_Divide |
else if (e >= -Ten_pmax) |
{ |
/* rv.d = */ rounded_quotient (rv.d, tens[-e]); |
goto ret; |
} |
#endif |
} |
e1 += nd - k; |
|
/* Get starting approximation = rv.d * 10**e1 */ |
|
if (e1 > 0) |
{ |
if ((i = e1 & 15) != 0) |
rv.d *= tens[i]; |
if (e1 &= ~15) |
{ |
if (e1 > DBL_MAX_10_EXP) |
{ |
ovfl: |
ptr->_errno = ERANGE; |
#ifdef _HAVE_STDC |
rv.d = HUGE_VAL; |
#else |
/* Can't trust HUGE_VAL */ |
#ifdef IEEE_Arith |
word0 (rv) = Exp_mask; |
#ifndef _DOUBLE_IS_32BITS |
word1 (rv) = 0; |
#endif |
#else |
word0 (rv) = Big0; |
#ifndef _DOUBLE_IS_32BITS |
word1 (rv) = Big1; |
#endif |
#endif |
#endif |
if (bd0) |
goto retfree; |
goto ret; |
} |
if (e1 >>= 4) |
{ |
for (j = 0; e1 > 1; j++, e1 >>= 1) |
if (e1 & 1) |
rv.d *= bigtens[j]; |
/* The last multiplication could overflow. */ |
word0 (rv) -= P * Exp_msk1; |
rv.d *= bigtens[j]; |
if ((z = word0 (rv) & Exp_mask) |
> Exp_msk1 * (DBL_MAX_EXP + Bias - P)) |
goto ovfl; |
if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) |
{ |
/* set to largest number */ |
/* (Can't trust DBL_MAX) */ |
word0 (rv) = Big0; |
#ifndef _DOUBLE_IS_32BITS |
word1 (rv) = Big1; |
#endif |
} |
else |
word0 (rv) += P * Exp_msk1; |
} |
|
} |
} |
else if (e1 < 0) |
{ |
e1 = -e1; |
if ((i = e1 & 15) != 0) |
rv.d /= tens[i]; |
if (e1 &= ~15) |
{ |
e1 >>= 4; |
if (e1 >= 1 << n_bigtens) |
goto undfl; |
for (j = 0; e1 > 1; j++, e1 >>= 1) |
if (e1 & 1) |
rv.d *= tinytens[j]; |
/* The last multiplication could underflow. */ |
rv0.d = rv.d; |
rv.d *= tinytens[j]; |
if (!rv.d) |
{ |
rv.d = 2. * rv0.d; |
rv.d *= tinytens[j]; |
if (!rv.d) |
{ |
undfl: |
rv.d = 0.; |
ptr->_errno = ERANGE; |
if (bd0) |
goto retfree; |
goto ret; |
} |
#ifndef _DOUBLE_IS_32BITS |
word0 (rv) = Tiny0; |
word1 (rv) = Tiny1; |
#else |
word0 (rv) = Tiny1; |
#endif |
/* The refinement below will clean |
* this approximation up. |
*/ |
} |
} |
} |
|
/* Now the hard part -- adjusting rv to the correct value.*/ |
|
/* Put digits into bd: true value = bd * 10^e */ |
|
bd0 = s2b (ptr, s0, nd0, nd, y); |
|
for (;;) |
{ |
bd = Balloc (ptr, bd0->_k); |
Bcopy (bd, bd0); |
bb = d2b (ptr, rv.d, &bbe, &bbbits); /* rv.d = bb * 2^bbe */ |
bs = i2b (ptr, 1); |
|
if (e >= 0) |
{ |
bb2 = bb5 = 0; |
bd2 = bd5 = e; |
} |
else |
{ |
bb2 = bb5 = -e; |
bd2 = bd5 = 0; |
} |
if (bbe >= 0) |
bb2 += bbe; |
else |
bd2 -= bbe; |
bs2 = bb2; |
#ifdef Sudden_Underflow |
#ifdef IBM |
j = 1 + 4 * P - 3 - bbbits + ((bbe + bbbits - 1) & 3); |
#else |
j = P + 1 - bbbits; |
#endif |
#else |
i = bbe + bbbits - 1; /* logb(rv.d) */ |
if (i < Emin) /* denormal */ |
j = bbe + (P - Emin); |
else |
j = P + 1 - bbbits; |
#endif |
bb2 += j; |
bd2 += j; |
i = bb2 < bd2 ? bb2 : bd2; |
if (i > bs2) |
i = bs2; |
if (i > 0) |
{ |
bb2 -= i; |
bd2 -= i; |
bs2 -= i; |
} |
if (bb5 > 0) |
{ |
bs = pow5mult (ptr, bs, bb5); |
bb1 = mult (ptr, bs, bb); |
Bfree (ptr, bb); |
bb = bb1; |
} |
if (bb2 > 0) |
bb = lshift (ptr, bb, bb2); |
if (bd5 > 0) |
bd = pow5mult (ptr, bd, bd5); |
if (bd2 > 0) |
bd = lshift (ptr, bd, bd2); |
if (bs2 > 0) |
bs = lshift (ptr, bs, bs2); |
delta = diff (ptr, bb, bd); |
dsign = delta->_sign; |
delta->_sign = 0; |
i = cmp (delta, bs); |
if (i < 0) |
{ |
/* Error is less than half an ulp -- check for |
* special case of mantissa a power of two. |
*/ |
if (dsign || word1 (rv) || word0 (rv) & Bndry_mask) |
break; |
delta = lshift (ptr, delta, Log2P); |
if (cmp (delta, bs) > 0) |
goto drop_down; |
break; |
} |
if (i == 0) |
{ |
/* exactly half-way between */ |
if (dsign) |
{ |
if ((word0 (rv) & Bndry_mask1) == Bndry_mask1 |
&& word1 (rv) == 0xffffffff) |
{ |
/*boundary case -- increment exponent*/ |
word0 (rv) = (word0 (rv) & Exp_mask) |
+ Exp_msk1 |
#ifdef IBM |
| Exp_msk1 >> 4 |
#endif |
; |
#ifndef _DOUBLE_IS_32BITS |
word1 (rv) = 0; |
#endif |
break; |
} |
} |
else if (!(word0 (rv) & Bndry_mask) && !word1 (rv)) |
{ |
drop_down: |
/* boundary case -- decrement exponent */ |
#ifdef Sudden_Underflow |
L = word0 (rv) & Exp_mask; |
#ifdef IBM |
if (L < Exp_msk1) |
#else |
if (L <= Exp_msk1) |
#endif |
goto undfl; |
L -= Exp_msk1; |
#else |
L = (word0 (rv) & Exp_mask) - Exp_msk1; |
#endif |
word0 (rv) = L | Bndry_mask1; |
#ifndef _DOUBLE_IS_32BITS |
word1 (rv) = 0xffffffff; |
#endif |
#ifdef IBM |
goto cont; |
#else |
break; |
#endif |
} |
#ifndef ROUND_BIASED |
if (!(word1 (rv) & LSB)) |
break; |
#endif |
if (dsign) |
rv.d += ulp (rv.d); |
#ifndef ROUND_BIASED |
else |
{ |
rv.d -= ulp (rv.d); |
#ifndef Sudden_Underflow |
if (!rv.d) |
goto undfl; |
#endif |
} |
#endif |
break; |
} |
if ((aadj = ratio (delta, bs)) <= 2.) |
{ |
if (dsign) |
aadj = aadj1 = 1.; |
else if (word1 (rv) || word0 (rv) & Bndry_mask) |
{ |
#ifndef Sudden_Underflow |
if (word1 (rv) == Tiny1 && !word0 (rv)) |
goto undfl; |
#endif |
aadj = 1.; |
aadj1 = -1.; |
} |
else |
{ |
/* special case -- power of FLT_RADIX to be */ |
/* rounded down... */ |
|
if (aadj < 2. / FLT_RADIX) |
aadj = 1. / FLT_RADIX; |
else |
aadj *= 0.5; |
aadj1 = -aadj; |
} |
} |
else |
{ |
aadj *= 0.5; |
aadj1 = dsign ? aadj : -aadj; |
#ifdef Check_FLT_ROUNDS |
switch (FLT_ROUNDS) |
{ |
case 2: /* towards +infinity */ |
aadj1 -= 0.5; |
break; |
case 0: /* towards 0 */ |
case 3: /* towards -infinity */ |
aadj1 += 0.5; |
} |
#else |
if (FLT_ROUNDS == 0) |
aadj1 += 0.5; |
#endif |
} |
y = word0 (rv) & Exp_mask; |
|
/* Check for overflow */ |
|
if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) |
{ |
rv0.d = rv.d; |
word0 (rv) -= P * Exp_msk1; |
adj = aadj1 * ulp (rv.d); |
rv.d += adj; |
if ((word0 (rv) & Exp_mask) >= |
Exp_msk1 * (DBL_MAX_EXP + Bias - P)) |
{ |
if (word0 (rv0) == Big0 && word1 (rv0) == Big1) |
goto ovfl; |
#ifdef _DOUBLE_IS_32BITS |
word0 (rv) = Big1; |
#else |
word0 (rv) = Big0; |
word1 (rv) = Big1; |
#endif |
goto cont; |
} |
else |
word0 (rv) += P * Exp_msk1; |
} |
else |
{ |
#ifdef Sudden_Underflow |
if ((word0 (rv) & Exp_mask) <= P * Exp_msk1) |
{ |
rv0.d = rv.d; |
word0 (rv) += P * Exp_msk1; |
adj = aadj1 * ulp (rv.d); |
rv.d += adj; |
#ifdef IBM |
if ((word0 (rv) & Exp_mask) < P * Exp_msk1) |
#else |
if ((word0 (rv) & Exp_mask) <= P * Exp_msk1) |
#endif |
{ |
if (word0 (rv0) == Tiny0 |
&& word1 (rv0) == Tiny1) |
goto undfl; |
word0 (rv) = Tiny0; |
word1 (rv) = Tiny1; |
goto cont; |
} |
else |
word0 (rv) -= P * Exp_msk1; |
} |
else |
{ |
adj = aadj1 * ulp (rv.d); |
rv.d += adj; |
} |
#else |
/* Compute adj so that the IEEE rounding rules will |
* correctly round rv.d + adj in some half-way cases. |
* If rv.d * ulp(rv.d) is denormalized (i.e., |
* y <= (P-1)*Exp_msk1), we must adjust aadj to avoid |
* trouble from bits lost to denormalization; |
* example: 1.2e-307 . |
*/ |
if (y <= (P - 1) * Exp_msk1 && aadj >= 1.) |
{ |
aadj1 = (double) (int) (aadj + 0.5); |
if (!dsign) |
aadj1 = -aadj1; |
} |
adj = aadj1 * ulp (rv.d); |
rv.d += adj; |
#endif |
} |
z = word0 (rv) & Exp_mask; |
if (y == z) |
{ |
/* Can we stop now? */ |
L = aadj; |
aadj -= L; |
/* The tolerances below are conservative. */ |
if (dsign || word1 (rv) || word0 (rv) & Bndry_mask) |
{ |
if (aadj < .4999999 || aadj > .5000001) |
break; |
} |
else if (aadj < .4999999 / FLT_RADIX) |
break; |
} |
cont: |
Bfree (ptr, bb); |
Bfree (ptr, bd); |
Bfree (ptr, bs); |
Bfree (ptr, delta); |
} |
retfree: |
Bfree (ptr, bb); |
Bfree (ptr, bd); |
Bfree (ptr, bs); |
Bfree (ptr, bd0); |
Bfree (ptr, delta); |
ret: |
if (se) |
*se = (char *) s; |
return sign ? -rv.d : rv.d; |
} |
|
#ifndef NO_REENT |
|
double |
_DEFUN (strtod, (s00, se), |
_CONST char *s00 _AND char **se) |
{ |
return _strtod_r (_REENT, s00, se); |
} |
|
float |
_DEFUN (strtodf, (s00, se), |
_CONST char *s00 _AND |
char **se) |
{ |
return _strtod_r (_REENT, s00, se); |
} |
|
#endif |
/putenv.c
0,0 → 1,32
/*- |
* Copyright (c) 1988 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that: (1) source distributions retain this entire copyright |
* notice and comment, and (2) distributions including binaries display |
* the following acknowledgement: ``This product includes software |
* developed by the University of California, Berkeley and its contributors'' |
* in the documentation or other materials provided with the distribution |
* and in all advertising materials mentioning features or use of this |
* software. Neither the name of the University nor the names of its |
* contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
#include <string.h> |
|
int |
_DEFUN (putenv, (str), |
_CONST char *str) |
{ |
return _putenv_r (_REENT, str); |
} |
|
#endif /* !_REENT_ONLY */ |
/labs.c
0,0 → 1,49
/* |
FUNCTION |
<<labs>>---long integer absolute value |
|
INDEX |
labs |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
long labs(long <[i]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
long labs(<[i]>) |
long <[i]>; |
|
DESCRIPTION |
<<labs>> returns |
@tex |
$|x|$, |
@end tex |
the absolute value of <[i]> (also called the magnitude |
of <[i]>). That is, if <[i]> is negative, the result is the opposite |
of <[i]>, but if <[i]> is nonnegative the result is <[i]>. |
|
The similar function <<abs>> uses and returns <<int>> rather than |
<<long>> values. |
|
RETURNS |
The result is a nonnegative long integer. |
|
PORTABILITY |
<<labs>> is ANSI. |
|
No supporting OS subroutine calls are required. |
*/ |
|
#include <stdlib.h> |
|
long |
_DEFUN (labs, (x), |
long x) |
{ |
if (x < 0) |
{ |
x = -x; |
} |
return x; |
} |
/div.c
0,0 → 1,132
/* |
FUNCTION |
<<div>>---divide two integers |
|
INDEX |
div |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
div_t div(int <[n]>, int <[d]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
div_t div(<[n]>, <[d]>) |
int <[n]>, <[d]>; |
|
DESCRIPTION |
Divide |
@tex |
$n/d$, |
@end tex |
@ifinfo |
<[n]>/<[d]>, |
@end ifinfo |
returning quotient and remainder as two integers in a structure <<div_t>>. |
|
RETURNS |
The result is represented with the structure |
|
. typedef struct |
. { |
. int quot; |
. int rem; |
. } div_t; |
|
where the <<quot>> field represents the quotient, and <<rem>> the |
remainder. For nonzero <[d]>, if `<<<[r]> = div(<[n]>,<[d]>);>>' then |
<[n]> equals `<<<[r]>.rem + <[d]>*<[r]>.quot>>'. |
|
To divide <<long>> rather than <<int>> values, use the similar |
function <<ldiv>>. |
|
PORTABILITY |
<<div>> is ANSI. |
|
No supporting OS subroutines are required. |
*/ |
|
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* This code is derived from software contributed to Berkeley by |
* Chris Torek. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
#include <_ansi.h> |
#include <stdlib.h> /* div_t */ |
|
div_t |
_DEFUN (div, (num, denom), |
int num _AND |
int denom) |
{ |
div_t r; |
|
r.quot = num / denom; |
r.rem = num % denom; |
/* |
* The ANSI standard says that |r.quot| <= |n/d|, where |
* n/d is to be computed in infinite precision. In other |
* words, we should always truncate the quotient towards |
* 0, never -infinity or +infinity. |
* |
* Machine division and remainer may work either way when |
* one or both of n or d is negative. If only one is |
* negative and r.quot has been truncated towards -inf, |
* r.rem will have the same sign as denom and the opposite |
* sign of num; if both are negative and r.quot has been |
* truncated towards -inf, r.rem will be positive (will |
* have the opposite sign of num). These are considered |
* `wrong'. |
* |
* If both are num and denom are positive, r will always |
* be positive. |
* |
* This all boils down to: |
* if num >= 0, but r.rem < 0, we got the wrong answer. |
* In that case, to get the right answer, add 1 to r.quot and |
* subtract denom from r.rem. |
* if num < 0, but r.rem > 0, we also have the wrong answer. |
* In this case, to get the right answer, subtract 1 from r.quot and |
* add denom to r.rem. |
*/ |
if (num >= 0 && r.rem < 0) { |
++r.quot; |
r.rem -= denom; |
} |
else if (num < 0 && r.rem > 0) { |
--r.quot; |
r.rem += denom; |
} |
return (r); |
} |
/rand.c
0,0 → 1,89
/* |
FUNCTION |
<<rand>>, <<srand>>---pseudo-random numbers |
|
INDEX |
rand |
INDEX |
srand |
INDEX |
rand_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int rand(void); |
void srand(unsigned int <[seed]>); |
int rand_r(unsigned int *<[seed]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int rand(); |
|
void srand(<[seed]>) |
unsigned int <[seed]>; |
|
void rand_r(<[seed]>) |
unsigned int *<[seed]>; |
|
|
DESCRIPTION |
<<rand>> returns a different integer each time it is called; each |
integer is chosen by an algorithm designed to be unpredictable, so |
that you can use <<rand>> when you require a random number. |
The algorithm depends on a static variable called the ``random seed''; |
starting with a given value of the random seed always produces the |
same sequence of numbers in successive calls to <<rand>>. |
|
You can set the random seed using <<srand>>; it does nothing beyond |
storing its argument in the static variable used by <<rand>>. You can |
exploit this to make the pseudo-random sequence less predictable, if |
you wish, by using some other unpredictable value (often the least |
significant parts of a time-varying value) as the random seed before |
beginning a sequence of calls to <<rand>>; or, if you wish to ensure |
(for example, while debugging) that successive runs of your program |
use the same ``random'' numbers, you can use <<srand>> to set the same |
random seed at the outset. |
|
RETURNS |
<<rand>> returns the next pseudo-random integer in sequence; it is a |
number between <<0>> and <<RAND_MAX>> (inclusive). |
|
<<srand>> does not return a result. |
|
NOTES |
<<rand>> and <<srand>> are unsafe for multi-thread applications. |
<<rand_r>> is MT-Safe and should be used instead. |
|
|
PORTABILITY |
<<rand>> is required by ANSI, but the algorithm for pseudo-random |
number generation is not specified; therefore, even if you use |
the same random seed, you cannot expect the same sequence of results |
on two different systems. |
|
<<rand>> requires no supporting OS subroutines. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
#include <reent.h> |
|
void |
_DEFUN (srand, (seed), unsigned int seed) |
{ |
_REENT->_new._reent._rand_next = seed; |
} |
|
int |
_DEFUN_VOID (rand) |
{ |
/* This multiplier was obtained from Knuth, D.E., "The Art of |
Computer Programming," Vol 2, Seminumerical Algorithms, Third |
Edition, Addison-Wesley, 1998, p. 106 (line 26) & p. 108 */ |
_REENT->_new._reent._rand_next = |
_REENT->_new._reent._rand_next * __extension__ 6364136223846793005LL + 1; |
return (int)((_REENT->_new._reent._rand_next >> 32) & RAND_MAX); |
} |
|
#endif /* _REENT_ONLY */ |
/strtol.c
0,0 → 1,226
/* |
FUNCTION |
<<strtol>>---string to long |
|
INDEX |
strtol |
INDEX |
_strtol_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
long strtol(const char *<[s]>, char **<[ptr]>,int <[base]>); |
|
long _strtol_r(void *<[reent]>, |
const char *<[s]>, char **<[ptr]>,int <[base]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
long strtol (<[s]>, <[ptr]>, <[base]>) |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
long _strtol_r (<[reent]>, <[s]>, <[ptr]>, <[base]>) |
char *<[reent]>; |
char *<[s]>; |
char **<[ptr]>; |
int <[base]>; |
|
DESCRIPTION |
The function <<strtol>> converts the string <<*<[s]>>> to |
a <<long>>. First, it breaks down the string into three parts: |
leading whitespace, which is ignored; a subject string consisting |
of characters resembling an integer in the radix specified by <[base]>; |
and a trailing portion consisting of zero or more unparseable characters, |
and always including the terminating null character. Then, it attempts |
to convert the subject string into a <<long>> and returns the |
result. |
|
If the value of <[base]> is 0, the subject string is expected to look |
like a normal C integer constant: an optional sign, a possible `<<0x>>' |
indicating a hexadecimal base, and a number. If <[base]> is between |
2 and 36, the expected form of the subject is a sequence of letters |
and digits representing an integer in the radix specified by <[base]>, |
with an optional plus or minus sign. The letters <<a>>--<<z>> (or, |
equivalently, <<A>>--<<Z>>) are used to signify values from 10 to 35; |
only letters whose ascribed values are less than <[base]> are |
permitted. If <[base]> is 16, a leading <<0x>> is permitted. |
|
The subject sequence is the longest initial sequence of the input |
string that has the expected form, starting with the first |
non-whitespace character. If the string is empty or consists entirely |
of whitespace, or if the first non-whitespace character is not a |
permissible letter or digit, the subject string is empty. |
|
If the subject string is acceptable, and the value of <[base]> is zero, |
<<strtol>> attempts to determine the radix from the input string. A |
string with a leading <<0x>> is treated as a hexadecimal value; a string with |
a leading 0 and no <<x>> is treated as octal; all other strings are |
treated as decimal. If <[base]> is between 2 and 36, it is used as the |
conversion radix, as described above. If the subject string begins with |
a minus sign, the value is negated. Finally, a pointer to the first |
character past the converted subject string is stored in <[ptr]>, if |
<[ptr]> is not <<NULL>>. |
|
If the subject string is empty (or not in acceptable form), no conversion |
is performed and the value of <[s]> is stored in <[ptr]> (if <[ptr]> is |
not <<NULL>>). |
|
The alternate function <<_strtol_r>> is a reentrant version. The |
extra argument <[reent]> is a pointer to a reentrancy structure. |
|
RETURNS |
<<strtol>> returns the converted value, if any. If no conversion was |
made, 0 is returned. |
|
<<strtol>> returns <<LONG_MAX>> or <<LONG_MIN>> if the magnitude of |
the converted value is too large, and sets <<errno>> to <<ERANGE>>. |
|
PORTABILITY |
<<strtol>> is ANSI. |
|
No supporting OS subroutines are required. |
*/ |
|
/*- |
* Copyright (c) 1990 The Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. All advertising materials mentioning features or use of this software |
* must display the following acknowledgement: |
* This product includes software developed by the University of |
* California, Berkeley and its contributors. |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
|
|
#include <_ansi.h> |
#include <limits.h> |
#include <ctype.h> |
#include <errno.h> |
#include <stdlib.h> |
#include <reent.h> |
|
/* |
* Convert a string to a long integer. |
* |
* Ignores `locale' stuff. Assumes that the upper and lower case |
* alphabets and digits are each contiguous. |
*/ |
long |
_DEFUN (_strtol_r, (rptr, nptr, endptr, base), |
struct _reent *rptr _AND |
_CONST char *nptr _AND |
char **endptr _AND |
int base) |
{ |
register const char *s = nptr; |
register unsigned long acc; |
register int c; |
register unsigned long cutoff; |
register int neg = 0, any, cutlim; |
|
/* |
* Skip white space and pick up leading +/- sign if any. |
* If base is 0, allow 0x for hex and 0 for octal, else |
* assume decimal; if base is already 16, allow 0x. |
*/ |
do { |
c = *s++; |
} while (isspace(c)); |
if (c == '-') { |
neg = 1; |
c = *s++; |
} else if (c == '+') |
c = *s++; |
if ((base == 0 || base == 16) && |
c == '0' && (*s == 'x' || *s == 'X')) { |
c = s[1]; |
s += 2; |
base = 16; |
} |
if (base == 0) |
base = c == '0' ? 8 : 10; |
|
/* |
* Compute the cutoff value between legal numbers and illegal |
* numbers. That is the largest legal value, divided by the |
* base. An input number that is greater than this value, if |
* followed by a legal input character, is too big. One that |
* is equal to this value may be valid or not; the limit |
* between valid and invalid numbers is then based on the last |
* digit. For instance, if the range for longs is |
* [-2147483648..2147483647] and the input base is 10, |
* cutoff will be set to 214748364 and cutlim to either |
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated |
* a value > 214748364, or equal but the next digit is > 7 (or 8), |
* the number is too big, and we will return a range error. |
* |
* Set any if any `digits' consumed; make it negative to indicate |
* overflow. |
*/ |
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; |
cutlim = cutoff % (unsigned long)base; |
cutoff /= (unsigned long)base; |
for (acc = 0, any = 0;; c = *s++) { |
if (isdigit(c)) |
c -= '0'; |
else if (isalpha(c)) |
c -= isupper(c) ? 'A' - 10 : 'a' - 10; |
else |
break; |
if (c >= base) |
break; |
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) |
any = -1; |
else { |
any = 1; |
acc *= base; |
acc += c; |
} |
} |
if (any < 0) { |
acc = neg ? LONG_MIN : LONG_MAX; |
rptr->_errno = ERANGE; |
} else if (neg) |
acc = -acc; |
if (endptr != 0) |
*endptr = (char *) (any ? s - 1 : nptr); |
return (acc); |
} |
|
#ifndef _REENT_ONLY |
|
long |
_DEFUN (strtol, (s, ptr, base), |
_CONST char *s _AND |
char **ptr _AND |
int base) |
{ |
return _strtol_r (_REENT, s, ptr, base); |
} |
|
#endif |
/Makefile.am
0,0 → 1,212
## Process this file with automake to generate Makefile.in |
|
AUTOMAKE_OPTIONS = cygnus |
|
INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS) |
|
LIB_SOURCES = \ |
__adjust.c \ |
__exp10.c \ |
__ten_mu.c \ |
abort.c \ |
abs.c \ |
assert.c \ |
atexit.c \ |
atof.c \ |
atoff.c \ |
atoi.c \ |
atol.c \ |
bsearch.c \ |
calloc.c \ |
div.c \ |
drand48.c \ |
dtoa.c \ |
dtoastub.c \ |
ecvtbuf.c \ |
efgcvt.c \ |
environ.c \ |
envlock.c \ |
eprintf.c \ |
erand48.c \ |
exit.c \ |
getenv.c \ |
getenv_r.c \ |
getopt.c \ |
jrand48.c \ |
labs.c \ |
lcong48.c \ |
ldiv.c \ |
ldtoa.c \ |
lrand48.c \ |
malign.c \ |
malloc.c \ |
mblen.c \ |
mblen_r.c \ |
mbstowcs.c \ |
mbstowcs_r.c \ |
mbtowc.c \ |
mbtowc_r.c \ |
mlock.c \ |
mprec.c \ |
mrand48.c \ |
msize.c \ |
mstats.c \ |
mtrim.c \ |
nrand48.c \ |
putenv.c \ |
putenv_r.c \ |
qsort.c \ |
rand.c \ |
rand48.c \ |
rand_r.c \ |
realloc.c \ |
seed48.c \ |
setenv.c \ |
setenv_r.c \ |
srand48.c \ |
strdup.c \ |
strdup_r.c \ |
strtod.c \ |
strtol.c \ |
strtoll.c \ |
strtoll_r.c \ |
strtoul.c \ |
strtoull.c \ |
strtoull_r.c \ |
system.c \ |
valloc.c \ |
wcstombs.c \ |
wcstombs_r.c \ |
wctomb.c \ |
wctomb_r.c |
|
# Because of how libtool moves objects around, mallocr must be built last. |
LIBADD_OBJS = freer.$(oext) reallocr.$(oext) callocr.$(oext) cfreer.$(oext) malignr.$(oext) \ |
vallocr.$(oext) pvallocr.$(oext) mallinfor.$(oext) mallstatsr.$(oext) msizer.$(oext) malloptr.$(oext) mallocr.$(oext) |
|
libstdlib_la_LDFLAGS = -Xcompiler -nostdlib |
|
if USE_LIBTOOL |
noinst_LTLIBRARIES = libstdlib.la |
libstdlib_la_SOURCES = $(LIB_SOURCES) |
libstdlib_la_LIBADD = $(LIBADD_OBJS) |
LIB_COMPILE = $(LTCOMPILE) |
noinst_DATA = objectlist.awk.in |
else |
noinst_LIBRARIES = lib.a |
lib_a_SOURCES = $(LIB_SOURCES) |
lib_a_LIBADD = $(LIBADD_OBJS) |
LIB_COMPILE = $(COMPILE) |
noinst_DATA = |
endif # USE_LIBTOOL |
|
include $(srcdir)/../../Makefile.shared |
|
MALLOC_COMPILE = $(LIB_COMPILE) -DINTERNAL_NEWLIB |
|
mallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOC -c $(srcdir)/mallocr.c -o $@ |
|
freer.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_FREE -c $(srcdir)/mallocr.c -o $@ |
|
reallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_REALLOC -c $(srcdir)/mallocr.c -o $@ |
|
callocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_CALLOC -c $(srcdir)/mallocr.c -o $@ |
|
cfreer.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_CFREE -c $(srcdir)/mallocr.c -o $@ |
|
malignr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MEMALIGN -c $(srcdir)/mallocr.c -o $@ |
|
vallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_VALLOC -c $(srcdir)/mallocr.c -o $@ |
|
pvallocr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_PVALLOC -c $(srcdir)/mallocr.c -o $@ |
|
mallinfor.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLINFO -c $(srcdir)/mallocr.c -o $@ |
|
mallstatsr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOC_STATS -c $(srcdir)/mallocr.c -o $@ |
|
msizer.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOC_USABLE_SIZE -c $(srcdir)/mallocr.c -o $@ |
|
malloptr.$(oext): mallocr.c |
$(MALLOC_COMPILE) -DDEFINE_MALLOPT -c $(srcdir)/mallocr.c -o $@ |
|
CHEWOUT_FILES= \ |
abort.def \ |
abs.def \ |
assert.def \ |
atexit.def \ |
atof.def \ |
ecvtbuf.def \ |
atoi.def \ |
bsearch.def \ |
calloc.def \ |
div.def \ |
efgcvt.def \ |
envlock.def \ |
exit.def \ |
getenv.def \ |
labs.def \ |
ldiv.def \ |
malloc.def \ |
mallocr.def \ |
mblen.def \ |
mbstowcs.def \ |
mbtowc.def \ |
mlock.def \ |
mstats.def \ |
qsort.def \ |
rand.def \ |
rand48.def \ |
strtod.def \ |
strtol.def \ |
strtoll.def \ |
strtoul.def \ |
strtoull.def \ |
system.def \ |
wcstombs.def \ |
wctomb.def |
|
SUFFIXES = .def |
|
CHEW = ../../doc/makedoc -f $(srcdir)/../../doc/doc.str |
|
.c.def: |
$(CHEW) < $< > $*.def 2> $*.ref |
touch stmp-def |
|
TARGETDOC = ../tmp.texi |
|
doc: $(CHEWOUT_FILES) |
cat $(srcdir)/stdlib.tex >> $(TARGETDOC) |
|
CLEANFILES = $(CHEWOUT_FILES) *.ref |
|
dtoa.$(oext): dtoa.c mprec.h |
ldtoa.$(oext): ldtoa.c mprec.h |
ecvtbuf.$(oext): ecvtbuf.c mprec.h |
mbtowc_r.$(oext): mbtowc_r.c mbctype.h |
$(LIB_COMPILE) -c -fshort-enums $(srcdir)/mbtowc_r.c -o $@ |
|
mprec.$(oext): mprec.c mprec.h |
strtod.$(oext): strtod.c mprec.h |
wctomb_r.$(oext): wctomb_r.c mbctype.h |
drand48.$(oext): drand48.c rand48.h |
erand48.$(oext): erand48.c rand48.h |
jrand48.$(oext): jrand48.c rand48.h |
lcong48.$(oext): lcong48.c rand48.h |
lrand48.$(oext): lrand48.c rand48.h |
mrand48.$(oext): mrand48.c rand48.h |
nrand48.$(oext): nrand48.c rand48.h |
rand48.$(oext): rand48.c rand48.h |
seed48.$(oext): seed48.c rand48.h |
srand48.$(oext): srand48.c rand48.h |
/getenv.c
0,0 → 1,94
/* |
FUNCTION |
<<getenv>>---look up environment variable |
|
INDEX |
getenv |
INDEX |
environ |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
char *getenv(const char *<[name]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
char *getenv(<[name]>) |
char *<[name]>; |
|
DESCRIPTION |
<<getenv>> searches the list of environment variable names and values |
(using the global pointer ``<<char **environ>>'') for a variable whose |
name matches the string at <[name]>. If a variable name matches, |
<<getenv>> returns a pointer to the associated value. |
|
RETURNS |
A pointer to the (string) value of the environment variable, or |
<<NULL>> if there is no such environment variable. |
|
PORTABILITY |
<<getenv>> is ANSI, but the rules for properly forming names of environment |
variables vary from one system to another. |
|
<<getenv>> requires a global pointer <<environ>>. |
*/ |
|
/* |
* Copyright (c) 1987, 2000 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that: (1) source distributions retain this entire copyright |
* notice and comment, and (2) distributions including binaries display |
* the following acknowledgement: ``This product includes software |
* developed by the University of California, Berkeley and its contributors'' |
* in the documentation or other materials provided with the distribution |
* and in all advertising materials mentioning features or use of this |
* software. Neither the name of the University nor the names of its |
* contributors may be used to endorse or promote products derived |
* from this software without specific prior written permission. |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
*/ |
|
#ifndef _REENT_ONLY |
|
#include <stdlib.h> |
#include <stddef.h> |
#include <string.h> |
|
/* |
* _findenv -- |
* Returns pointer to value associated with name, if any, else NULL. |
* Sets offset to be the offset of the name/value combination in the |
* environmental array, for use by setenv(3) and unsetenv(3). |
* Explicitly removes '=' in argument name. |
* |
* This routine *should* be a static; don't use it. |
*/ |
|
char * |
_DEFUN (_findenv, (name, offset), |
register _CONST char *name _AND |
int *offset) |
{ |
return _findenv_r (_REENT, name, offset); |
} |
|
/* |
* getenv -- |
* Returns ptr to value associated with name, if any, else NULL. |
*/ |
|
char * |
_DEFUN (getenv, (name), |
_CONST char *name) |
{ |
int offset; |
char *_findenv_r (); |
|
return _findenv_r (_REENT, name, &offset); |
} |
|
#endif /* !_REENT_ONLY */ |
/__exp10.c
0,0 → 1,29
/* |
* compute 10**x by successive squaring. |
*/ |
|
#include <_ansi.h> |
|
double |
_DEFUN (__exp10, (x), |
unsigned x) |
{ |
static _CONST double powtab[] = |
{1.0, |
10.0, |
100.0, |
1000.0, |
10000.0}; |
|
if (x < (sizeof (powtab) / sizeof (double))) |
return powtab[x]; |
else if (x & 1) |
{ |
return 10.0 * __exp10 (x - 1); |
} |
else |
{ |
double n = __exp10 (x / 2); |
return n * n; |
} |
} |
/atoi.c
0,0 → 1,54
/* |
FUNCTION |
<<atoi>>, <<atol>>---string to integer |
|
INDEX |
atoi |
INDEX |
atol |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
int atoi(const char *<[s]>); |
long atol(const char *<[s]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
int atoi(<[s]>) |
char *<[s]>; |
|
long atol(<[s]>) |
char *<[s]>; |
|
|
DESCRIPTION |
<<atoi>> converts the initial portion of a string to an <<int>>. |
<<atol>> converts the initial portion of a string to a <<long>>. |
|
<<atoi(s)>> is implemented as <<(int)strtol(s, NULL, 10).>> |
<<atol(s)>> is implemented as <<strtol(s, NULL, 10).>> |
|
RETURNS |
The functions return the converted value, if any. If no conversion was |
made, <<0>> is returned. |
|
PORTABILITY |
<<atoi>> is ANSI. |
|
No supporting OS subroutines are required. |
*/ |
|
/* |
* Andy Wilson, 2-Oct-89. |
*/ |
|
#include <stdlib.h> |
#include <_ansi.h> |
|
int |
_DEFUN (atoi, (s), |
_CONST char *s) |
{ |
return (int) strtol (s, NULL, 10); |
} |
|
/calloc.c
0,0 → 1,69
#ifdef MALLOC_PROVIDED |
int _dummy_calloc = 1; |
#else |
/* |
FUNCTION |
<<calloc>>---allocate space for arrays |
|
INDEX |
calloc |
|
INDEX |
_calloc_r |
|
ANSI_SYNOPSIS |
#include <stdlib.h> |
void *calloc(size_t <[n]>, size_t <[s]>); |
void *calloc_r(void *<[reent]>, size_t <n>, <size_t> <[s]>); |
|
TRAD_SYNOPSIS |
#include <stdlib.h> |
char *calloc(<[n]>, <[s]>) |
size_t <[n]>, <[s]>; |
|
char *_calloc_r(<[reent]>, <[n]>, <[s]>) |
char *<[reent]>; |
size_t <[n]>; |
size_t <[s]>; |
|
|
|
DESCRIPTION |
Use <<calloc>> to request a block of memory sufficient to hold an |
array of <[n]> elements, each of which has size <[s]>. |
|
The memory allocated by <<calloc>> comes out of the same memory pool |
used by <<malloc>>, but the memory block is initialized to all zero |
bytes. (To avoid the overhead of initializing the space, use |
<<malloc>> instead.) |
|
The alternate function <<_calloc_r>> is reentrant. |
The extra argument <[reent]> is a pointer to a reentrancy structure. |
|
RETURNS |
If successful, a pointer to the newly allocated space. |
|
If unsuccessful, <<NULL>>. |
|
PORTABILITY |
<<calloc>> is ANSI. |
|
Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>, |
<<lseek>>, <<read>>, <<sbrk>>, <<write>>. |
*/ |
|
#include <string.h> |
#include <stdlib.h> |
|
#ifndef _REENT_ONLY |
|
_PTR |
_DEFUN (calloc, (n, size), |
size_t n _AND |
size_t size) |
{ |
return _calloc_r (_REENT, n, size); |
} |
|
#endif |
#endif /* MALLOC_PROVIDED */ |