aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-07-01 00:00:00 -0800
committersvn2git <svn2git@FreeBSD.org>1994-07-01 00:00:00 -0800
commit5e0e9b99dc3fc0ecd49d929db0d57c784b66f481 (patch)
treee779b5a6edddbb949b7990751b12d6f25304ba86 /lib
parenta16f65c7d117419bd266c28a1901ef129a337569 (diff)
downloadsrc-releng/1.tar.gz
src-releng/1.zip
Release FreeBSD 1.1.5.1release/1.1.5.1_cvsreleng/1
This commit was manufactured to restore the state of the 1.1.5.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile10
-rw-r--r--lib/Makefile.inc2
-rw-r--r--lib/csu.i386/Makefile13
-rw-r--r--lib/csu.i386/c++rt0.c80
-rw-r--r--lib/csu.i386/crt0.c11
-rw-r--r--lib/csu.i386/crt1.c47
-rw-r--r--lib/libc/Makefile2
-rw-r--r--lib/libc/compat-43/Makefile.inc5
-rw-r--r--lib/libc/compat-43/setrgid.c (renamed from lib/libc/gen/setrgid.c)15
-rw-r--r--lib/libc/compat-43/setruid.c (renamed from lib/libc/gen/setruid.c)15
-rw-r--r--lib/libc/db/hash/hash.c2
-rw-r--r--lib/libc/db/recno/rec_open.c2
-rw-r--r--lib/libc/gen/Makefile.inc13
-rw-r--r--lib/libc/gen/ctype_.c8
-rw-r--r--lib/libc/gen/getcap.32
-rw-r--r--lib/libc/gen/getcap.c29
-rw-r--r--lib/libc/gen/getfsent.32
-rw-r--r--lib/libc/gen/getmntinfo.32
-rw-r--r--lib/libc/gen/getpwent.314
-rw-r--r--lib/libc/gen/getpwent.c93
-rw-r--r--lib/libc/gen/semconfig.c2
-rw-r--r--lib/libc/gen/setmode.c11
-rw-r--r--lib/libc/i386/DEFS.h2
-rw-r--r--lib/libc/i386/string/bcmp.S11
-rw-r--r--lib/libc/i386/string/memcmp.S15
-rw-r--r--lib/libc/i386/string/memmove.S17
-rw-r--r--lib/libc/i386/string/memset.S16
-rw-r--r--lib/libc/i386/string/strcmp.S4
-rw-r--r--lib/libc/i386/string/strncmp.S69
-rw-r--r--lib/libc/locale/Makefile.inc18
-rw-r--r--lib/libc/locale/ansi.c148
-rw-r--r--lib/libc/locale/euc.4231
-rw-r--r--lib/libc/locale/euc.c220
-rw-r--r--lib/libc/locale/frune.c103
-rw-r--r--lib/libc/locale/isctype.c (renamed from lib/libc/gen/isctype.c)86
-rw-r--r--lib/libc/locale/mbrune.3157
-rw-r--r--lib/libc/locale/mbrune.c112
-rw-r--r--lib/libc/locale/multibyte.3241
-rw-r--r--lib/libc/locale/none.c (renamed from lib/libc/stdlib/multibyte.c)102
-rw-r--r--lib/libc/locale/rune.3269
-rw-r--r--lib/libc/locale/rune.c334
-rw-r--r--lib/libc/locale/setlocale.3321
-rw-r--r--lib/libc/locale/setlocale.c198
-rw-r--r--lib/libc/locale/table.c160
-rw-r--r--lib/libc/locale/utf2.487
-rw-r--r--lib/libc/locale/utf2.c148
-rw-r--r--lib/libc/net/gethostnamadr.c1
-rw-r--r--lib/libc/net/ns_addr.c4
-rw-r--r--lib/libc/net/rcmd.c30
-rw-r--r--lib/libc/stdio/Makefile.inc7
-rw-r--r--lib/libc/stdio/fclose.c2
-rw-r--r--lib/libc/stdio/fgetline.c1
-rw-r--r--lib/libc/stdio/fgetln.3 (renamed from lib/libc/stdio/fgetline.3)52
-rw-r--r--lib/libc/stdio/fgetln.c162
-rw-r--r--lib/libc/stdio/fseek.c2
-rw-r--r--lib/libc/stdio/gets.c13
-rw-r--r--lib/libc/stdio/local.h2
-rw-r--r--lib/libc/stdio/printf.32
-rw-r--r--lib/libc/stdlib/Makefile.inc2
-rw-r--r--lib/libc/stdlib/rand.c2
-rw-r--r--lib/libc/string/index.32
-rw-r--r--lib/libc/string/strftime.c1
-rw-r--r--lib/libc/sys/Makefile.inc9
-rw-r--r--lib/libc/sys/execve.22
-rw-r--r--lib/libc/sys/setregid.22
-rw-r--r--lib/libc/sys/setreuid.22
-rw-r--r--lib/libc/sys/setuid.2 (renamed from lib/libc/gen/setuid.3)64
-rw-r--r--lib/libc/sys/sigsuspend.24
-rw-r--r--lib/libcompat/Makefile18
-rw-r--r--lib/libcompat/cftime.c63
-rw-r--r--lib/libcompat/ftime.c69
-rw-r--r--lib/libcompat/libcompat.3205
-rw-r--r--lib/libcompat/regex.c93
-rw-r--r--lib/libcompat/regexp/COPYRIGHT22
-rw-r--r--lib/libcompat/regexp/Makefile.inc20
-rw-r--r--lib/libcompat/regexp/README84
-rw-r--r--lib/libcompat/regexp/regerror.c18
-rw-r--r--lib/libcompat/regexp/regexp.3321
-rw-r--r--lib/libcompat/regexp/regexp.c1320
-rw-r--r--lib/libcompat/regexp/regexp.h21
-rw-r--r--lib/libcompat/regexp/regmagic.h5
-rw-r--r--lib/libcompat/regexp/regsub.c81
-rw-r--r--lib/libcompat/setrgid.c49
-rw-r--r--lib/libcompat/setruid.c49
-rw-r--r--lib/libcompat/sgtty.c67
-rw-r--r--lib/libcurses/Makefile3
-rw-r--r--lib/libcurses/cr_put.c24
-rw-r--r--lib/libcurses/curses.h1
-rw-r--r--lib/libcurses/refresh.c42
-rw-r--r--lib/libcurses/setterm.c27
-rw-r--r--lib/libcurses/tstp.c8
-rw-r--r--lib/libcurses/tty.c41
-rw-r--r--lib/libmalloc/CHANGES58
-rw-r--r--lib/libmalloc/COPYRIGHT23
-rw-r--r--lib/libmalloc/Makefile17
-rw-r--r--lib/libmalloc/Makefile.moraes187
-rw-r--r--lib/libmalloc/NOTE151
-rw-r--r--lib/libmalloc/README68
-rw-r--r--lib/libmalloc/TODO62
-rw-r--r--lib/libmalloc/_emalloc.c55
-rw-r--r--lib/libmalloc/_malloc.c88
-rw-r--r--lib/libmalloc/_memalign.c37
-rw-r--r--lib/libmalloc/_strdup.c23
-rw-r--r--lib/libmalloc/_strsave.c23
-rw-r--r--lib/libmalloc/align.h94
-rw-r--r--lib/libmalloc/assert.h10
-rw-r--r--lib/libmalloc/botch.c45
-rw-r--r--lib/libmalloc/bsd.lib.mk269
-rw-r--r--lib/libmalloc/defs.h386
-rw-r--r--lib/libmalloc/dumpheap.c107
-rw-r--r--lib/libmalloc/emalloc.c69
-rw-r--r--lib/libmalloc/externs.h113
-rw-r--r--lib/libmalloc/getmem.c108
-rw-r--r--lib/libmalloc/globals.c87
-rw-r--r--lib/libmalloc/globals.h43
-rw-r--r--lib/libmalloc/globrename.h46
-rw-r--r--lib/libmalloc/leak.c160
-rw-r--r--lib/libmalloc/malloc.c622
-rw-r--r--lib/libmalloc/malloc.doc653
-rw-r--r--lib/libmalloc/malloc.h136
-rw-r--r--lib/libmalloc/memalign.c160
-rw-r--r--lib/libmalloc/setopts.c120
-rw-r--r--lib/libmalloc/sptree.c763
-rw-r--r--lib/libmalloc/sptree.h65
-rw-r--r--lib/libmalloc/stats.c38
-rw-r--r--lib/libmalloc/strdup.c26
-rw-r--r--lib/libmalloc/strsave.c21
-rwxr-xr-xlib/libmalloc/tests/munge.sh40
-rwxr-xr-xlib/libmalloc/tests/plot.sh81
-rwxr-xr-xlib/libmalloc/tests/regress11
-rw-r--r--lib/libmalloc/tests/simumalloc.c239
-rw-r--r--lib/libmalloc/tests/t1.c40
-rw-r--r--lib/libmalloc/tests/t2.c37
-rw-r--r--lib/libmalloc/tests/t3.c110
-rw-r--r--lib/libmalloc/tests/t4.c20
-rw-r--r--lib/libmalloc/tests/t5.c31
-rw-r--r--lib/libmalloc/tests/test.out415
-rw-r--r--lib/libmalloc/tests/testmalloc.c182
-rw-r--r--lib/libmalloc/tests/testmemalign.c16
-rwxr-xr-xlib/libmalloc/tests/testrun.sh28
-rw-r--r--lib/libmalloc/tests/testsbrk.c22
-rw-r--r--lib/libmalloc/tests/teststomp.c34
-rw-r--r--lib/libmalloc/trace.h19
-rw-r--r--lib/libmalloc/verify.c81
-rw-r--r--lib/libmalloc/version.c1
-rw-r--r--lib/libpthread/include/stdio.h4
-rw-r--r--lib/libpthread/stdio/fflush.c4
-rw-r--r--lib/libpthread/stdio/ftell.c4
-rw-r--r--lib/libpthread/stdio/vfprintf.c6
-rw-r--r--lib/libskey/Makefile7
-rw-r--r--lib/libskey/authfile.c177
-rw-r--r--lib/libskey/md4.c336
-rw-r--r--lib/libskey/md4.h47
-rw-r--r--lib/libskey/pathnames.h5
-rw-r--r--lib/libskey/put.c2289
-rw-r--r--lib/libskey/skey_crypt.c37
-rw-r--r--lib/libskey/skeylogin.c328
-rw-r--r--lib/libskey/skeysubr.c225
-rw-r--r--lib/libterm/Makefile4
-rw-r--r--lib/libterm/tputs.c14
-rw-r--r--lib/libutil/kvm.c33
-rw-r--r--lib/libutil/login.c37
-rw-r--r--lib/msun/Makefile111
-rw-r--r--lib/msun/i387/DEFS.h83
-rw-r--r--lib/msun/i387/e_acos.S49
-rw-r--r--lib/msun/i387/e_asin.S48
-rw-r--r--lib/msun/i387/e_atan2.S43
-rw-r--r--lib/msun/i387/e_exp.S52
-rw-r--r--lib/msun/i387/e_fmod.S47
-rw-r--r--lib/msun/i387/e_log.S43
-rw-r--r--lib/msun/i387/e_log10.S43
-rw-r--r--lib/msun/i387/e_remainder.S47
-rw-r--r--lib/msun/i387/e_scalb.S43
-rw-r--r--lib/msun/i387/e_sqrt.S42
-rw-r--r--lib/msun/i387/s_atan.S43
-rw-r--r--lib/msun/i387/s_ceil.S57
-rw-r--r--lib/msun/i387/s_copysign.S47
-rw-r--r--lib/msun/i387/s_cos.S55
-rw-r--r--lib/msun/i387/s_finite.S45
-rw-r--r--lib/msun/i387/s_floor.S57
-rw-r--r--lib/msun/i387/s_ilogb.S52
-rw-r--r--lib/msun/i387/s_log1p.S43
-rw-r--r--lib/msun/i387/s_logb.S43
-rw-r--r--lib/msun/i387/s_rint.S42
-rw-r--r--lib/msun/i387/s_scalbn.S43
-rw-r--r--lib/msun/i387/s_significand.S43
-rw-r--r--lib/msun/i387/s_sin.S55
-rw-r--r--lib/msun/i387/s_tan.S56
-rw-r--r--lib/msun/man/acos.389
-rw-r--r--lib/msun/man/acosh.382
-rw-r--r--lib/msun/man/asin.391
-rw-r--r--lib/msun/man/asinh.370
-rw-r--r--lib/msun/man/atan.375
-rw-r--r--lib/msun/man/atan2.3189
-rw-r--r--lib/msun/man/atanh.384
-rw-r--r--lib/msun/man/ceil.363
-rw-r--r--lib/msun/man/cos.374
-rw-r--r--lib/msun/man/cosh.375
-rw-r--r--lib/msun/man/erf.383
-rw-r--r--lib/msun/man/exp.3287
-rw-r--r--lib/msun/man/fabs.367
-rw-r--r--lib/msun/man/floor.363
-rw-r--r--lib/msun/man/fmod.376
-rw-r--r--lib/msun/man/hypot.3125
-rw-r--r--lib/msun/man/ieee.3152
-rw-r--r--lib/msun/man/ieee_test.390
-rw-r--r--lib/msun/man/j0.3128
-rw-r--r--lib/msun/man/lgamma.3124
-rw-r--r--lib/msun/man/math.3633
-rw-r--r--lib/msun/man/rint.363
-rw-r--r--lib/msun/man/sin.373
-rw-r--r--lib/msun/man/sinh.375
-rw-r--r--lib/msun/man/sqrt.3121
-rw-r--r--lib/msun/man/tan.374
-rw-r--r--lib/msun/man/tanh.371
-rw-r--r--lib/msun/src/Readme211
-rw-r--r--lib/msun/src/dependencies471
-rw-r--r--lib/msun/src/e_acos.c116
-rw-r--r--lib/msun/src/e_acosh.c75
-rw-r--r--lib/msun/src/e_asin.c125
-rw-r--r--lib/msun/src/e_atan2.c132
-rw-r--r--lib/msun/src/e_atanh.c78
-rw-r--r--lib/msun/src/e_cosh.c92
-rw-r--r--lib/msun/src/e_exp.c167
-rw-r--r--lib/msun/src/e_fmod.c153
-rw-r--r--lib/msun/src/e_gamma.c35
-rw-r--r--lib/msun/src/e_gamma_r.c34
-rw-r--r--lib/msun/src/e_hypot.c125
-rw-r--r--lib/msun/src/e_j0.c488
-rw-r--r--lib/msun/src/e_j1.c486
-rw-r--r--lib/msun/src/e_jn.c282
-rw-r--r--lib/msun/src/e_lgamma.c35
-rw-r--r--lib/msun/src/e_lgamma_r.c313
-rw-r--r--lib/msun/src/e_log.c149
-rw-r--r--lib/msun/src/e_log10.c101
-rw-r--r--lib/msun/src/e_pow.c308
-rw-r--r--lib/msun/src/e_rem_pio2.c153
-rw-r--r--lib/msun/src/e_remainder.c89
-rw-r--r--lib/msun/src/e_scalb.c54
-rw-r--r--lib/msun/src/e_sinh.c85
-rw-r--r--lib/msun/src/e_sqrt.c461
-rw-r--r--lib/msun/src/fdlibm.h196
-rw-r--r--lib/msun/src/k_cos.c102
-rw-r--r--lib/msun/src/k_rem_pio2.c319
-rw-r--r--lib/msun/src/k_sin.c84
-rw-r--r--lib/msun/src/k_standard.c737
-rw-r--r--lib/msun/src/k_tan.c137
-rw-r--r--lib/msun/src/math.h224
-rw-r--r--lib/msun/src/s_asinh.c71
-rw-r--r--lib/msun/src/s_atan.c143
-rw-r--r--lib/msun/src/s_cbrt.c95
-rw-r--r--lib/msun/src/s_ceil.c88
-rw-r--r--lib/msun/src/s_copysign.c42
-rw-r--r--lib/msun/src/s_cos.c87
-rw-r--r--lib/msun/src/s_erf.c320
-rw-r--r--lib/msun/src/s_expm1.c226
-rw-r--r--lib/msun/src/s_fabs.c38
-rw-r--r--lib/msun/src/s_finite.c41
-rw-r--r--lib/msun/src/s_floor.c89
-rw-r--r--lib/msun/src/s_frexp.c67
-rw-r--r--lib/msun/src/s_ilogb.c56
-rw-r--r--lib/msun/src/s_isnan.c50
-rw-r--r--lib/msun/src/s_ldexp.c31
-rw-r--r--lib/msun/src/s_lib_version.c38
-rw-r--r--lib/msun/src/s_log1p.c175
-rw-r--r--lib/msun/src/s_logb.c48
-rw-r--r--lib/msun/src/s_matherr.c29
-rw-r--r--lib/msun/src/s_modf.c92
-rw-r--r--lib/msun/src/s_nextafter.c90
-rw-r--r--lib/msun/src/s_rint.c94
-rw-r--r--lib/msun/src/s_scalbn.c73
-rw-r--r--lib/msun/src/s_signgam.c2
-rw-r--r--lib/msun/src/s_significand.c33
-rw-r--r--lib/msun/src/s_sin.c87
-rw-r--r--lib/msun/src/s_tan.c81
-rw-r--r--lib/msun/src/s_tanh.c85
-rw-r--r--lib/msun/src/w_acos.c42
-rw-r--r--lib/msun/src/w_acosh.c41
-rw-r--r--lib/msun/src/w_asin.c43
-rw-r--r--lib/msun/src/w_atan2.c42
-rw-r--r--lib/msun/src/w_atanh.c46
-rw-r--r--lib/msun/src/w_cabs.c27
-rw-r--r--lib/msun/src/w_cosh.c41
-rw-r--r--lib/msun/src/w_drem.c15
-rw-r--r--lib/msun/src/w_exp.c52
-rw-r--r--lib/msun/src/w_fmod.c42
-rw-r--r--lib/msun/src/w_gamma.c48
-rw-r--r--lib/msun/src/w_gamma_r.c45
-rw-r--r--lib/msun/src/w_hypot.c42
-rw-r--r--lib/msun/src/w_j0.c68
-rw-r--r--lib/msun/src/w_j1.c69
-rw-r--r--lib/msun/src/w_jn.c91
-rw-r--r--lib/msun/src/w_lgamma.c48
-rw-r--r--lib/msun/src/w_lgamma_r.c45
-rw-r--r--lib/msun/src/w_log.c42
-rw-r--r--lib/msun/src/w_log10.c45
-rw-r--r--lib/msun/src/w_pow.c62
-rw-r--r--lib/msun/src/w_remainder.c41
-rw-r--r--lib/msun/src/w_scalb.c59
-rw-r--r--lib/msun/src/w_sinh.c41
-rw-r--r--lib/msun/src/w_sqrt.c41
301 files changed, 30627 insertions, 433 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 29043c1fd223..7c72039dc047 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 5.25.1.1 (Berkeley) 5/7/91
-SUBDIR= csu.${MACHINE} libc libcurses libm libpthread \
- libresolv librpcsvc libtelnet libterm libutil liby
+SUBDIR= csu.${MACHINE} libc libcurses libmalloc libpthread \
+ libresolv librpcsvc libskey libtelnet libterm libutil liby
.if exists(libcrypt)
.if !defined(NOCRYPT)
@@ -15,4 +15,10 @@ SUBDIR+= libf2c
SUBDIR+= libI77 libF77
.endif
+.if !defined(WANT_MSUN)
+SUBDIR+= libm
+.else
+SUBDIR+= msun
+.endif
+
.include <bsd.subdir.mk>
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 8e9d1e78a221..848db237caae 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -1,3 +1,3 @@
# Default version for system libs (override in <lib>/Makefile if necessary)
SHLIB_MAJOR?= 1
-SHLIB_MINOR?= 0
+SHLIB_MINOR?= 1
diff --git a/lib/csu.i386/Makefile b/lib/csu.i386/Makefile
index 503ad9753294..adb0c85a0425 100644
--- a/lib/csu.i386/Makefile
+++ b/lib/csu.i386/Makefile
@@ -1,9 +1,12 @@
# from: @(#)Makefile 5.6 (Berkeley) 5/22/91
-# $Id: Makefile,v 1.8 1993/12/24 02:11:37 jkh Exp $
+# $Id: Makefile,v 1.12 1994/06/21 15:21:28 jkh Exp $
CFLAGS+= -DLIBC_SCCS -DDYNAMIC
-OBJS= crt0.o gcrt0.o crt1.so
+OBJS= crt0.o mcrt0.o c++rt0.o
CLEANFILES+= gmon.o moncrt0.o core a.out
+.if defined(STARTUP_LOCALE)
+CFLAGS+= -DSTARTUP_LOCALE
+.endif
all: ${OBJS}
@@ -12,9 +15,9 @@ crt0.o: crt0.c
${LD} -x -r ${.TARGET}
mv a.out ${.TARGET}
-crt1.so: crt1.c
+c++rt0.o: c++rt0.c
${CC} ${CFLAGS} -fpic -c ${.ALLSRC} -o ${.TARGET}
- ${LD} -X -r ${.TARGET}
+ @${LD} -x -r ${.TARGET}
@mv a.out ${.TARGET}
moncrt0.o: crt0.c
@@ -22,7 +25,7 @@ moncrt0.o: crt0.c
${LD} -x -r ${.TARGET}
mv a.out ${.TARGET}
-gcrt0.o: moncrt0.o gmon.o
+mcrt0.o: moncrt0.o gmon.o
${LD} -x -r -o ${.TARGET} moncrt0.o gmon.o
gmon.o: gmon.c gmon.h
diff --git a/lib/csu.i386/c++rt0.c b/lib/csu.i386/c++rt0.c
new file mode 100644
index 000000000000..d917a78a55e5
--- /dev/null
+++ b/lib/csu.i386/c++rt0.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: c++rt0.c,v 1.1 1994/03/09 17:12:59 nate Exp $
+ */
+
+/*
+ * Run-time module for GNU C++ compiled shared libraries.
+ *
+ * The linker constructs the following arrays of pointers to global
+ * constructors and destructors. The first element contains the
+ * number of pointers in each.
+ * The tables are also null-terminated.
+ */
+void (*__CTOR_LIST__[0])(void);
+void (*__DTOR_LIST__[0])(void);
+
+static void
+__dtors(void)
+{
+ unsigned long i = (unsigned long) __DTOR_LIST__[0];
+ void (**p)(void) = __DTOR_LIST__ + i;
+
+ while (i--)
+ (**p--)();
+}
+
+static void
+__ctors(void)
+{
+ void (**p)(void) = __CTOR_LIST__ + 1;
+
+ while (*p)
+ (**p++)();
+}
+
+extern void __init() asm(".init");
+
+void
+__init(void)
+{
+ static int initialized = 0;
+
+ /*
+ * Call global constructors.
+ * Arrange to call global destructors at exit.
+ */
+ if (!initialized) {
+ initialized = 1;
+ __ctors();
+ atexit(__dtors);
+ }
+
+}
diff --git a/lib/csu.i386/crt0.c b/lib/csu.i386/crt0.c
index 93bb1e1ff7fb..4c0deb0ae91d 100644
--- a/lib/csu.i386/crt0.c
+++ b/lib/csu.i386/crt0.c
@@ -27,7 +27,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: crt0.c,v 1.9 1994/02/16 19:26:39 nate Exp $
+ * $Id: crt0.c,v 1.10 1994/06/12 10:51:01 ache Exp $
*/
@@ -39,6 +39,9 @@ extern void exit();
int _callmain();
#include <sys/param.h>
+#ifdef STARTUP_LOCALE
+#include <locale.h>
+#endif /* STARTUP_LOCALE */
#ifdef DYNAMIC
#include <sys/types.h>
@@ -166,7 +169,11 @@ asm("eprol:");
#ifdef MCRT0
atexit(_mcleanup);
monstartup(&eprol, &etext);
-#endif MCRT0
+#endif /* MCRT0 */
+
+#ifdef STARTUP_LOCALE
+ (void) setlocale(LC_ALL, "");
+#endif /* STARTUP_LOCALE */
asm ("__callmain:"); /* Defined for the benefit of debuggers */
exit(main(kfp->kargc, argv, environ));
diff --git a/lib/csu.i386/crt1.c b/lib/csu.i386/crt1.c
deleted file mode 100644
index bee2d1b6fb67..000000000000
--- a/lib/csu.i386/crt1.c
+++ /dev/null
@@ -1,47 +0,0 @@
-typedef void (*func_ptr) (void);
-
-func_ptr __CTOR_LIST__[2];
-func_ptr __DTOR_LIST__[2];
-
-/* Run all the global destructors on exit from the program. */
-
-static void
-__do_global_dtors ()
-{
- unsigned nptrs = (unsigned long) __DTOR_LIST__[0];
- unsigned i;
-
- /* Some systems place the number of pointers
- in the first word of the table.
- On other systems, that word is -1.
- In all cases, the table is null-terminated. */
-
- /* If the length is not recorded, count up to the null. */
- if (nptrs == -1)
- for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++);
-
- /* GNU LD format. */
- for (i = nptrs; i >= 1; i--)
- __DTOR_LIST__[i] ();
-
-}
-
-static void
-__do_global_ctors ()
-{
- func_ptr *p;
-
- for (p = __CTOR_LIST__ + 1; *p; )
- (*p++)();
- atexit (__do_global_dtors);
-}
-
-__init()
-{
- static int initialized = 0;
- if (! initialized) {
- initialized = 1;
- __do_global_ctors ();
- }
-
-}
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
index 319a528c5a54..fe11e19456a1 100644
--- a/lib/libc/Makefile
+++ b/lib/libc/Makefile
@@ -15,7 +15,9 @@ INSTALL_PIC_ARCHIVE=
.include "${.CURDIR}/gen/Makefile.inc"
.include "${.CURDIR}/locale/Makefile.inc"
.include "${.CURDIR}/net/Makefile.inc"
+.if defined(GCC1_IN_LIBC)
.include "${.CURDIR}/quad/Makefile.inc"
+.endif
.include "${.CURDIR}/stdio/Makefile.inc"
.include "${.CURDIR}/stdlib/Makefile.inc"
.include "${.CURDIR}/string/Makefile.inc"
diff --git a/lib/libc/compat-43/Makefile.inc b/lib/libc/compat-43/Makefile.inc
index 63c330fcd813..bcb3d1efe3cb 100644
--- a/lib/libc/compat-43/Makefile.inc
+++ b/lib/libc/compat-43/Makefile.inc
@@ -1,9 +1,10 @@
-# @(#)Makefile.inc 5.3 (Berkeley) 2/20/91
+# From: @(#)Makefile.inc 5.3 (Berkeley) 2/20/91
+# $Id: Makefile.inc,v 1.5 1994/04/04 19:33:56 wollman Exp $
# compat-43 sources
.PATH: ${.CURDIR}/${MACHINE}/compat-43 ${.CURDIR}/compat-43
-SRCS+= creat.c getwd.c killpg.c setpgrp.c sigcompat.c
+SRCS+= creat.c getwd.c killpg.c setpgrp.c sigcompat.c setruid.c setrgid.c
MAN2+= compat-43/creat.2 compat-43/killpg.2 compat-43/sigblock.2 \
compat-43/sigpause.2 compat-43/sigsetmask.2 compat-43/sigvec.2
diff --git a/lib/libc/gen/setrgid.c b/lib/libc/compat-43/setrgid.c
index 43492306191e..50484554ac8b 100644
--- a/lib/libc/gen/setrgid.c
+++ b/lib/libc/compat-43/setrgid.c
@@ -32,10 +32,16 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setrgid.c 5.5 (Berkeley) 2/23/91";
+static char sccsid[] = "From: @(#)setrgid.c 5.5 (Berkeley) 2/23/91";
+static const char rcsid[] =
+ "$Id: setrgid.c,v 1.5 1994/04/23 23:52:45 wollman Exp $";
#endif /* LIBC_SCCS and not lint */
#include <unistd.h>
+#include <string.h>
+
+#define MESSAGE ": warning: this program uses setrgid(), which doesn't do anything\r\n(but used to)\r\n"
+
int
#ifdef __STDC__
@@ -45,6 +51,11 @@ setrgid(rgid)
int rgid;
#endif
{
-
+ extern char *__progname;
+ write(2, __progname, strlen(__progname));
+ write(2, MESSAGE, sizeof(MESSAGE) - 1);
return (setregid(rgid, -1));
}
+
+asm(".stabs \"warning: setrgid function referenced\", 30, 0,0,0");
+asm(".stabs \"_setrgid\", 1, 0, 0, 0");
diff --git a/lib/libc/gen/setruid.c b/lib/libc/compat-43/setruid.c
index 1c224a33095d..72171a57b30d 100644
--- a/lib/libc/gen/setruid.c
+++ b/lib/libc/compat-43/setruid.c
@@ -32,10 +32,15 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setruid.c 5.5 (Berkeley) 2/23/91";
+static char sccsid[] = "From: @(#)setruid.c 5.5 (Berkeley) 2/23/91";
+static const char rcsid[] =
+ "$Id: setruid.c,v 1.4 1994/04/23 20:39:02 wollman Exp $";
#endif /* LIBC_SCCS and not lint */
#include <unistd.h>
+#include <string.h>
+
+#define MESSAGE ": warning: this program uses setruid, which doesn't do anything\r\n(but used to)\r\n"
int
#ifdef __STDC__
@@ -45,6 +50,12 @@ setruid(ruid)
int ruid;
#endif
{
-
+ extern char *__progname;
+ write(2, __progname, strlen(__progname));
+ write(2, MESSAGE, sizeof(MESSAGE) - 1);
return (setreuid(ruid, -1));
}
+
+asm(".stabs \"warning: setruid function referenced\", 30, 0, 0, 0");
+asm(".stabs \"_setruid\", 1, 0, 0, 0");
+
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c
index e9b25831d20e..c6a52d738973 100644
--- a/lib/libc/db/hash/hash.c
+++ b/lib/libc/db/hash/hash.c
@@ -433,6 +433,8 @@ hdestroy(hashp)
if (hashp->fp != -1)
(void)close(hashp->fp);
+ free(hashp);
+
if (save_errno) {
errno = save_errno;
return (ERROR);
diff --git a/lib/libc/db/recno/rec_open.c b/lib/libc/db/recno/rec_open.c
index f05a44bb0026..514e9811f91a 100644
--- a/lib/libc/db/recno/rec_open.c
+++ b/lib/libc/db/recno/rec_open.c
@@ -160,7 +160,7 @@ slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
else {
t->bt_msize = sb.st_size;
if ((t->bt_smap = mmap(NULL, t->bt_msize,
- PROT_READ, MAP_PRIVATE, rfd,
+ PROT_READ, MAP_FILE|MAP_PRIVATE, rfd,
(off_t)0)) == (caddr_t)-1)
goto slow;
t->bt_cmap = t->bt_smap;
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 0f0a66405d13..3b54c31a5d12 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -8,10 +8,10 @@ SRCS+= alarm.c assert.c clock.c crypt.c ctermid.c ctime.c ctype_.c \
fnmatch.c frexp.c fstab.c fts.c getcap.c getcwd.c getgrent.c \
getlogin.c getmntinfo.c getpass.c getpwent.c getsubopt.c getttyent.c \
getusershell.c glob.c infinity.c initgroups.c insque.c isatty.c \
- isctype.c isinf.c mktemp.c msgctl.c msgget.c msgsnd.c msgrcv.c \
+ isinf.c mktemp.c msgctl.c msgget.c msgsnd.c msgrcv.c \
nice.c nlist.c pause.c popen.c psignal.c raise.c scandir.c \
semconfig.c semctl.c semget.c semop.c \
- setjmperr.c setmode.c setrgid.c setruid.c \
+ setjmperr.c setmode.c \
shmat.c shmctl.c shmdt.c shmget.c \
siginterrupt.c siglist.c signal.c sigsetops.c sleep.c syslog.c \
termios.c time.c times.c timezone.c ttyname.c ttyslot.c \
@@ -27,7 +27,9 @@ SRCS+= adddf3.s addsf3.s ashlsi3.s ashrsi3.s cmpdf2.s cmpsf2.s divdf3.s \
umodsi3.s umulsi3.s
.elif (${MACHINE} == "i386")
SRCS+= _setjmp.S alloca.S fabs.S ldexp.c modf.S setjmp.S sigsetjmp.S
+.if defined (GCC1_IN_LIBC)
SRCS+= divsi3.S fixdfsi.S fixunsdfsi.S udivsi3.S
+.endif
.elif (${MACHINE} == "tahoe")
CFLAGS+=-I/sys
SRCS+= _setjmp.s alloca.s fabs.s ldexp.s modf.s setjmp.s
@@ -36,6 +38,9 @@ SRCS+= udiv.s urem.s
SRCS+= _setjmp.s alloca.s fabs.s ldexp.s modf.s setjmp.s
SRCS+= udiv.s urem.s
.endif
+.if defined (PW_COMPACT)
+CFLAGS+=-DPW_COMPACT
+.endif
MAN3+= gen/alarm.3 gen/clock.3 gen/crypt.3 gen/ctermid.3 gen/ctime.3 \
gen/ctype.3 gen/directory.3 gen/err.3 gen/exec.3 gen/fnmatch.3 \
@@ -47,7 +52,7 @@ MAN3+= gen/alarm.3 gen/clock.3 gen/crypt.3 gen/ctermid.3 gen/ctime.3 \
gen/islower.3 gen/isprint.3 gen/ispunct.3 gen/isspace.3 \
gen/isupper.3 gen/isxdigit.3 gen/ldexp.3 gen/modf.3 gen/nice.3 \
gen/nlist.3 gen/pause.3 gen/popen.3 gen/psignal.3 gen/raise.3 \
- gen/scandir.3 gen/setjmp.3 gen/setmode.3 gen/setuid.3 \
+ gen/scandir.3 gen/setjmp.3 gen/setmode.3 \
gen/siginterrupt.3 gen/signal.3 gen/sigsetops.3 gen/sleep.3 \
gen/syslog.3 gen/tcgetpgrp.3 gen/tcsendbreak.3 gen/tcsetattr.3 \
gen/tcsetpgrp.3 gen/time.3 gen/times.3 gen/timezone.3 gen/tolower.3 \
@@ -86,8 +91,6 @@ MLINKS+=scandir.3 alphasort.3
MLINKS+=setjmp.3 _longjmp.3 setjmp.3 _setjmp.3 setjmp.3 longjmp.3 \
setjmp.3 sigsetjmp.3 setjmp.3 siglongjmp.3 setjmp.3 longjmperror.3
MLINKS+=setmode.3 getmode.3
-MLINKS+=setuid.3 setegid.3 setuid.3 seteuid.3 setuid.3 setgid.3 \
- setuid.3 setrgid.3 setuid.3 setruid.3
MLINKS+=sigsetops.3 sigemptyset.3 sigsetops.3 sigfillset.3 \
sigsetops.3 sigaddset.3 sigsetops.3 sigdelset.3 \
sigsetops.3 sigismember.3
diff --git a/lib/libc/gen/ctype_.c b/lib/libc/gen/ctype_.c
index d361c1617cea..0f06fe2b8123 100644
--- a/lib/libc/gen/ctype_.c
+++ b/lib/libc/gen/ctype_.c
@@ -5,7 +5,7 @@
* or UNIX System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
- * $Id: ctype_.c,v 1.1.1.1.2.1 1994/05/04 07:39:42 rgrimes Exp $
+ * $Id: ctype_.c,v 1.3 1994/05/04 08:17:14 rgrimes Exp $
*/
/*
* Copyright (c) 1989 The Regents of the University of California.
@@ -41,10 +41,12 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)ctype_.c 5.6 (Berkeley) 6/1/90";
+static char sccsid[] = "From: @(#)ctype_.c 5.6 (Berkeley) 6/1/90";
+static const char rcsid[] =
+ "$Id: ctype_.c,v 1.3 1994/05/04 08:17:14 rgrimes Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <ctype.h>
+#include <octype.h>
char _ctype_[1 + 256] = {
0,
diff --git a/lib/libc/gen/getcap.3 b/lib/libc/gen/getcap.3
index d18b3797bc7e..a2cf2665d0d4 100644
--- a/lib/libc/gen/getcap.3
+++ b/lib/libc/gen/getcap.3
@@ -33,7 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)getcap.3 5.4 (Berkeley) 8/11/92
-.\" $Id: getcap.3,v 1.1.2.1 1994/05/01 16:05:00 jkh Exp $
+.\" $Id: getcap.3,v 1.2 1994/04/17 09:16:14 alm Exp $
.\"
.Dd "August 11, 1992"
.Dt GETCAP 3
diff --git a/lib/libc/gen/getcap.c b/lib/libc/gen/getcap.c
index 7f70789450fd..647a5bff41a7 100644
--- a/lib/libc/gen/getcap.c
+++ b/lib/libc/gen/getcap.c
@@ -35,7 +35,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getcap.c 5.15 (Berkeley) 3/19/93";
+/*static char *sccsid = "from: @(#)getcap.c 5.15 (Berkeley) 3/19/93";*/
+static char *rcsid = "$Id: getcap.c,v 1.2 1994/04/17 09:16:16 alm Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
@@ -194,8 +195,8 @@ getent(cap, len, db_array, fd, name, depth, nfield)
DB *capdbp;
DBT key, data;
register char *r_end, *rp, **db_p;
- int myfd, eof, foundit, retval;
- char *record;
+ int myfd, eof, foundit, retval, clen;
+ char *record, *cbuf;
int tc_not_resolved;
char pbuf[_POSIX_PATH_MAX];
@@ -250,11 +251,21 @@ getent(cap, len, db_array, fd, name, depth, nfield)
!= NULL) {
free(record);
retval = cdbget(capdbp, &record, name);
- if (capdbp->close(capdbp) < 0)
+ if (retval < 0) {
+ /* no record available */
+ (void)capdbp->close(capdbp);
+ return (retval);
+ }
+ /* save the data; close frees it */
+ clen = strlen(record);
+ cbuf = malloc(clen + 1);
+ memcpy(cbuf, record, clen + 1);
+ if (capdbp->close(capdbp) < 0) {
+ free(cbuf);
return (-2);
- *len = strlen(record);
- *cap = malloc(*len + 1);
- memmove(*cap, record, *len + 1);
+ }
+ *len = clen;
+ *cap = cbuf;
return (retval);
} else {
fd = open(*db_p, O_RDONLY, 0);
@@ -657,7 +668,7 @@ cgetnext(bp, db_array)
gottoprec = 1;
line = toprec;
} else {
- line = fgetline(pfp, &len);
+ line = fgetln(pfp, &len);
if (line == NULL && pfp) {
(void)fclose(pfp);
if (ferror(pfp)) {
@@ -716,7 +727,7 @@ cgetnext(bp, db_array)
*np = '\0';
break;
} else { /* name field extends beyond the line */
- line = fgetline(pfp, &len);
+ line = fgetln(pfp, &len);
if (line == NULL && pfp) {
(void)fclose(pfp);
if (ferror(pfp)) {
diff --git a/lib/libc/gen/getfsent.3 b/lib/libc/gen/getfsent.3
index 16847ed0b5f7..e29ed40724df 100644
--- a/lib/libc/gen/getfsent.3
+++ b/lib/libc/gen/getfsent.3
@@ -43,7 +43,7 @@
.Nd get file system descriptor file entry
.Sh SYNOPSIS
.Fd #include <fstab.h>
-.Ft fstab *
+.Ft struct fstab *
.Fn getfsent void
.Ft struct fstab *
.Fn getfsspec "const char *spec"
diff --git a/lib/libc/gen/getmntinfo.3 b/lib/libc/gen/getmntinfo.3
index 6119c6a4b2b7..689a28e3ddbf 100644
--- a/lib/libc/gen/getmntinfo.3
+++ b/lib/libc/gen/getmntinfo.3
@@ -41,7 +41,7 @@
.Fd #include <sys/types.h>
.Fd #include <sys/mount.h>
.Ft int
-.Fn getmntinfo "int mntbufp" "int flags"
+.Fn getmntinfo "int *mntbufp" "int flags"
.Sh DESCRIPTION
The
.Fn getmntinfo
diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3
index 6d0b9194bb0b..7963afab91e6 100644
--- a/lib/libc/gen/getpwent.3
+++ b/lib/libc/gen/getpwent.3
@@ -200,6 +200,20 @@ and
.Fn setpwent
are fairly useless in a networked environment and should be
avoided, if possible.
+.Pp
+Standard database make routines are slow especially for big passwd
+files. Moreover, *pwd.db bases are too big and waste root space.
+You can have much faster routines with small *pwd.db,
+but loose binary compatibility
+with previous versions and with other BSD-like systems.
+If you want to setup much faster routines, define
+.B PW_COMPACT
+envirnoment variable (f.e. 'setenv PW_COMPACT' in csh) and use
+.I bootstrappwd
+target into /usr/src/Makefile.
+If you will want to return this changes back, use the same target
+without defining
+.BR PW_COMPACT .
.Sh COMPATIBILITY
The historic function
.Xr setpwfile 3 ,
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
index 93a09ee52ff6..96ae370c761c 100644
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -33,7 +33,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)getpwent.c 5.21 (Berkeley) 3/14/91";*/
-static char *rcsid = "$Id: getpwent.c,v 1.4 1994/01/11 19:00:58 nate Exp $";
+static char *rcsid = "$Id: getpwent.c,v 1.9 1994/05/05 18:16:44 ache Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@@ -54,8 +54,14 @@ static char *rcsid = "$Id: getpwent.c,v 1.4 1994/01/11 19:00:58 nate Exp $";
#include <rpcsvc/ypclnt.h>
#endif
+/* #define PW_COMPACT */
+/* Compact pwd.db/spwd.db structure by Alex G. Bulushev, bag@demos.su */
+
static struct passwd _pw_passwd; /* password structure */
static DB *_pw_db; /* password database */
+#ifdef PW_COMPACT
+static DB *_spw_db; /* shadow password database */
+#endif
static int _pw_keynum; /* key counter */
static int _pw_stayopen; /* keep fd's open */
static int __hashpw(), __initdb();
@@ -260,6 +266,12 @@ getpwnam(name)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return &_pw_passwd;
}
@@ -268,6 +280,12 @@ getpwnam(name)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return (struct passwd *)NULL;
}
@@ -283,6 +301,12 @@ getpwnam(name)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return(rval ? &_pw_passwd : (struct passwd *)NULL);
}
@@ -355,6 +379,12 @@ getpwuid(uid)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return &_pw_passwd;
}
@@ -363,6 +393,12 @@ getpwuid(uid)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return (struct passwd *)NULL;
}
@@ -378,6 +414,12 @@ getpwuid(uid)
if (!_pw_stayopen) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
return(rval ? &_pw_passwd : (struct passwd *)NULL);
}
@@ -410,6 +452,12 @@ endpwent()
if (_pw_db) {
(void)(_pw_db->close)(_pw_db);
_pw_db = (DB *)NULL;
+#ifdef PW_COMPACT
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#endif
}
#ifdef YP
__ypmode = 0;
@@ -425,12 +473,30 @@ __initdb()
static int warned;
char *p;
+#ifdef PW_COMPACT
+ if (!geteuid()) {
+ _spw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (!_spw_db && !warned)
+ syslog(LOG_ERR, "%s: %m", _PATH_SMP_DB);
+ }
+ _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (_pw_db)
+ return(1);
+ if (!warned)
+ syslog(LOG_ERR, "%s: %m", _PATH_MP_DB);
+ if (_spw_db) {
+ (void)(_spw_db->close)(_spw_db);
+ _spw_db = (DB *)NULL;
+ }
+#else
p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
if (_pw_db)
return(1);
if (!warned)
syslog(LOG_ERR, "%s: %m", p);
+#endif
+ warned = 1;
return(0);
}
@@ -442,9 +508,26 @@ __hashpw(key)
static u_int max;
static char *line;
DBT data;
+#ifdef PW_COMPACT
+ DBT _key, *__key;
+ char bf[sizeof(_pw_keynum) + 1];
+#endif
if ((_pw_db->get)(_pw_db, key, &data, 0))
return(0);
+#ifdef PW_COMPACT
+ __key = key;
+ if (((char *)(*__key).data)[0] != _PW_KEYBYNUM) {
+ if (data.size != sizeof(_pw_keynum)) return(0);
+ bf[0] = _PW_KEYBYNUM;
+ bcopy(data.data, bf + 1, sizeof(_pw_keynum));
+ _key.data = (u_char *)bf;
+ _key.size = sizeof(_pw_keynum) + 1;
+ __key = (DBT *)&_key;
+ if ((_pw_db->get)(_pw_db, __key, &data, 0))
+ return(0);
+ }
+#endif
p = (char *)data.data;
if (data.size > max && !(line = realloc(line, max += 1024)))
return(0);
@@ -452,7 +535,9 @@ __hashpw(key)
t = line;
#define EXPAND(e) e = t; while (*t++ = *p++);
EXPAND(_pw_passwd.pw_name);
+#ifndef PW_COMPACT
EXPAND(_pw_passwd.pw_passwd);
+#endif
bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
p += sizeof(int);
bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
@@ -465,5 +550,11 @@ __hashpw(key)
EXPAND(_pw_passwd.pw_shell);
bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
p += sizeof(time_t);
+#ifdef PW_COMPACT
+ if (_spw_db && !(_spw_db->get)(_spw_db, __key, &data, 0))
+ p = (char *)data.data;
+ else p = "*";
+ EXPAND(_pw_passwd.pw_passwd);
+#endif
return(1);
}
diff --git a/lib/libc/gen/semconfig.c b/lib/libc/gen/semconfig.c
index 66fbb2d93398..cf5399b6dde4 100644
--- a/lib/libc/gen/semconfig.c
+++ b/lib/libc/gen/semconfig.c
@@ -5,7 +5,7 @@
#if __STDC__
int semconfig(int cmd, int p1, int p2, int p3)
#else
-int semctl(cmd, p1, p2, p3)
+int semconfig(cmd, p1, p2, p3)
int cmd, p1, p2, p3;
#endif
{
diff --git a/lib/libc/gen/setmode.c b/lib/libc/gen/setmode.c
index 12f7c1ab1ca7..9858beaa4a06 100644
--- a/lib/libc/gen/setmode.c
+++ b/lib/libc/gen/setmode.c
@@ -215,6 +215,7 @@ setmode(p)
mode_t mask;
struct bitcmd *set, *saveset, *endset;
int permXbits, setlen;
+ int equalopdone;
static void compress_mode();
/*
@@ -285,6 +286,8 @@ setmode(p)
free(saveset);
return(NULL);
}
+ if(op == '=')
+ equalopdone = 0;
who &= ~S_ISTXT;
for (perm = 0, permXbits = 0;; ++p) {
@@ -321,10 +324,12 @@ setmode(p)
* to flush out any partial mode that we have,
* and then do the copying of the mode bits.
*/
- if (perm || op == '=') {
+ if (perm) {
ADDCMD(op, who, perm, mask);
perm = 0;
}
+ if (op == '=')
+ equalopdone = 1;
if (op == '+' && permXbits) {
ADDCMD('X', who, permXbits, mask);
permXbits = 0;
@@ -337,7 +342,9 @@ setmode(p)
* Add any permissions that we haven't already
* done.
*/
- if (perm || op == '=') {
+ if (perm || (op == '=' && !equalopdone)) {
+ if(op == '=')
+ equalopdone = 1;
ADDCMD(op, who, perm, mask);
perm = 0;
}
diff --git a/lib/libc/i386/DEFS.h b/lib/libc/i386/DEFS.h
index 4b4df3e68ccb..6df18a13def7 100644
--- a/lib/libc/i386/DEFS.h
+++ b/lib/libc/i386/DEFS.h
@@ -35,7 +35,7 @@
*
* from: @(#)DEFS.h 5.1 (Berkeley) 4/23/90
*
- * $Id: DEFS.h,v 1.3.2.1 1994/05/04 08:44:15 rgrimes Exp $
+ * $Id: DEFS.h,v 1.4 1994/05/03 16:29:13 jkh Exp $
*/
/* XXX should use align 4,0x90 for -m486. */
diff --git a/lib/libc/i386/string/bcmp.S b/lib/libc/i386/string/bcmp.S
index 21027dadd8b4..d19922498d88 100644
--- a/lib/libc/i386/string/bcmp.S
+++ b/lib/libc/i386/string/bcmp.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: bcmp.S,v 1.1 1993/12/05 13:01:40 ats Exp $
+ * $Id: bcmp.S,v 1.2 1994/03/31 14:10:57 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: bcmp.S,v 1.1 1993/12/05 13:01:40 ats Exp $"
+ .asciz "$Id: bcmp.S,v 1.2 1994/03/31 14:10:57 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -48,17 +48,16 @@ ENTRY(bcmp)
pushl %esi
movl 12(%esp),%edi
movl 16(%esp),%esi
- movl 20(%esp),%edx
xorl %eax,%eax /* clear return value */
cld /* set compare direction forward */
- movl %edx,%ecx /* compare by words */
+ movl 20(%esp),%ecx /* compare by words */
shrl $2,%ecx
repe
cmpsl
jne L1
- movl %edx,%ecx /* compare remainder by bytes */
+ movl 20(%esp),%ecx /* compare remainder by bytes */
andl $3,%ecx
repe
cmpsb
diff --git a/lib/libc/i386/string/memcmp.S b/lib/libc/i386/string/memcmp.S
index e1fdaaa31f6e..5e74a7373235 100644
--- a/lib/libc/i386/string/memcmp.S
+++ b/lib/libc/i386/string/memcmp.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: memcmp.S,v 1.1.2.1 1994/03/07 02:19:34 rgrimes Exp $
+ * $Id: memcmp.S,v 1.3 1994/03/31 14:10:59 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: memcmp.S,v 1.1.2.1 1994/03/07 02:19:34 rgrimes Exp $"
+ .asciz "$Id: memcmp.S,v 1.3 1994/03/31 14:10:59 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -48,16 +48,15 @@ ENTRY(memcmp)
pushl %esi
movl 12(%esp),%edi
movl 16(%esp),%esi
- movl 20(%esp),%edx
cld /* set compare direction forward */
- movl %edx,%ecx /* compare by words */
+ movl 20(%esp),%ecx /* compare by words */
shrl $2,%ecx
repe
cmpsl
jne L5 /* do we match so far? */
- movl %edx,%ecx /* compare remainder by bytes */
+ movl 20(%esp),%ecx /* compare remainder by bytes */
andl $3,%ecx
repe
cmpsb
@@ -73,8 +72,8 @@ L5: movl $4,%ecx /* We know that one of the next */
subl %ecx,%esi /* match. */
repe
cmpsb
-L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */
- movzbl -1(%esi),%edx
+L6: movzbl -1(%edi),%eax /* Perform unsigned comparison */
+ movzbl -1(%esi),%edx
subl %edx,%eax
popl %esi
popl %edi
diff --git a/lib/libc/i386/string/memmove.S b/lib/libc/i386/string/memmove.S
index 57e52ad04295..7eeec5bd8c21 100644
--- a/lib/libc/i386/string/memmove.S
+++ b/lib/libc/i386/string/memmove.S
@@ -32,11 +32,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: memmove.S,v 1.1 1993/12/05 13:01:50 ats Exp $
+ * $Id: memmove.S,v 1.2 1994/03/31 14:11:00 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: memmove.S,v 1.1 1993/12/05 13:01:50 ats Exp $"
+ .asciz "$Id: memmove.S,v 1.2 1994/03/31 14:11:00 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -51,20 +51,19 @@ ENTRY(memmove)
pushl %esi
pushl %edi
movl 12(%esp),%edi
- pushl %edi
- movl 20(%esp),%esi
- movl 24(%esp),%ecx
+ movl 16(%esp),%esi
+ movl 20(%esp),%ecx
cmpl %esi,%edi /* potentially overlapping? */
jnb 1f
cld /* nope, copy forwards. */
shrl $2,%ecx /* copy by words */
rep
movsl
- movl 24(%esp),%ecx
+ movl 20(%esp),%ecx
andl $3,%ecx /* any bytes left? */
rep
movsb
- popl %eax
+ movl 12(%esp),%eax
popl %edi
popl %esi
ret
@@ -77,13 +76,13 @@ ENTRY(memmove)
decl %esi
rep
movsb
- movl 24(%esp),%ecx /* copy remainder by words */
+ movl 20(%esp),%ecx /* copy remainder by words */
shrl $2,%ecx
subl $3,%esi
subl $3,%edi
rep
movsl
- popl %eax
+ movl 12(%esp),%eax
popl %edi
popl %esi
cld
diff --git a/lib/libc/i386/string/memset.S b/lib/libc/i386/string/memset.S
index 47e763781932..b7fc069da3c5 100644
--- a/lib/libc/i386/string/memset.S
+++ b/lib/libc/i386/string/memset.S
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: memset.S,v 1.1 1993/12/05 13:01:53 ats Exp $
+ * $Id: memset.S,v 1.2 1994/03/31 14:11:01 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: memset.S,v 1.1 1993/12/05 13:01:53 ats Exp $"
+ .asciz "$Id: memset.S,v 1.2 1994/03/31 14:11:01 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
@@ -57,17 +57,15 @@ ENTRY(memset)
/*
* if the string is too short, it's really not worth the overhead
- * of aligning to word boundries, etc. So we jump to a plain
+ * of aligning to word boundries, etc. So we jump to a plain
* unaligned set.
*/
cmpl $0x0f,%ecx
jle L1
- movl %eax,%edx /* copy value to all bytes in word */
- sall $8,%edx /* XXX is there a better way? */
- orl %edx,%eax
+ movb %al,%ah /* copy char to all bytes in word */
movl %eax,%edx
- sall $16,%edx
+ sall $16,%eax
orl %edx,%eax
movl %edi,%edx /* compute misalignment */
@@ -75,7 +73,7 @@ ENTRY(memset)
andl $3,%edx
movl %ecx,%ebx
subl %edx,%ebx
-
+
movl %edx,%ecx /* set until word aligned */
rep
stosb
diff --git a/lib/libc/i386/string/strcmp.S b/lib/libc/i386/string/strcmp.S
index 015c21aa7fa3..bdc4585aed2f 100644
--- a/lib/libc/i386/string/strcmp.S
+++ b/lib/libc/i386/string/strcmp.S
@@ -27,11 +27,11 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: strcmp.S,v 1.1.2.1 1994/03/07 02:19:31 rgrimes Exp $
+ * $Id: strcmp.S,v 1.2 1994/03/04 15:50:28 ache Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: strcmp.S,v 1.1.2.1 1994/03/07 02:19:31 rgrimes Exp $"
+ .asciz "$Id: strcmp.S,v 1.2 1994/03/04 15:50:28 ache Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
diff --git a/lib/libc/i386/string/strncmp.S b/lib/libc/i386/string/strncmp.S
index 72922fb30fec..a4df8025bfb5 100644
--- a/lib/libc/i386/string/strncmp.S
+++ b/lib/libc/i386/string/strncmp.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1993 Winning Strategies, Inc.
+ * Copyright (c) 1993,94 Winning Strategies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -14,7 +14,7 @@
* must display the following acknowledgement:
* This product includes software developed by Winning Strategies, Inc.
* 4. The name of the author may not be used to endorse or promote products
- * derived from this software withough specific prior written permission
+ * derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -27,20 +27,20 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: strncmp.S,v 1.1.2.1 1994/03/07 02:19:33 rgrimes Exp $
+ * $Id: strncmp.S,v 1.3 1994/03/31 14:11:02 davidg Exp $
*/
#if defined(LIBC_RCS) && !defined(lint)
- .asciz "$Id: strncmp.S,v 1.1.2.1 1994/03/07 02:19:33 rgrimes Exp $"
+ .asciz "$Id: strncmp.S,v 1.3 1994/03/31 14:11:02 davidg Exp $"
#endif /* LIBC_RCS and not lint */
#include "DEFS.h"
/*
- * strncmp(s1, s2, n)
- * return an integer greater than, equal to, or less than 0,
+ * strncmp(s1, s2, n)
+ * return an integer greater than, equal to, or less than 0,
* according as the first n characters of string s1 is greater
- * than, equal to, or less than the string s2.
+ * than, equal to, or less than the string s2.
*
* %eax - pointer to s1
* %ecx - pointer to s2
@@ -53,7 +53,7 @@
/*
* I've unrolled the loop eight times: large enough to make a
* significant difference, and small enough not to totally trash the
- * cashe.
+ * cache.
*/
ENTRY(strncmp)
@@ -61,92 +61,93 @@ ENTRY(strncmp)
movl 8(%esp),%eax
movl 12(%esp),%ecx
movl 16(%esp),%edx
+ testl %edx,%edx
jmp L2 /* Jump into the loop! */
.align 2,0x90
L1: incl %eax
incl %ecx
decl %edx
-L2: testl %edx,%edx /* Have we compared n chars yet? */
- jle L4 /* Yes, strings are equal */
+L2: jz L4 /* strings are equal */
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
jne L3
+
incl %eax
incl %ecx
decl %edx
- testl %edx,%edx
- jle L4
+ jz L4
movb (%eax),%bl
testb %bl,%bl
- je L3
+ jz L3
cmpb %bl,(%ecx)
je L1
+
.align 2,0x90
-L3: movzbl (%eax),%eax /* unsigned comparision */
- movzbl (%ecx),%ecx
+L3: movzbl (%eax),%eax /* unsigned comparision */
+ movzbl (%ecx),%ecx
subl %ecx,%eax
popl %ebx
ret
diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc
index 855608475d59..aa9d8bb14b56 100644
--- a/lib/libc/locale/Makefile.inc
+++ b/lib/libc/locale/Makefile.inc
@@ -1,6 +1,20 @@
-# @(#)Makefile.inc 5.1 (Berkeley) 2/18/91
+# From: @(#)Makefile.inc 5.1 (Berkeley) 2/18/91
+# $Id: Makefile.inc,v 1.5 1994/04/13 20:12:15 wollman Exp $
# locale sources
.PATH: ${.CURDIR}/${MACHINE}/locale ${.CURDIR}/locale
-SRCS+= lconv.c localeconv.c setlocale.c
+SRCS+= ansi.c frune.c mbrune.c lconv.c localeconv.c rune.c setlocale.c \
+ table.c isctype.c \
+ euc.c none.c utf2.c
+MAN3+= locale/mbrune.3 locale/multibyte.3 locale/rune.3 locale/setlocale.3
+MAN4+= locale/euc.4 locale/utf2.4
+
+MLINKS+= mbrune.3 mbrrune.3 mbrune.3 mbmb.3
+MLINKS+= multibyte.3 mblen.3 multibyte.3 mbstowcs.3 \
+ multibyte.3 mbtowc.3 multibyte.3 wcstombs.3 \
+ multibyte.3 wctomb.3
+MLINKS+= rune.3 setrunelocale.3 rune.3 setinvalidrune.3 \
+ rune.3 sgetrune.3 rune.3 sputrune.3
+MLINKS+= setlocale.3 localeconv.3
+MLINKS+= utf2.4 utf8.4
diff --git a/lib/libc/locale/ansi.c b/lib/libc/locale/ansi.c
new file mode 100644
index 000000000000..e5c8e8ff96de
--- /dev/null
+++ b/lib/libc/locale/ansi.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)ansi.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <stddef.h>
+#include <rune.h>
+
+int
+mblen(s, n)
+ const char *s;
+ size_t n;
+{
+ char const *e;
+
+ if (s == 0 || *s == 0)
+ return (0); /* No support for state dependent encodings. */
+
+ if (sgetrune(s, (int)n, &e) == _INVALID_RUNE)
+ return (s - e);
+ return (e - s);
+}
+
+int
+mbtowc(pwc, s, n)
+ wchar_t *pwc;
+ const char *s;
+ size_t n;
+{
+ char const *e;
+ rune_t r;
+
+ if (s == 0 || *s == 0)
+ return (0); /* No support for state dependent encodings. */
+
+ if ((r = sgetrune(s, (int)n, &e)) == _INVALID_RUNE)
+ return (s - e);
+ if (pwc)
+ *pwc = r;
+ return (e - s);
+}
+
+int
+wctomb(s, wchar)
+ char *s;
+ wchar_t wchar;
+{
+ char *e;
+
+ if (s == 0)
+ return (0); /* No support for state dependent encodings. */
+
+ if (wchar == 0) {
+ *s = 0;
+ return (1);
+ }
+
+ sputrune(wchar, s, MB_CUR_MAX, &e);
+ return (e ? e - s : -1);
+}
+
+size_t
+mbstowcs(pwcs, s, n)
+ wchar_t *pwcs;
+ const char *s;
+ size_t n;
+{
+ char const *e;
+ int cnt = 0;
+
+ if (!pwcs || !s)
+ return (-1);
+
+ while (n-- > 0) {
+ *pwcs = sgetrune(s, MB_LEN_MAX, &e);
+ if (*pwcs == _INVALID_RUNE)
+ return (-1);
+ if (*pwcs++ == 0)
+ break;
+ s = e;
+ ++cnt;
+ }
+ return (cnt);
+}
+
+size_t
+wcstombs(s, pwcs, n)
+ char *s;
+ const wchar_t *pwcs;
+ size_t n;
+{
+ char *e;
+ int cnt = 0;
+
+ if (!pwcs || !s)
+ return (-1);
+
+ while (n > 0) {
+ if (*pwcs == 0) {
+ *s = 0;
+ break;
+ }
+ if (!sputrune(*pwcs++, s, (int)n, &e))
+ return (-1); /* encoding error */
+ if (!e) /* too long */
+ return (cnt);
+ cnt += e - s;
+ s = e;
+ }
+ return (cnt);
+}
diff --git a/lib/libc/locale/euc.4 b/lib/libc/locale/euc.4
new file mode 100644
index 000000000000..966b896b657f
--- /dev/null
+++ b/lib/libc/locale/euc.4
@@ -0,0 +1,231 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)euc.4 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt EUC 4
+.Os
+.Sh NAME
+.Nm EUC
+.Nd EUC encoding of runes
+.Sh SYNOPSIS
+\fBENCODING "EUC"\fP
+.br
+\fBVARIABLE \fP\fIlen1 mask1 len2 mask2 len3 mask3 len4 mask4 mask\fP
+.Sh DESCRIPTION
+The
+.Nm EUC
+encoding is provided for compatibility with
+.Ux
+based systems.
+See
+.Xr mklocale 1
+for a complete description of the
+.Ev LC_CTYPE
+source file format.
+.Pp
+.Nm EUC
+implements a system of 4 multibyte codesets.
+A multibyte character in the first codeset consists of
+.Ar len1
+bytes starting with a byte in the range of 0x00 to 0x7f.
+To allow use of ASCII,
+.Ar len1
+is always 1.
+A multibyte character in the second codeset consists of
+.Ar len2
+bytes starting with a byte in the range of 0x80-0xff excluding 0x8e and 0x8f.
+A multibyte character in the third codeset consists of
+.Ar len3
+bytes starting with the byte 0x8e.
+A multibyte character in the fourth codeset consists of
+.Ar len4
+bytes starting with the byte 0x8f.
+.Pp
+The
+.Ev rune_t
+encoding of
+.Nm EUC
+multibyte characters is dependent on the
+.Ar len
+and
+.Ar mask
+arguments.
+First, the bytes are moved into a
+.Ev rune_t
+as follows:
+.Bd -literal
+byte0 << ((\fIlen\fPN-1) * 8) | byte1 << ((\fIlen\fPN-2) * 8) | ... | byte\fIlen\fPN-1
+.Ed
+.sp
+The result is then ANDed with
+.Ar ~mask
+and ORed with
+.Ar mask\fPN.
+Codesets 2 and 3 are special in that the leading byte (0x8e or 0x8f) is
+first removed and the
+.Ar len\fPN
+argument is reduced by 1.
+.sp
+For example, the Japanese locale has the following
+.Ev VARIABLE
+line:
+.Bd -literal
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+.Ed
+.sp
+Codeset 1 consists of the values 0x0000 - 0x007f.
+.sp
+Codeset 2 consists of the values who have the bits 0x8080 set.
+.sp
+Codeset 3 consists of the values 0x0080 - 0x00ff.
+.sp
+Codeset 4 consists of the values 0x8000 - 0xff7f excluding the values
+which have the 0x0080 bit set.
+.sp
+Notice that the global
+.Ar mask
+is set to 0x8080, this implies that from those 2 bits the codeset can
+be determined.
+.Sh "EXAMPLE - Japanese Locale"
+This is a complete example of an
+.Ev LC_CTYPE
+source file for the Japanese locale
+.Bd -literal
+/*
+ * Japanese LOCALE_CTYPE definitions using EUC of JIS character sets
+ */
+
+ENCODING "EUC"
+
+/* JIS JIS JIS */
+/* X201 X208 X201 */
+/* 00-7f 84-fe */
+
+VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
+
+/*
+ * Code Set 1
+ */
+ALPHA 'A' - 'Z' 'a' - 'z'
+CONTROL 0x00 - 0x1f 0x7f
+DIGIT '0' - '9'
+GRAPH 0x21 - 0x7e
+LOWER 'a' - 'z'
+PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
+SPACE 0x09 - 0x0d 0x20
+UPPER 'A' - 'Z'
+XDIGIT 'a' - 'f' 'A' - 'F'
+BLANK ' ' '\t'
+PRINT 0x20 - 0x7e
+
+MAPLOWER < 'A' - 'Z' : 'a' > < 'a' - 'z' : 'a' >
+MAPUPPER < 'A' - 'Z' : 'A' > < 'a' - 'z' : 'A' >
+TODIGIT < '0' - '9' : 0 >
+TODIGIT < 'A' - 'F' : 10 > < 'a' - 'f' : 10 >
+
+/*
+ * Code Set 2
+ */
+
+SPACE 0xa1a1
+PHONOGRAM 0xa1bc
+SPECIAL 0xa1a2 - 0xa1fe
+PUNCT 0xa1a2 - 0xa1f8 /* A few too many in here... */
+
+SPECIAL 0xa2a1 - 0xa2ae 0xa2ba - 0xa2c1 0xa2ca - 0xa2d0 0xa2dc - 0xa2ea
+SPECIAL 0xa2f2 - 0xa2f9 0xa2fe
+
+DIGIT 0xa3b0 - 0xa3b9
+UPPER 0xa3c1 - 0xa3da /* Romaji */
+LOWER 0xa3e1 - 0xa3fa /* Romaji */
+MAPLOWER < 0xa3c1 - 0xa3da : 0xa3e1 > /* English */
+MAPLOWER < 0xa3e1 - 0xa3fa : 0xa3e1 > /* English */
+MAPUPPER < 0xa3c1 - 0xa3da : 0xa3c1 >
+MAPUPPER < 0xa3e1 - 0xa3fa : 0xa3c1 >
+
+XDIGIT 0xa3c1 - 0xa3c6 0xa3e1 - 0xa3e6
+
+TODIGIT < 0xa3b0 - 0xa3b9 : 0 >
+TODIGIT < 0xa3c1 - 0xa3c6 : 10 > < 0xa3e1 - 0xa3e6 : 10 >
+
+PHONOGRAM 0xa4a1 - 0xa4f3
+PHONOGRAM 0xa5a1 - 0xa5f6
+
+UPPER 0xa6a1 - 0xa6b8 /* Greek */
+LOWER 0xa6c1 - 0xa6d8 /* Greek */
+MAPLOWER < 0xa6a1 - 0xa6b8 : 0xa6c1 > < 0xa6c1 - 0xa6d8 : 0xa6c1 >
+MAPUPPER < 0xa6a1 - 0xa6b8 : 0xa6a1 > < 0xa6c1 - 0xa6d8 : 0xa6a1 >
+
+UPPER 0xa7a1 - 0xa7c1 /* Cyrillic */
+LOWER 0xa7d1 - 0xa7f1 /* Cyrillic */
+MAPLOWER < 0xa7a1 - 0xa7c1 : 0xa7d1 > < 0xa7d1 - 0xa7f1 : 0xa7d1 >
+MAPUPPER < 0xa7a1 - 0xa7c1 : 0xa7a1 > < 0xa7d1 - 0xa7f1 : 0xa7a1 >
+
+SPECIAL 0xa8a1 - 0xa8c0
+
+IDEOGRAM 0xb0a1 - 0xb0fe 0xb1a1 - 0xb1fe 0xb2a1 - 0xb2fe
+IDEOGRAM 0xb3a1 - 0xb3fe 0xb4a1 - 0xb4fe 0xb5a1 - 0xb5fe
+IDEOGRAM 0xb6a1 - 0xb6fe 0xb7a1 - 0xb7fe 0xb8a1 - 0xb8fe
+IDEOGRAM 0xb9a1 - 0xb9fe 0xbaa1 - 0xbafe 0xbba1 - 0xbbfe
+IDEOGRAM 0xbca1 - 0xbcfe 0xbda1 - 0xbdfe 0xbea1 - 0xbefe
+IDEOGRAM 0xbfa1 - 0xbffe 0xc0a1 - 0xc0fe 0xc1a1 - 0xc1fe
+IDEOGRAM 0xc2a1 - 0xc2fe 0xc3a1 - 0xc3fe 0xc4a1 - 0xc4fe
+IDEOGRAM 0xc5a1 - 0xc5fe 0xc6a1 - 0xc6fe 0xc7a1 - 0xc7fe
+IDEOGRAM 0xc8a1 - 0xc8fe 0xc9a1 - 0xc9fe 0xcaa1 - 0xcafe
+IDEOGRAM 0xcba1 - 0xcbfe 0xcca1 - 0xccfe 0xcda1 - 0xcdfe
+IDEOGRAM 0xcea1 - 0xcefe 0xcfa1 - 0xcfd3 0xd0a1 - 0xd0fe
+IDEOGRAM 0xd1a1 - 0xd1fe 0xd2a1 - 0xd2fe 0xd3a1 - 0xd3fe
+IDEOGRAM 0xd4a1 - 0xd4fe 0xd5a1 - 0xd5fe 0xd6a1 - 0xd6fe
+IDEOGRAM 0xd7a1 - 0xd7fe 0xd8a1 - 0xd8fe 0xd9a1 - 0xd9fe
+IDEOGRAM 0xdaa1 - 0xdafe 0xdba1 - 0xdbfe 0xdca1 - 0xdcfe
+IDEOGRAM 0xdda1 - 0xddfe 0xdea1 - 0xdefe 0xdfa1 - 0xdffe
+IDEOGRAM 0xe0a1 - 0xe0fe 0xe1a1 - 0xe1fe 0xe2a1 - 0xe2fe
+IDEOGRAM 0xe3a1 - 0xe3fe 0xe4a1 - 0xe4fe 0xe5a1 - 0xe5fe
+IDEOGRAM 0xe6a1 - 0xe6fe 0xe7a1 - 0xe7fe 0xe8a1 - 0xe8fe
+IDEOGRAM 0xe9a1 - 0xe9fe 0xeaa1 - 0xeafe 0xeba1 - 0xebfe
+IDEOGRAM 0xeca1 - 0xecfe 0xeda1 - 0xedfe 0xeea1 - 0xeefe
+IDEOGRAM 0xefa1 - 0xeffe 0xf0a1 - 0xf0fe 0xf1a1 - 0xf1fe
+IDEOGRAM 0xf2a1 - 0xf2fe 0xf3a1 - 0xf3fe 0xf4a1 - 0xf4a4
+/*
+ * This is for Code Set 3, half-width kana
+ */
+SPECIAL 0xa1 - 0xdf
+PHONOGRAM 0xa1 - 0xdf
+CONTROL 0x84 - 0x97 0x9b - 0x9f 0xe0 - 0xfe
+.Ed
+.Sh "SEE ALSO"
+.Xr mklocale 1 ,
+.Xr setlocale 3
diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c
new file mode 100644
index 000000000000..e58c8556087a
--- /dev/null
+++ b/lib/libc/locale/euc.c
@@ -0,0 +1,220 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)euc.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+rune_t _EUC_sgetrune __P((const char *, size_t, char const **));
+int _EUC_sputrune __P((rune_t, char *, size_t, char **));
+
+typedef struct {
+ int count[4];
+ rune_t bits[4];
+ rune_t mask;
+} _EucInfo;
+
+int
+_EUC_init(rl)
+ _RuneLocale *rl;
+{
+ _EucInfo *ei;
+ int x;
+ char *v, *e;
+
+ rl->sgetrune = _EUC_sgetrune;
+ rl->sputrune = _EUC_sputrune;
+
+ if (!rl->variable) {
+ free(rl);
+ return (EFTYPE);
+ }
+ v = (char *) rl->variable;
+
+ while (*v == ' ' || *v == '\t')
+ ++v;
+
+ if ((ei = malloc(sizeof(_EucInfo))) == NULL) {
+ free(rl);
+ return (ENOMEM);
+ }
+ for (x = 0; x < 4; ++x) {
+ ei->count[x] = (int) strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(rl);
+ free(ei);
+ return (EFTYPE);
+ }
+ while (*v == ' ' || *v == '\t')
+ ++v;
+ ei->bits[x] = (int) strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(rl);
+ free(ei);
+ return (EFTYPE);
+ }
+ while (*v == ' ' || *v == '\t')
+ ++v;
+ }
+ ei->mask = (int)strtol(v, &e, 0);
+ if (v == e || !(v = e)) {
+ free(rl);
+ free(ei);
+ return (EFTYPE);
+ }
+ if (sizeof(_EucInfo) <= rl->variable_len) {
+ memcpy(rl->variable, ei, sizeof(_EucInfo));
+ free(ei);
+ } else {
+ rl->variable = &ei;
+ }
+ rl->variable_len = sizeof(_EucInfo);
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 3;
+ return (0);
+}
+
+#define CEI ((_EucInfo *)(_CurrentRuneLocale->variable))
+
+#define _SS2 0x008e
+#define _SS3 0x008f
+
+static inline int
+_euc_set(c)
+ u_int c;
+{
+ c &= 0xff;
+
+ return ((c & 0x80) ? c == _SS3 ? 3 : c == _SS2 ? 2 : 1 : 0);
+}
+rune_t
+_EUC_sgetrune(string, n, result)
+ const char *string;
+ size_t n;
+ char const **result;
+{
+ rune_t rune = 0;
+ int len, set;
+
+ if (n < 1 || (len = CEI->count[set = _euc_set(*string)]) > n) {
+ if (result)
+ *result = string;
+ return (_INVALID_RUNE);
+ }
+ switch (set) {
+ case 3:
+ case 2:
+ --len;
+ ++string;
+ /* FALLTHROUGH */
+ case 1:
+ case 0:
+ while (len-- > 0)
+ rune = (rune << 8) | ((u_int)(*string++) & 0xff);
+ break;
+ }
+ if (result)
+ *result = string;
+ return ((rune & ~CEI->mask) | CEI->bits[set]);
+}
+
+int
+_EUC_sputrune(c, string, n, result)
+ rune_t c;
+ char *string, **result;
+ size_t n;
+{
+ rune_t m = c & CEI->mask;
+ rune_t nm = c & ~m;
+ int i, len;
+
+ if (m == CEI->bits[1]) {
+CodeSet1:
+ /* Codeset 1: The first byte must have 0x80 in it. */
+ i = len = CEI->count[1];
+ if (n >= len) {
+ if (result)
+ *result = string + len;
+ while (i-- > 0)
+ *string++ = (nm >> (i << 3)) | 0x80;
+ } else
+ if (result)
+ *result = (char *) 0;
+ } else {
+ if (m == CEI->bits[0]) {
+ i = len = CEI->count[0];
+ if (n < len) {
+ if (result)
+ *result = NULL;
+ return (len);
+ }
+ } else
+ if (m == CEI->bits[2]) {
+ i = len = CEI->count[2];
+ if (n < len) {
+ if (result)
+ *result = NULL;
+ return (len);
+ }
+ *string++ = _SS2;
+ --i;
+ } else
+ if (m == CEI->bits[3]) {
+ i = len = CEI->count[3];
+ if (n < len) {
+ if (result)
+ *result = NULL;
+ return (len);
+ }
+ *string++ = _SS3;
+ --i;
+ } else
+ goto CodeSet1; /* Bletch */
+ while (i-- > 0)
+ *string++ = (nm >> (i << 3)) & 0xff;
+ if (result)
+ *result = string;
+ }
+ return (len);
+}
diff --git a/lib/libc/locale/frune.c b/lib/libc/locale/frune.c
new file mode 100644
index 000000000000..443d3ba6eb36
--- /dev/null
+++ b/lib/libc/locale/frune.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)frune.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+
+long
+fgetrune(fp)
+ FILE *fp;
+{
+ rune_t r;
+ int c, len;
+ char buf[MB_LEN_MAX];
+ char const *result;
+
+ len = 0;
+ do {
+ if ((c = getc(fp)) == EOF) {
+ if (len)
+ break;
+ return (EOF);
+ }
+ buf[len++] = c;
+
+ if ((r = sgetrune(buf, len, &result)) != _INVALID_RUNE)
+ return (r);
+ } while (result == buf && len < MB_LEN_MAX);
+
+ while (--len > 0)
+ ungetc(buf[len], fp);
+ return (_INVALID_RUNE);
+}
+
+int
+fungetrune(r, fp)
+ rune_t r;
+ FILE* fp;
+{
+ int len;
+ char buf[MB_LEN_MAX];
+
+ len = sputrune(r, buf, MB_LEN_MAX, 0);
+ while (len-- > 0)
+ if (ungetc(buf[len], fp) == EOF)
+ return (EOF);
+ return (0);
+}
+
+int
+fputrune(r, fp)
+ rune_t r;
+ FILE *fp;
+{
+ int i, len;
+ char buf[MB_LEN_MAX];
+
+ len = sputrune(r, buf, MB_LEN_MAX, 0);
+
+ for (i = 0; i < len; ++i)
+ if (putc(buf[i], fp) == EOF)
+ return (EOF);
+
+ return (0);
+}
diff --git a/lib/libc/gen/isctype.c b/lib/libc/locale/isctype.c
index d8dd5bc33e9f..06cb1254ce68 100644
--- a/lib/libc/gen/isctype.c
+++ b/lib/libc/locale/isctype.c
@@ -1,15 +1,9 @@
/*
- * Copyright (c) UNIX System Laboratories, Inc. All or some portions
- * of this file are derived from material licensed to the
- * University of California by American Telephone and Telegraph Co.
- * or UNIX System Laboratories, Inc. and are reproduced herein with
- * the permission of UNIX System Laboratories, Inc.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
*
- * $Id: isctype.c,v 1.1.1.1.2.1 1994/05/04 07:39:44 rgrimes Exp $
- */
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -38,105 +32,139 @@
* 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[] = "@(#)isctype.c 5.2 (Berkeley) 6/1/90";
+static char sccsid[] = "@(#)isctype.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#define _ANSI_LIBRARY
#include <ctype.h>
#undef isalnum
+int
isalnum(c)
int c;
{
- return((_ctype_ + 1)[c] & (_U|_L|_N));
+ return(__istype((c), (_A|_D)));
}
#undef isalpha
+int
isalpha(c)
int c;
{
- return((_ctype_ + 1)[c] & (_U|_L));
+ return (__istype((c), _A));
+}
+
+#undef isascii
+int
+isascii(c)
+ int c;
+{
+ return((c & ~0x7F) == 0);
+}
+
+#undef isblank
+int
+isblank(c)
+ int c;
+{
+ return (__istype((c), _B));
}
#undef iscntrl
+int
iscntrl(c)
int c;
{
- return((_ctype_ + 1)[c] & _C);
+ return (__istype((c), _C));
}
#undef isdigit
+int
isdigit(c)
int c;
{
- return((_ctype_ + 1)[c] & _N);
+ return (__isctype((c), _D));
}
#undef isgraph
+int
isgraph(c)
int c;
{
- return((_ctype_ + 1)[c] & (_P|_U|_L|_N));
+ return (__istype((c), _G));
}
#undef islower
+int
islower(c)
int c;
{
- return((_ctype_ + 1)[c] & _L);
+ return (__istype((c), _L));
}
#undef isprint
+int
isprint(c)
int c;
{
- return((_ctype_ + 1)[c] & (_P|_U|_L|_N|_B));
+ return (__istype((c), _R));
}
#undef ispunct
+int
ispunct(c)
int c;
{
- return((_ctype_ + 1)[c] & _P);
+ return (__istype((c), _P));
}
#undef isspace
+int
isspace(c)
int c;
{
- return((_ctype_ + 1)[c] & _S);
+ return (__istype((c), _S));
}
#undef isupper
+int
isupper(c)
int c;
{
- return((_ctype_ + 1)[c] & _U);
+ return (__istype((c), _U));
}
#undef isxdigit
+int
isxdigit(c)
int c;
{
- return((_ctype_ + 1)[c] & (_N|_X));
+ return (__isctype((c), _X));
}
-#undef tolower
-tolower(c)
+#undef toascii
+int
+toascii(c)
int c;
{
-/* was: return((c) - 'A' + 'a');*/
- return ( isupper(c) ? c - 'A' + 'a' : c);
+ return (c & 0177);
}
#undef toupper
+int
toupper(c)
int c;
{
-/* was: return((c) - 'a' + 'A');*/
- return ( islower(c) ? c - 'a' + 'A' : c);
+ return((c & _CRMASK) ? ___toupper(c) : _CurrentRuneLocale->mapupper[c]);
+}
+
+#undef tolower
+int
+tolower(c)
+ int c;
+{
+ return((c & _CRMASK) ? ___tolower(c) : _CurrentRuneLocale->maplower[c]);
}
diff --git a/lib/libc/locale/mbrune.3 b/lib/libc/locale/mbrune.3
new file mode 100644
index 000000000000..83e9dfe938d2
--- /dev/null
+++ b/lib/libc/locale/mbrune.3
@@ -0,0 +1,157 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)mbrune.3 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt MBRUNE 3
+.Os
+.Sh NAME
+.Nm mbrune ,
+.Nm mbrrune ,
+.Nm mbmb
+.Nd multibyte rune support for C
+.Sh SYNOPSIS
+.Fd #include <rune.h>
+.Ft char *
+.Fn mbrune "const char *string" "rune_t rune"
+.Ft char *
+.Fn mbrrune "const char *string" "rune_t rune"
+.Ft char *
+.Fn mbmb "const char *string" "char *pattern"
+.Sh DESCRIPTION
+These routines provide the corresponding functionality of
+.Fn strchr ,
+.Fn strrchr
+and
+.Fn strstr
+for multibyte strings.
+.Pp
+The
+.Fn mbrune
+function locates the first occurrence of
+.Fn rune
+in the string pointed to by
+.Ar string .
+The terminating
+.Dv NULL
+character is considered part of the string.
+If
+.Fa rune
+is
+.Ql \e0 ,
+.Fn mbrune
+locates the terminating
+.Ql \e0 .
+.Pp
+The
+.Fn mbrrune
+function
+locates the last occurrence of
+.Fa rune
+in the string
+.Fa string .
+If
+.Fa rune
+is
+.Ql \e0 ,
+.Fn mbrune
+locates the terminating
+.Ql \e0 .
+.Pp
+The
+.Fn mbmb
+function locates the first occurrence of the null-terminated string
+.Fa pattern
+in the null-terminated string
+.Fa string.
+If
+.Fa pattern
+is the empty string,
+.Fn mbmb
+returns
+.Fa string ;
+if
+.Fa pattern
+occurs nowhere in
+.Fa string ,
+.Fn mbmb
+returns
+.Dv NULL ;
+otherwise
+.Fn mbmb
+returns a pointer to the first character of the first occurrence of
+.Fa pattern .
+.Sh RETURN VALUES
+The function
+.Fn mbrune
+returns a pointer to the located character, or
+.Dv NULL
+if the character does not appear in the string.
+.Pp
+The
+.Fn mbrrune
+function
+returns a pointer to the character, or
+.Dv NULL
+if the character does not appear in the string.
+.Pp
+The
+.Fn mbmb
+function
+returns a pointer to the
+.Fa pattern ,
+or
+.Dv NULL
+if the
+.Fa pattern
+does not appear in the string.
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr rune 3 ,
+.Xr setlocale 3 ,
+.Xr utf2 4
+.Sh HISTORY
+The
+.Fn mbrune ,
+.Fn mbrrune ,
+and
+.Fn mbmb
+functions
+first appeared in Plan 9 from Bell Labs as
+.Fn utfrune ,
+.Fn utfrrune ,
+and
+.Fn utfutf .
diff --git a/lib/libc/locale/mbrune.c b/lib/libc/locale/mbrune.c
new file mode 100644
index 000000000000..92efe838a036
--- /dev/null
+++ b/lib/libc/locale/mbrune.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)mbrune.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <limits.h>
+#include <rune.h>
+#include <stddef.h>
+#include <string.h>
+
+char *
+mbrune(string, c)
+ const char *string;
+ rune_t c;
+{
+ char const *result;
+ rune_t r;
+
+ while ((r = sgetrune(string, MB_LEN_MAX, &result))) {
+ if (r == c)
+ return ((char *)string);
+ string = result == string ? string + 1 : result;
+ }
+
+ return (c == *string ? (char *)string : NULL);
+}
+
+char *
+mbrrune(string, c)
+ const char *string;
+ rune_t c;
+{
+ const char *last = 0;
+ char const *result;
+ rune_t r;
+
+ while ((r = sgetrune(string, MB_LEN_MAX, &result))) {
+ if (r == c)
+ last = string;
+ string = result == string ? string + 1 : result;
+ }
+ return (c == *string ? (char *)string : (char *)last);
+}
+
+char *
+mbmb(string, pattern)
+ const char *string;
+ char *pattern;
+{
+ rune_t first, r;
+ size_t plen, slen;
+ char const *result;
+
+ plen = strlen(pattern);
+ slen = strlen(string);
+ if (plen > slen)
+ return (0);
+
+ first = sgetrune(pattern, plen, &result);
+ if (result == string)
+ return (0);
+
+ while (slen >= plen && (r = sgetrune(string, slen, &result))) {
+ if (r == first) {
+ if (strncmp(string, pattern, slen) == 0)
+ return ((char *) string);
+ }
+ if (result == string) {
+ --slen;
+ ++string;
+ } else {
+ slen -= result - string;
+ string = result;
+ }
+ }
+ return (0);
+}
diff --git a/lib/libc/locale/multibyte.3 b/lib/libc/locale/multibyte.3
new file mode 100644
index 000000000000..3ea10e5ace3d
--- /dev/null
+++ b/lib/libc/locale/multibyte.3
@@ -0,0 +1,241 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley of BSDI.
+.\"
+.\" 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.
+.\"
+.\" @(#)multibyte.3 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt MULTIBYTE 3
+.Os
+.Sh NAME
+.Nm mblen ,
+.Nm mbstowcs ,
+.Nm mbtowc ,
+.Nm wcstombs ,
+.Nm wctomb
+.Nd multibyte character support for C
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Ft int
+.Fn mblen "const char *mbchar" "int nbytes"
+.Ft size_t
+.Fn mbstowcs "wchar_t *wcstring" "const char *mbstring" "size_t nwchars"
+.Ft int
+.Fn mbtowc "wchar_t *wcharp" "const char *mbchar" "size_t nbytes"
+.Ft size_t
+.Fn wcstombs "char *mbstring" "const wchar_t *wcstring" "size_t nbytes"
+.Ft int
+.Fn wctomb "char *mbchar" "wchar_t wchar"
+.Sh DESCRIPTION
+The basic elements of some written natural languages such as Chinese
+cannot be represented uniquely with single C
+.Va char Ns s .
+The C standard supports two different ways of dealing with
+extended natural language encodings,
+.Em wide
+characters and
+.Em multibyte
+characters.
+Wide characters are an internal representation
+which allows each basic element to map
+to a single object of type
+.Va wchar_t .
+Multibyte characters are used for input and output
+and code each basic element as a sequence of C
+.Va char Ns s .
+Individual basic elements may map into one or more
+.Pq up to Dv MB_CHAR_MAX
+bytes in a multibyte character.
+.Pp
+The current locale
+.Pq Xr setlocale 3
+governs the interpretation of wide and multibyte characters.
+The locale category
+.Dv LC_CTYPE
+specifically controls this interpretation.
+The
+.Va wchar_t
+type is wide enough to hold the largest value
+in the wide character representations for all locales.
+.Pp
+Multibyte strings may contain
+.Sq shift
+indicators to switch to and from
+particular modes within the given representation.
+If explicit bytes are used to signal shifting,
+these are not recognized as separate characters
+but are lumped with a neighboring character.
+There is always a distinguished
+.Sq initial
+shift state.
+The
+.Fn mbstowcs
+and
+.Fn wcstombs
+functions assume that multibyte strings are interpreted
+starting from the initial shift state.
+The
+.Fn mblen ,
+.Fn mbtowc
+and
+.Fn wctomb
+functions maintain static shift state internally.
+A call with a null
+.Fa mbchar
+pointer returns nonzero if the current locale requires shift states,
+zero otherwise;
+if shift states are required, the shift state is reset to the initial state.
+The internal shift states are undefined after a call to
+.Fn setlocale
+with the
+.Dv LC_CTYPE
+or
+.Dv LC_ALL
+categories.
+.Pp
+For convenience in processing,
+the wide character with value 0
+.Pq the null wide character
+is recognized as the wide character string terminator,
+and the character with value 0
+.Pq the null byte
+is recognized as the multibyte character string terminator.
+Null bytes are not permitted within multibyte characters.
+.Pp
+The
+.Fn mblen
+function computes the length in bytes
+of a multibyte character
+.Fa mbchar .
+Up to
+.Fa nbytes
+bytes are examined.
+.Pp
+The
+.Fn mbtowc
+function converts a multibyte character
+.Fa mbchar
+into a wide character and stores the result
+in the object pointed to by
+.Fa wcharp.
+Up to
+.Fa nbytes
+bytes are examined.
+.Pp
+The
+.Fn wctomb
+function converts a wide character
+.Fa wchar
+into a multibyte character and stores
+the result in
+.Fa mbchar .
+The object pointed to by
+.Fa mbchar
+must be large enough to accommodate the multibyte character.
+.Pp
+The
+.Fn mbstowcs
+function converts a multibyte character string
+.Fa mbstring
+into a wide character string
+.Fa wcstring .
+No more than
+.Fa nwchars
+wide characters are stored.
+A terminating null wide character is appended if there is room.
+.Pp
+The
+.Fn wcstombs
+function converts a wide character string
+.Fa wcstring
+into a multibyte character string
+.Fa mbstring .
+Up to
+.Fa nbytes
+bytes are stored in
+.Fa mbstring .
+Partial multibyte characters at the end of the string are not stored.
+The multibyte character string is null terminated if there is room.
+.Sh "RETURN VALUES
+If multibyte characters are not supported in the current locale,
+all of these functions will return \-1 if characters can be processed,
+otherwise 0.
+.Pp
+If
+.Fa mbchar
+is
+.Dv NULL ,
+the
+.Fn mblen ,
+.Fn mbtowc
+and
+.Fn wctomb
+functions return nonzero if shift states are supported,
+zero otherwise.
+If
+.Fa mbchar
+is valid,
+then these functions return
+the number of bytes processed in
+.Fa mbchar ,
+or \-1 if no multibyte character
+could be recognized or converted.
+.Pp
+The
+.Fn mbstowcs
+function returns the number of wide characters converted,
+not counting any terminating null wide character.
+The
+.Fn wcstombs
+function returns the number of bytes converted,
+not counting any terminating null byte.
+If any invalid multibyte characters are encountered,
+both functions return \-1.
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr rune 3 ,
+.Xr setlocale 3 ,
+.Xr utf2 4
+.Sh STANDARDS
+The
+.Fn mblen ,
+.Fn mbstowcs ,
+.Fn mbtowc ,
+.Fn wcstombs
+and
+.Fn wctomb
+functions conform to
+.St -ansiC .
+.Sh BUGS
+The current implementation does not support shift states.
diff --git a/lib/libc/stdlib/multibyte.c b/lib/libc/locale/none.c
index 695127969633..b5d8e44299cd 100644
--- a/lib/libc/stdlib/multibyte.c
+++ b/lib/libc/locale/none.c
@@ -1,6 +1,9 @@
-/*
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,74 +35,59 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)multibyte.c 5.1 (Berkeley) 2/18/91";
+static char sccsid[] = "@(#)none.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
+#include <stddef.h>
+#include <stdio.h>
+#include <rune.h>
+#include <errno.h>
#include <stdlib.h>
-/*
- * Stub multibyte character functions.
- * These ignore the current fixed ("C") locale and
- * always indicate that no multibyte characters are supported.
- */
+rune_t _none_sgetrune __P((const char *, size_t, char const **));
+int _none_sputrune __P((rune_t, char *, size_t, char **));
int
-mblen(s, n)
- const char *s;
- size_t n;
+_none_init(rl)
+ _RuneLocale *rl;
{
- if (s && n && *s)
- return -1;
- return 0;
+ rl->sgetrune = _none_sgetrune;
+ rl->sputrune = _none_sputrune;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 1;
+ return(0);
}
-/*ARGSUSED*/
-int
-mbtowc(pwc, s, n)
- wchar_t *pwc;
- const char *s;
+rune_t
+_none_sgetrune(string, n, result)
+ const char *string;
size_t n;
+ char const **result;
{
- if (s && n && *s)
- return -1;
- return 0;
-}
-
-/*ARGSUSED*/
-int
-#ifdef __STDC__
-wctomb(char *s, wchar_t wchar)
-#else
-wctomb(s, wchar)
- char *s;
- wchar_t wchar;
-#endif
-{
- if (s)
- return -1;
- return 0;
-}
+ int c;
-/*ARGSUSED*/
-size_t
-mbstowcs(pwcs, s, n)
- wchar_t *pwcs;
- const char *s;
- size_t n;
-{
- if (s && n && *s)
- return -1;
- return 0;
+ if (n < 1) {
+ if (result)
+ *result = string;
+ return(_INVALID_RUNE);
+ }
+ if (result)
+ *result = string + 1;
+ return(*string & 0xff);
}
-/*ARGSUSED*/
-size_t
-wcstombs(s, pwcs, n)
- char *s;
- const wchar_t *pwcs;
+int
+_none_sputrune(c, string, n, result)
+ rune_t c;
+ char *string, **result;
size_t n;
{
- if (pwcs && n && *pwcs)
- return -1;
- return 0;
+ if (n >= 1) {
+ if (string)
+ *string = c;
+ if (result)
+ *result = string + 1;
+ } else if (result)
+ *result = (char *)0;
+ return(1);
}
diff --git a/lib/libc/locale/rune.3 b/lib/libc/locale/rune.3
new file mode 100644
index 000000000000..8d2ca5dd4b5e
--- /dev/null
+++ b/lib/libc/locale/rune.3
@@ -0,0 +1,269 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)rune.3 8.1 (Berkeley) 6/27/93
+.\"
+.Dd "June 27, 1993"
+.Dt RUNE 3
+.Os
+.Sh NAME
+.Nm setrunelocale ,
+.Nm setinvalidrune ,
+.Nm sgetrune ,
+.Nm sputrune
+.Nd rune support for C
+.Sh SYNOPSIS
+.Fd #include <rune.h>
+.Fd #include <errno.h>
+.Ft int
+.Fn setrunelocale "char *locale"
+.Ft void
+.Fn setinvalidrune "rune_t rune"
+.Ft rune_t
+.Fn sgetrune "const char *string" "size_t n" "char const **result"
+.Ft int
+.Fn sputrune "rune_t rune" "char *string" "size_t n" "char **result"
+.sp
+.Fd #include <stdio.h>
+.Ft long
+.Fn fgetrune "FILE *stream"
+.Ft int
+.Fn fungetrune "rune_t rune" "FILE *stream"
+.Ft int
+.Fn fputrune "rune_t rune" "FILE *stream"
+.Sh DESCRIPTION
+The
+.Fn setrunelocale
+controls the type of encoding used to represent runes as multibyte strings
+as well as the properties of the runes as defined in
+\fB<ctype.h>\fP.
+The
+.Fa locale
+argument indicates the locale which to load.
+If the locale is successfully loaded,
+.Dv 0
+is returned, otherwise an errno value is returned to indicate the
+type of error.
+.Pp
+The
+.Fn setinvalidrune
+function sets the value of the global value
+.Ev _INVALID_RUNE
+to be
+.Fa rune.
+.Pp
+The
+.Fn sgetrune
+function tries to read a single multibyte character from
+.Fa string ,
+which is at most
+.Fa n
+bytes long.
+If
+.Fn sgetrune
+is successful, the rune is returned.
+If
+.Fa result
+is not
+.Dv NULL ,
+.Fa *result
+will point to the first byte which was not converted in
+.Fa string.
+If the first
+.Fa n
+bytes of
+.Fa string
+do not describe a full multibyte character,
+.Ev _INVALID_RUNE
+is returned and
+.Fa *result
+will point to
+.Fa string.
+If there is an encoding error at the start of
+.Fa string ,
+.Ev _INVALID_RUNE
+is returned and
+.Fa *result
+will point to the second character of
+.Fa string.
+.Pp
+the
+.Fn sputrune
+function tries to encode
+.Fa rune
+as a multibyte string and store it at
+.Fa string ,
+but no more than
+.Fa n
+bytes will be stored.
+If
+.Fa result
+is not
+.Dv NULL ,
+.Fa *result
+will be set to point to the first byte in string following the new
+multibyte character.
+If
+.Fa string
+is
+.Dv NULL ,
+.Fa *result
+will point to
+.Dv "(char *)0 +"
+.Fa x ,
+where
+.Fa x
+is the number of bytes that would be needed to store the multibyte value.
+If the multibyte character would consist of more than
+.Fa n
+bytes and
+.Fa result
+is not
+.Dv NULL ,
+.Fa *result
+will be set to
+.Dv NULL.
+In all cases,
+.Fn sputrune
+will return the number of bytes which would be needed to store
+.Fa rune
+as a multibyte character.
+.Pp
+The
+.Fn fgetrune
+function operates the same as
+.Fn sgetrune
+with the exception that it attempts to read enough bytes from
+.Fa stream
+to decode a single rune. It returns either
+.Ev EOF
+on end of file,
+.Ev _INVALID_RUNE
+on an encoding error, or the rune decoded if all went well.
+.Pp
+The
+.Fn fungetrune
+function function pushes the multibyte encoding, as provided by
+.Fn sputrune ,
+of
+.Fa rune
+onto
+.Fa stream
+such that the next
+.Fn fgetrune
+call will return
+.Fa rune .
+It returns
+.Ev EOF
+if it fails and
+.Dv 0
+on success.
+.Pp
+The
+.Fn fputrune
+function writes the multibyte encoding of
+.Fa rune ,
+as provided by
+.Fn sputrune ,
+onto
+.Fa stream .
+It returns
+.Ev EOF
+on failure and
+.Dv 0
+on success.
+.Sh RETURN VALUES
+The
+.Fn setrunelocale
+function returns one of the following values:
+.Bl -tag -width WWWWWWWW
+.It Dv 0
+.Fa setrunelocale was successful.
+.It Ev EFAULT
+.Fa locale
+was
+.Dv NULL .
+.It Ev ENOENT
+The locale could not be found.
+.It Ev EFTYPE
+The file found was not a valid file.
+.It Ev EINVAL
+The encoding indicated by the locale was unknown.
+.El
+.Pp
+The
+.Fn sgetrune
+function either returns the rune read or
+.Ev _INVALID_RUNE .
+The
+.Fn sputrune
+function returns the number of bytes needed to store
+.Fa rune
+as a multibyte string.
+.Sh FILES
+.Bl -tag -width /usr/share/locale/locale/LC_CTYPE -compact
+.It Pa $PATH_LOCALE/\fIlocale\fP/LC_CTYPE
+.It Pa /usr/share/locale/\fIlocale\fP/LC_CTYPE
+binary LC_CTYPE file for the locale \fIlocale\fP.
+.El
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr setlocale 3 ,
+.Xr utf2 4
+.Sh NOTE
+The ANSI C type
+.Ev wchar_t
+is the same as
+.Ev rune_t .
+.Ev Rune_t
+was chosen to accent the purposeful choice of not basing the
+system with the ANSI C
+primitives, which were, shall we say, less aesthetic.
+.Sh HISTORY
+These functions first appeared in
+.Bx 4.4 .
+.Pp
+The
+.Fn setrunelocale
+function and the other non-ANSI rune functions were inspired by
+.Nm Plan 9 from Bell Labs
+as a much more sane alternative to the ANSI multibyte and
+wide character support.
+.\"They were conceived at the San Diego 1993 Summer USENIX conference by
+.\"Paul Borman of Krystal Technologies, Keith Bostic of CSRG and Andrew Hume
+.\"of Bell Labs.
+.Pp
+All of the ANSI multibyte and wide character
+support functions are built using the rune functions.
diff --git a/lib/libc/locale/rune.c b/lib/libc/locale/rune.c
new file mode 100644
index 000000000000..b239484fac81
--- /dev/null
+++ b/lib/libc/locale/rune.c
@@ -0,0 +1,334 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)rune.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <rune.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int _none_init __P((_RuneLocale *));
+extern int _UTF2_init __P((_RuneLocale *));
+extern int _EUC_init __P((_RuneLocale *));
+static _RuneLocale *_Read_RuneMagi __P((FILE *));
+
+static char *PathLocale = 0;
+
+int
+setrunelocale(encoding)
+ char *encoding;
+{
+ FILE *fp;
+ char name[PATH_MAX];
+ _RuneLocale *rl;
+
+ if (!encoding)
+ return(EFAULT);
+
+ /*
+ * The "C" and "POSIX" locale are always here.
+ */
+ if (!strcmp(encoding, "C") || !strcmp(encoding, "POSIX")) {
+ _CurrentRuneLocale = &_DefaultRuneLocale;
+ return(0);
+ }
+
+ if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
+ PathLocale = _PATH_LOCALE;
+
+ sprintf(name, "%s/%s/LC_CTYPE", PathLocale, encoding);
+
+ if ((fp = fopen(name, "r")) == NULL)
+ return(ENOENT);
+
+ if ((rl = _Read_RuneMagi(fp)) == 0) {
+ fclose(fp);
+ return(EFTYPE);
+ }
+
+ if (!rl->encoding[0] || !strcmp(rl->encoding, "UTF2")) {
+ return(_UTF2_init(rl));
+ } else if (!strcmp(rl->encoding, "NONE")) {
+ return(_none_init(rl));
+ } else if (!strcmp(rl->encoding, "EUC")) {
+ return(_EUC_init(rl));
+ } else
+ return(EINVAL);
+}
+
+void
+setinvalidrune(ir)
+ rune_t ir;
+{
+ _INVALID_RUNE = ir;
+}
+
+static _RuneLocale *
+_Read_RuneMagi(fp)
+ FILE *fp;
+{
+ char *data;
+ void *np;
+ void *lastp;
+ _RuneLocale *rl;
+ _RuneEntry *rr;
+ struct stat sb;
+ int x;
+
+ if (fstat(fileno(fp), &sb) < 0)
+ return(0);
+
+ if (sb.st_size < sizeof(_RuneLocale))
+ return(0);
+
+ if ((data = malloc(sb.st_size)) == NULL)
+ return(0);
+
+ rewind(fp); /* Someone might have read the magic number once already */
+
+ if (fread(data, sb.st_size, 1, fp) != 1) {
+ free(data);
+ return(0);
+ }
+
+ rl = (_RuneLocale *)data;
+ lastp = data + sb.st_size;
+
+ rl->variable = rl + 1;
+
+ if (memcmp(rl->magic, _RUNE_MAGIC_1, sizeof(rl->magic))) {
+ free(data);
+ return(0);
+ }
+
+ rl->invalid_rune = ntohl(rl->invalid_rune);
+ rl->variable_len = ntohl(rl->variable_len);
+ rl->runetype_ext.nranges = ntohl(rl->runetype_ext.nranges);
+ rl->maplower_ext.nranges = ntohl(rl->maplower_ext.nranges);
+ rl->mapupper_ext.nranges = ntohl(rl->mapupper_ext.nranges);
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ rl->runetype[x] = ntohl(rl->runetype[x]);
+ rl->maplower[x] = ntohl(rl->maplower[x]);
+ rl->mapupper[x] = ntohl(rl->mapupper[x]);
+ }
+
+ rl->runetype_ext.ranges = (_RuneEntry *)rl->variable;
+ rl->variable = rl->runetype_ext.ranges + rl->runetype_ext.nranges;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+
+ rl->maplower_ext.ranges = (_RuneEntry *)rl->variable;
+ rl->variable = rl->maplower_ext.ranges + rl->maplower_ext.nranges;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+
+ rl->mapupper_ext.ranges = (_RuneEntry *)rl->variable;
+ rl->variable = rl->mapupper_ext.ranges + rl->mapupper_ext.nranges;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+
+ for (x = 0; x < rl->runetype_ext.nranges; ++x) {
+ rr = rl->runetype_ext.ranges;
+
+ rr[x].min = ntohl(rr[x].min);
+ rr[x].max = ntohl(rr[x].max);
+ if ((rr[x].map = ntohl(rr[x].map)) == 0) {
+ int len = rr[x].max - rr[x].min + 1;
+ rr[x].types = rl->variable;
+ rl->variable = rr[x].types + len;
+ if (rl->variable > lastp) {
+ free(data);
+ return(0);
+ }
+ while (len-- > 0)
+ rr[x].types[len] = ntohl(rr[x].types[len]);
+ } else
+ rr[x].types = 0;
+ }
+
+ for (x = 0; x < rl->maplower_ext.nranges; ++x) {
+ rr = rl->maplower_ext.ranges;
+
+ rr[x].min = ntohl(rr[x].min);
+ rr[x].max = ntohl(rr[x].max);
+ rr[x].map = ntohl(rr[x].map);
+ }
+
+ for (x = 0; x < rl->mapupper_ext.nranges; ++x) {
+ rr = rl->mapupper_ext.ranges;
+
+ rr[x].min = ntohl(rr[x].min);
+ rr[x].max = ntohl(rr[x].max);
+ rr[x].map = ntohl(rr[x].map);
+ }
+ if (((char *)rl->variable) + rl->variable_len > (char *)lastp) {
+ free(data);
+ return(0);
+ }
+
+ /*
+ * Go out and zero pointers that should be zero.
+ */
+ if (!rl->variable_len)
+ rl->variable = 0;
+
+ if (!rl->runetype_ext.nranges)
+ rl->runetype_ext.ranges = 0;
+
+ if (!rl->maplower_ext.nranges)
+ rl->maplower_ext.ranges = 0;
+
+ if (!rl->mapupper_ext.nranges)
+ rl->mapupper_ext.ranges = 0;
+
+ return(rl);
+}
+
+unsigned long
+___runetype(c)
+ _BSD_RUNE_T_ c;
+{
+ int x;
+ _RuneRange *rr = &_CurrentRuneLocale->runetype_ext;
+ _RuneEntry *re = rr->ranges;
+
+ if (c == EOF)
+ return(0);
+ for (x = 0; x < rr->nranges; ++x, ++re) {
+ if (c < re->min)
+ return(0L);
+ if (c <= re->max) {
+ if (re->types)
+ return(re->types[c - re->min]);
+ else
+ return(re->map);
+ }
+ }
+ return(0L);
+}
+
+_BSD_RUNE_T_
+___toupper(c)
+ _BSD_RUNE_T_ c;
+{
+ int x;
+ _RuneRange *rr = &_CurrentRuneLocale->mapupper_ext;
+ _RuneEntry *re = rr->ranges;
+
+ if (c == EOF)
+ return(EOF);
+ for (x = 0; x < rr->nranges; ++x, ++re) {
+ if (c < re->min)
+ return(c);
+ if (c <= re->max)
+ return(re->map + c - re->min);
+ }
+ return(c);
+}
+
+_BSD_RUNE_T_
+___tolower(c)
+ _BSD_RUNE_T_ c;
+{
+ int x;
+ _RuneRange *rr = &_CurrentRuneLocale->maplower_ext;
+ _RuneEntry *re = rr->ranges;
+
+ if (c == EOF)
+ return(EOF);
+ for (x = 0; x < rr->nranges; ++x, ++re) {
+ if (c < re->min)
+ return(c);
+ if (c <= re->max)
+ return(re->map + c - re->min);
+ }
+ return(c);
+}
+
+
+#if !defined(_USE_CTYPE_INLINE_) && !defined(_USE_CTYPE_MACROS_)
+/*
+ * See comments in <machine/ansi.h>
+ */
+int
+__istype(c, f)
+ _BSD_RUNE_T_ c;
+ unsigned long f;
+{
+ return ((((c & _CRMASK) ? ___runetype(c)
+ : _CurrentRuneLocale->runetype[c]) & f) ? 1 : 0);
+}
+
+int
+__isctype(_BSD_RUNE_T_ c, unsigned long f)
+ _BSD_RUNE_T_ c;
+ unsigned long f;
+{
+ return ((((c & _CRMASK) ? 0
+ : _DefaultRuneLocale.runetype[c]) & f) ? 1 : 0);
+}
+
+_BSD_RUNE_T_
+toupper(c)
+ _BSD_RUNE_T_ c;
+{
+ return ((c & _CRMASK) ?
+ ___toupper(c) : _CurrentRuneLocale->mapupper[c]);
+}
+
+_BSD_RUNE_T_
+tolower(c)
+ _BSD_RUNE_T_ c;
+{
+ return ((c & _CRMASK) ?
+ ___tolower(c) : _CurrentRuneLocale->maplower[c]);
+}
+#endif
diff --git a/lib/libc/locale/setlocale.3 b/lib/libc/locale/setlocale.3
new file mode 100644
index 000000000000..74cce03bfc5e
--- /dev/null
+++ b/lib/libc/locale/setlocale.3
@@ -0,0 +1,321 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Donn Seeley at BSDI.
+.\"
+.\" 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.
+.\"
+.\" @(#)setlocale.3 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt SETLOCALE 3
+.Os
+.Sh NAME
+.Nm setlocale ,
+.Nm localeconv
+.Nd natural language formatting for C
+.Sh SYNOPSIS
+.Fd #include <locale.h>
+.Ft char *
+.Fn setlocale "int category" "const char *locale"
+.Ft struct lconv *
+.Fn localeconv "void"
+.Sh DESCRIPTION
+The
+.Fn setlocale
+function sets the C library's notion
+of natural language formatting style
+for particular sets of routines.
+Each such style is called a
+.Sq locale
+and is invoked using an appropriate name passed as a C string.
+The
+.Fn localeconv
+routine returns the current locale's parameters
+for formatting numbers.
+.Pp
+The
+.Fn setlocale
+function recognizes several categories of routines.
+These are the categories and the sets of routines they select:
+.Pp
+.Bl -tag -width LC_MONETARY
+.It Dv LC_ALL
+Set the entire locale generically.
+.It Dv LC_COLLATE
+Set a locale for string collation routines.
+This controls alphabetic ordering in
+.Fn strcoll
+and
+.Fn strxfrm .
+.It Dv LC_CTYPE
+Set a locale for the
+.Xr ctype 3 ,
+.Xr mbrune 3 ,
+.Xr multibyte 3
+and
+.Xr rune 3
+functions.
+This controls recognition of upper and lower case,
+alphabetic or non-alphabetic characters,
+and so on. The real work is done by the
+.Fn setrunelocale
+function.
+.It Dv LC_MONETARY
+Set a locale for formatting monetary values;
+this affects the
+.Fn localeconv
+function.
+.It Dv LC_NUMERIC
+Set a locale for formatting numbers.
+This controls the formatting of decimal points
+in input and output of floating point numbers
+in functions such as
+.Fn printf
+and
+.Fn scanf ,
+as well as values returned by
+.Fn localeconv .
+.It Dv LC_TIME
+Set a locale for formatting dates and times using the
+.Fn strftime
+function.
+.El
+.Pp
+Only three locales are defined by default,
+the empty string
+.Li "\&""\|""
+which denotes the native environment, and the
+.Li "\&""C""
+and
+.LI "\&""POSIX""
+locales, which denote the C language environment.
+A
+.Fa locale
+argument of
+.Dv NULL
+causes
+.Fn setlocale
+to return the current locale.
+By default, C programs start in the
+.Li "\&""C""
+locale.
+The only function in the library that sets the locale is
+.Fn setlocale ;
+the locale is never changed as a side effect of some other routine.
+.Pp
+The
+.Fn localeconv
+function returns a pointer to a structure
+which provides parameters for formatting numbers,
+especially currency values:
+.Bd -literal -offset indent
+struct lconv {
+ char *decimal_point;
+ char *thousands_sep;
+ char *grouping;
+ char *int_curr_symbol;
+ char *currency_symbol;
+ char *mon_decimal_point;
+ char *mon_thousands_sep;
+ char *mon_grouping;
+ char *positive_sign;
+ char *negative_sign;
+ char int_frac_digits;
+ char frac_digits;
+ char p_cs_precedes;
+ char p_sep_by_space;
+ char n_cs_precedes;
+ char n_sep_by_space;
+ char p_sign_posn;
+ char n_sign_posn;
+};
+.Ed
+.Pp
+The individual fields have the following meanings:
+.Pp
+.Bl -tag -width mon_decimal_point
+.It Fa decimal_point
+The decimal point character, except for currency values.
+.It Fa thousands_sep
+The separator between groups of digits
+before the decimal point, except for currency values.
+.It Fa grouping
+The sizes of the groups of digits, except for currency values.
+This is a pointer to a vector of integers, each of size
+.Va char ,
+representing group size from low order digit groups
+to high order (right to left).
+The list may be terminated with 0 or
+.Dv CHAR_MAX .
+If the list is terminated with 0,
+the last group size before the 0 is repeated to account for all the digits.
+If the list is terminated with
+.Dv CHAR_MAX ,
+no more grouping is performed.
+.It Fa int_curr_symbol
+The standardized international currency symbol.
+.It Fa currency_symbol
+The local currency symbol.
+.It Fa mon_decimal_point
+The decimal point character for currency values.
+.It Fa mon_thousands_sep
+The separator for digit groups in currency values.
+.It Fa mon_grouping
+Like
+.Fa grouping
+but for currency values.
+.It Fa positive_sign
+The character used to denote nonnegative currency values,
+usually the empty string.
+.It Fa negative_sign
+The character used to denote negative currency values,
+usually a minus sign.
+.It Fa int_frac_digits
+The number of digits after the decimal point
+in an international-style currency value.
+.It Fa frac_digits
+The number of digits after the decimal point
+in the local style for currency values.
+.It Fa p_cs_precedes
+1 if the currency symbol precedes the currency value
+for nonnegative values, 0 if it follows.
+.It Fa p_sep_by_space
+1 if a space is inserted between the currency symbol
+and the currency value for nonnegative values, 0 otherwise.
+.It Fa n_cs_precedes
+Like
+.Fa p_cs_precedes
+but for negative values.
+.It Fa n_sep_by_space
+Like
+.Fa p_sep_by_space
+but for negative values.
+.It Fa p_sign_posn
+The location of the
+.Fa positive_sign
+with respect to a nonnegative quantity and the
+.Fa currency_symbol ,
+coded as follows:
+.Bl -tag -width 3n -compact
+.It Li 0
+Parentheses around the entire string.
+.It Li 1
+Before the string.
+.It Li 2
+After the string.
+.It Li 3
+Just before
+.Fa currency_symbol .
+.It Li 4
+Just after
+.Fa currency_symbol .
+.El
+.It Fa n_sign_posn
+Like
+.Fa p_sign_posn
+but for negative currency values.
+.El
+.Pp
+Unless mentioned above,
+an empty string as a value for a field
+indicates a zero length result or
+a value that is not in the current locale.
+A
+.Dv CHAR_MAX
+result similarly denotes an unavailable value.
+.Sh "RETURN VALUES
+The
+.Fn setlocale
+function returns
+.Dv NULL
+and fails to change the locale
+if the given combination of
+.Fa category
+and
+.Fa locale
+makes no sense.
+The
+.Fn localeconv
+function returns a pointer to a static object
+which may be altered by later calls to
+.Fn setlocale
+or
+.Fn localeconv .
+.Sh FILES
+.Bl -tag -width /usr/share/locale/locale/category -compact
+.It Pa $PATH_LOCALE/\fIlocale\fP/\fIcategory\fP
+.It Pa /usr/share/locale/\fIlocale\fP/\fIcategory\fP
+locale file for the locale \fIlocale\fP
+and the category \fIcategory\fP.
+.El
+.Sh "SEE ALSO
+.Xr euc 4 ,
+.Xr mbrune 3 ,
+.Xr multibyte 3 ,
+.Xr rune 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3 ,
+.Xr utf2 4
+.Sh STANDARDS
+The
+.Fn setlocale
+and
+.Fn localeconv
+functions conform to
+.St -ansiC .
+.Sh HISTORY
+The
+.Fn setlocale
+and
+.Fn localeconv
+functions first appeared in 4.4BSD.
+.Sh BUGS
+The current implementation supports only the
+.Li "\&""C""
+and
+.Li "\&""POSIX""
+locales for all but the LC_CTYPE locale.
+.Pp
+In spite of the gnarly currency support in
+.Fn localeconv ,
+the standards don't include any functions
+for generalized currency formatting.
+.Pp
+.Dv LC_COLLATE
+does not make sense for many languages.
+Use of
+.Dv LC_MONETARY
+could lead to misleading results until we have a real time currency
+conversion function.
+.Dv LC_NUMERIC
+and
+.Dv LC_TIME
+are personal choices and should not be wrapped up with the other categories.
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c
index 247a2782b0c9..414f58ef381a 100644
--- a/lib/libc/locale/setlocale.c
+++ b/lib/libc/locale/setlocale.c
@@ -1,6 +1,9 @@
/*
- * Copyright (c) 1991 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,27 +35,200 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)setlocale.c 5.2 (Berkeley) 2/24/91";
+static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93";
#endif /* LIBC_SCCS and not lint */
+#include <limits.h>
#include <locale.h>
+#include <rune.h>
+#include <stdlib.h>
#include <string.h>
-static char C[] = "C";
+/*
+ * Category names for getenv()
+ */
+static char *categories[_LC_LAST] = {
+ "LC_ALL",
+ "LC_COLLATE",
+ "LC_CTYPE",
+ "LC_MONETARY",
+ "LC_NUMERIC",
+ "LC_TIME",
+};
/*
- * The setlocale function.
- *
- * Sorry, for now we only accept the C locale.
+ * Current locales for each category
*/
+static char current_categories[_LC_LAST][32] = {
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+ "C",
+};
+
+/*
+ * The locales we are going to try and load
+ */
+static char new_categories[_LC_LAST][32];
+
+static char current_locale_string[_LC_LAST * 33];
+static char *PathLocale;
+
+static char *currentlocale __P((void));
+static char *loadlocale __P((int));
+
char *
setlocale(category, locale)
int category;
const char *locale;
{
- if ((unsigned int)category >= _LC_LAST)
+ int found, i, len;
+ char *env, *r;
+
+ if (!PathLocale && !(PathLocale = getenv("PATH_LOCALE")))
+ PathLocale = _PATH_LOCALE;
+
+ if (category < 0 || category >= _LC_LAST)
return (NULL);
- if (locale == NULL)
- return (C);
- return(strcmp(locale, C) ? NULL : C);
+
+ if (!locale)
+ return (category ?
+ current_categories[category] : currentlocale());
+
+ /*
+ * Default to the current locale for everything.
+ */
+ for (i = 1; i < _LC_LAST; ++i)
+ (void)strcpy(new_categories[i], current_categories[i]);
+
+ /*
+ * Now go fill up new_categories from the locale argument
+ */
+ if (!*locale) {
+ env = getenv(categories[category]);
+
+ if (!env)
+ env = getenv(categories[0]);
+
+ if (!env)
+ env = getenv("LANG");
+
+ if (!env)
+ env = "C";
+
+ (void) strncpy(new_categories[category], env, 31);
+ new_categories[category][31] = 0;
+ if (!category) {
+ for (i = 1; i < _LC_LAST; ++i) {
+ if (!(env = getenv(categories[i])))
+ env = new_categories[0];
+ (void)strncpy(new_categories[i], env, 31);
+ new_categories[i][31] = 0;
+ }
+ }
+ } else if (category) {
+ (void)strncpy(new_categories[category], locale, 31);
+ new_categories[category][31] = 0;
+ } else {
+ if ((r = strchr(locale, '/')) == 0) {
+ for (i = 1; i < _LC_LAST; ++i) {
+ (void)strncpy(new_categories[i], locale, 31);
+ new_categories[i][31] = 0;
+ }
+ } else {
+ for (i = 1; r[1] == '/'; ++r);
+ if (!r[1])
+ return (NULL); /* Hmm, just slashes... */
+ do {
+ len = r - locale > 31 ? 31 : r - locale;
+ (void)strncpy(new_categories[i++], locale, len);
+ new_categories[i++][len] = 0;
+ locale = r;
+ while (*locale == '/')
+ ++locale;
+ while (*++r && *r != '/');
+ } while (*locale);
+ while (i < _LC_LAST)
+ (void)strcpy(new_categories[i],
+ new_categories[i-1]);
+ }
+ }
+
+ if (category)
+ return (loadlocale(category));
+
+ found = 0;
+ for (i = 1; i < _LC_LAST; ++i)
+ if (loadlocale(i) != NULL)
+ found = 1;
+ if (found)
+ return (currentlocale());
+ return (NULL);
+}
+
+static char *
+currentlocale()
+{
+ int i;
+
+ (void)strcpy(current_locale_string, current_categories[1]);
+
+ for (i = 2; i < _LC_LAST; ++i)
+ if (strcmp(current_categories[1], current_categories[i])) {
+ (void)snprintf(current_locale_string,
+ sizeof(current_locale_string), "%s/%s/%s/%s/%s",
+ current_categories[1], current_categories[2],
+ current_categories[3], current_categories[4],
+ current_categories[5]);
+ break;
+ }
+ return (current_locale_string);
+}
+
+static char *
+loadlocale(category)
+ int category;
+{
+ char name[PATH_MAX];
+
+ if (strcmp(new_categories[category],
+ current_categories[category]) == 0)
+ return (current_categories[category]);
+
+ if (category == LC_CTYPE) {
+ if (setrunelocale(new_categories[LC_CTYPE]))
+ return (NULL);
+ (void)strcpy(current_categories[LC_CTYPE],
+ new_categories[LC_CTYPE]);
+ return (current_categories[LC_CTYPE]);
+ }
+
+ if (!strcmp(new_categories[category], "C") ||
+ !strcmp(new_categories[category], "POSIX")) {
+
+ /*
+ * Some day this will need to reset the locale to the default
+ * C locale. Since we have no way to change them as of yet,
+ * there is no need to reset them.
+ */
+ (void)strcpy(current_categories[category],
+ new_categories[category]);
+ return (current_categories[category]);
+ }
+
+ /*
+ * Some day we will actually look at this file.
+ */
+ (void)snprintf(name, sizeof(name), "%s/%s/%s",
+ PathLocale, new_categories[category], categories[category]);
+
+ switch (category) {
+ case LC_COLLATE:
+ case LC_MONETARY:
+ case LC_NUMERIC:
+ case LC_TIME:
+ return (NULL);
+ }
}
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
new file mode 100644
index 000000000000..fb7344eafad5
--- /dev/null
+++ b/lib/libc/locale/table.c
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)table.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <rune.h>
+
+extern rune_t _none_sgetrune __P((const char *, size_t, char const **));
+extern int _none_sputrune __P((rune_t, char *, size_t, char **));
+extern int _none_init __P((char *, char **));
+
+_RuneLocale _DefaultRuneLocale = {
+ _RUNE_MAGIC_1,
+ "none",
+ _none_sgetrune,
+ _none_sputrune,
+ 0xFFFD,
+
+ { /*00*/ _C, _C, _C, _C,
+ _C, _C, _C, _C,
+ /*08*/ _C, _C|_S|_B, _C|_S, _C|_S,
+ _C|_S, _C|_S, _C, _C,
+ /*10*/ _C, _C, _C, _C,
+ _C, _C, _C, _C,
+ /*18*/ _C, _C, _C, _C,
+ _C, _C, _C, _C,
+ /*20*/ _S|_B|_R, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*28*/ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*30*/ _D|_R|_G|_X|0, _D|_R|_G|_X|1, _D|_R|_G|_X|2, _D|_R|_G|_X|3,
+ _D|_R|_G|_X|4, _D|_R|_G|_X|5, _D|_R|_G|_X|6, _D|_R|_G|_X|7,
+ /*38*/ _D|_R|_G|_X|8, _D|_R|_G|_X|9, _P|_R|_G, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*40*/ _P|_R|_G, _U|_X|_R|_G|_A|10, _U|_X|_R|_G|_A|11, _U|_X|_R|_G|_A|12,
+ _U|_X|_R|_G|_A|13, _U|_X|_R|_G|_A|14, _U|_X|_R|_G|_A|15, _U|_R|_G|_A,
+ /*48*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ /*50*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A,
+ /*58*/ _U|_R|_G|_A, _U|_R|_G|_A, _U|_R|_G|_A, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _P|_R|_G,
+ /*60*/ _P|_R|_G, _L|_X|_R|_G|_A|10, _L|_X|_R|_G|_A|11, _L|_X|_R|_G|_A|12,
+ _L|_X|_R|_G|_A|13, _L|_X|_R|_G|_A|14, _L|_X|_R|_G|_A|15, _L|_R|_G|_A,
+ /*68*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ /*70*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A,
+ /*78*/ _L|_R|_G|_A, _L|_R|_G|_A, _L|_R|_G|_A, _P|_R|_G,
+ _P|_R|_G, _P|_R|_G, _P|_R|_G, _C,
+ },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
+ 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
+ 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ },
+};
+
+_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
+
+int __mb_cur_max = 1;
diff --git a/lib/libc/locale/utf2.4 b/lib/libc/locale/utf2.4
new file mode 100644
index 000000000000..c46f4f986c41
--- /dev/null
+++ b/lib/libc/locale/utf2.4
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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.
+.\"
+.\" @(#)utf2.4 8.1 (Berkeley) 6/4/93
+.\"
+.Dd "June 4, 1993"
+.Dt UTF2 4
+.Os
+.Sh NAME
+.Nm UTF2
+.Nd "Universal character set Transformation Format encoding of runes
+.Sh SYNOPSIS
+\fBENCODING "UTF2"\fP
+.Sh DESCRIPTION
+The
+.Nm UTF2
+encoding is based on a proposed X-Open multibyte
+\s-1FSS-UCS-TF\s+1 (File System Safe Universal Character Set Transformation Format) encoding as used in
+.Nm Plan 9 from Bell Labs.
+Although it is capable of representing more than 16 bits,
+the current implementation is limited to 16 bits as defined by the
+Unicode Standard.
+UTF2 is also called UTF8 in some circles.
+.Pp
+.Nm UTF2
+representation is backwards compatible with ASCII, so 0x00-0x7f refer to the
+ASCII character set. The multibyte encoding of runes between 0x0080 and 0xffff
+consist entirely of bytes whose high order bit is set. The actual
+encoding is represented by the following table:
+.Bd -literal
+[0x0000 - 0x007f] [00000000.0bbbbbbb] -> 0bbbbbbb
+[0x0080 - 0x03ff] [00000bbb.bbbbbbbb] -> 110bbbbb, 10bbbbbb
+[0x0400 - 0xffff] [bbbbbbbb.bbbbbbbb] -> 1110bbbb, 10bbbbbb, 10bbbbbb
+.Ed
+.sp
+If more than a single representation of a value exists (for example,
+0x00; 0xC0 0x80; 0xE0 0x80 0x80) the shortest representation is always
+used (but the longer ones will be correctly decoded).
+.Pp
+The final three encodings provided by X-Open:
+.Bd -literal
+[00000000.000bbbbb.bbbbbbbb.bbbbbbbb] ->
+ 11110bbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+
+[000000bb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
+ 111110bb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+
+[0bbbbbbb.bbbbbbbb.bbbbbbbb.bbbbbbbb] ->
+ 1111110b, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb, 10bbbbbb
+.Ed
+.sp
+which provides for the entire proposed ISO-10646 31 bit standard are currently
+not implemented.
+.Sh "SEE ALSO"
+.Xr mklocale 1 ,
+.Xr setlocale 3
diff --git a/lib/libc/locale/utf2.c b/lib/libc/locale/utf2.c
new file mode 100644
index 000000000000..846fad90ed6f
--- /dev/null
+++ b/lib/libc/locale/utf2.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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[] = "@(#)utf2.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <errno.h>
+#include <rune.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+rune_t _UTF2_sgetrune __P((const char *, size_t, char const **));
+int _UTF2_sputrune __P((rune_t, char *, size_t, char **));
+
+static _utf_count[16] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 2, 2, 3, 0,
+};
+
+int
+_UTF2_init(rl)
+ _RuneLocale *rl;
+{
+ rl->sgetrune = _UTF2_sgetrune;
+ rl->sputrune = _UTF2_sputrune;
+ _CurrentRuneLocale = rl;
+ __mb_cur_max = 3;
+ return (0);
+}
+
+rune_t
+_UTF2_sgetrune(string, n, result)
+ const char *string;
+ size_t n;
+ char const **result;
+{
+ int c;
+
+ if (n < 1 || (c = _utf_count[(*string >> 4) & 0xf]) > n) {
+ if (result)
+ *result = string;
+ return (_INVALID_RUNE);
+ }
+ switch (c) {
+ case 1:
+ if (result)
+ *result = string + 1;
+ return (*string & 0xff);
+ case 2:
+ if ((string[1] & 0xC0) != 0x80)
+ goto encoding_error;
+ if (result)
+ *result = string + 2;
+ return (((string[0] & 0x1F) << 6) | (string[1] & 0x3F));
+ case 3:
+ if ((string[1] & 0xC0) != 0x80 || (string[2] & 0xC0) != 0x80)
+ goto encoding_error;
+ if (result)
+ *result = string + 3;
+ return (((string[0] & 0x1F) << 12) | ((string[1] & 0x3F) << 6)
+ | (string[2] & 0x3F));
+ default:
+encoding_error: if (result)
+ *result = string + 1;
+ return (_INVALID_RUNE);
+ }
+}
+
+int
+_UTF2_sputrune(c, string, n, result)
+ rune_t c;
+ char *string, **result;
+ size_t n;
+{
+ if (c & 0xF800) {
+ if (n >= 3) {
+ if (string) {
+ string[0] = 0xE0 | ((c >> 12) & 0x0F);
+ string[1] = 0x80 | ((c >> 6) & 0x3F);
+ string[2] = 0x80 | ((c) & 0x3F);
+ }
+ if (result)
+ *result = string + 3;
+ } else
+ if (result)
+ *result = NULL;
+
+ return (3);
+ } else
+ if (c & 0x0780) {
+ if (n >= 2) {
+ if (string) {
+ string[0] = 0xC0 | ((c >> 6) & 0x1F);
+ string[1] = 0x80 | ((c) & 0x3F);
+ }
+ if (result)
+ *result = string + 2;
+ } else
+ if (result)
+ *result = NULL;
+ return (2);
+ } else {
+ if (n >= 1) {
+ if (string)
+ string[0] = c;
+ if (result)
+ *result = string + 1;
+ } else
+ if (result)
+ *result = NULL;
+ return (1);
+ }
+}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 2b1597a20796..b4c154672d58 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -120,6 +120,7 @@ init_services()
service_order[cc++] = SERVICE_NIS;
}
service_order[cc] = SERVICE_NONE;
+ fclose(fd);
}
service_done = 1;
}
diff --git a/lib/libc/net/ns_addr.c b/lib/libc/net/ns_addr.c
index e31e6d13570f..684dd8e79165 100644
--- a/lib/libc/net/ns_addr.c
+++ b/lib/libc/net/ns_addr.c
@@ -55,8 +55,8 @@ ns_addr(name)
char *hostname, *socketname, *cp;
char buf[50];
- (void)strncpy(buf, name, sizeof(buf - 1));
- buf[sizeof(buf - 1)] = '\0';
+ (void)strncpy(buf, name, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
/*
* First, figure out what he intends as a field separtor.
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c
index d0cd18000ba9..5d1a575fe110 100644
--- a/lib/libc/net/rcmd.c
+++ b/lib/libc/net/rcmd.c
@@ -38,6 +38,7 @@ static char sccsid[] = "@(#)rcmd.c 5.24 (Berkeley) 2/24/91";
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
@@ -138,7 +139,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
FD_SET(s, &reads);
FD_SET(s2, &reads);
errno = 0;
- if (select(32, &reads, 0, 0, 0) < 1 ||
+ if (select(FD_SETSIZE, &reads, 0, 0, 0) < 1 ||
!FD_ISSET(s2, &reads)) {
if (errno != 0)
perror("select: setting up stderr");
@@ -230,6 +231,12 @@ ruserok(rhost, superuser, ruser, luser)
int first = 1;
register char *sp, *p;
int baselen = -1;
+ uid_t suid;
+ gid_t sgid;
+ int int_sgid; /* this is a kludge and should be removed
+ when we transition to FreeBSD 2.0. If you
+ find this code in a 2.0 source tree, please
+ contact the core team. */
sp = (char *)rhost;
p = fhost;
@@ -248,6 +255,12 @@ again:
if (hostf) {
if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
(void) fclose(hostf);
+ if (first == 0) {
+ (void)seteuid(suid);
+ (void)setegid(sgid);
+ int_sgid = sgid;
+ (void)setgroups(1, &int_sgid);
+ }
return(0);
}
(void) fclose(hostf);
@@ -258,12 +271,17 @@ again:
char pbuf[MAXPATHLEN];
first = 0;
+ suid = geteuid();
+ sgid = getegid();
if ((pwd = getpwnam(luser)) == NULL)
return(-1);
+ (void)setegid(pwd->pw_gid);
+ (void)initgroups(luser, pwd->pw_gid);
+ (void)seteuid(pwd->pw_uid);
(void)strcpy(pbuf, pwd->pw_dir);
(void)strcat(pbuf, "/.rhosts");
if ((hostf = fopen(pbuf, "r")) == NULL)
- return(-1);
+ goto bad;
/*
* if owned by someone other than user or root or if
* writeable by anyone but the owner, quit
@@ -272,10 +290,16 @@ again:
sbuf.st_uid && sbuf.st_uid != pwd->pw_uid ||
sbuf.st_mode&022) {
fclose(hostf);
- return(-1);
+ goto bad;
}
goto again;
}
+bad:
+ if (first == 0) {
+ (void)seteuid(suid);
+ (void)setegid(sgid);
+ (void)setgroups(1, (int *)&sgid);
+ }
return (-1);
}
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc
index ad87006fbac7..3fd05f51ffc3 100644
--- a/lib/libc/stdio/Makefile.inc
+++ b/lib/libc/stdio/Makefile.inc
@@ -3,8 +3,9 @@
# stdio sources
.PATH: ${.CURDIR}/stdio
-SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
- fgetline.c fgetpos.c fgets.c fileno.c findfp.c flags.c fopen.c \
+SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c \
+ fgetc.c fgetline.c fgetln.c fgetpos.c fgets.c \
+ fileno.c findfp.c flags.c fopen.c \
fprintf.c fpurge.c fputc.c fputs.c fread.c freopen.c fscanf.c \
fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwrite.c \
getc.c getchar.c gets.c getw.c makebuf.c perror.c printf.c putc.c \
@@ -14,7 +15,7 @@ SRCS+= clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \
vfscanf.c vprintf.c vscanf.c vsnprintf.c vsprintf.c vsscanf.c \
wbuf.c wsetup.c
-MAN3+= stdio/fclose.3 stdio/ferror.3 stdio/fflush.3 stdio/fgetline.3 \
+MAN3+= stdio/fclose.3 stdio/ferror.3 stdio/fflush.3 stdio/fgetln.3 \
stdio/fgets.3 stdio/fopen.3 stdio/fputs.3 stdio/fread.3 \
stdio/fseek.3 stdio/funopen.3 stdio/getc.3 stdio/mktemp.3 \
stdio/printf.3 stdio/putc.3 stdio/remove.3 stdio/scanf.3 \
diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c
index 27d873f2073f..974cd444853d 100644
--- a/lib/libc/stdio/fclose.c
+++ b/lib/libc/stdio/fclose.c
@@ -48,7 +48,7 @@ fclose(fp)
{
register int r;
- if (fp->_flags == 0) { /* not open! */
+ if (!fp || (fp->_flags == 0)) { /* not open! */
errno = EBADF;
return (EOF);
}
diff --git a/lib/libc/stdio/fgetline.c b/lib/libc/stdio/fgetline.c
index bcd80aca4e86..70fe9d65fe5b 100644
--- a/lib/libc/stdio/fgetline.c
+++ b/lib/libc/stdio/fgetline.c
@@ -48,6 +48,7 @@ static char sccsid[] = "@(#)fgetline.c 5.2 (Berkeley) 5/4/91";
* The `new size' does not account for a terminating '\0',
* so we add 1 here.
*/
+static int
__slbexpand(fp, newsize)
FILE *fp;
size_t newsize;
diff --git a/lib/libc/stdio/fgetline.3 b/lib/libc/stdio/fgetln.3
index 745e745c66f6..a453cff29c13 100644
--- a/lib/libc/stdio/fgetline.3
+++ b/lib/libc/stdio/fgetln.3
@@ -1,5 +1,5 @@
-.\" Copyright (c) 1990, 1991 The Regents of the University of California.
-.\" All rights reserved.
+.\" Copyright (c) 1990, 1991, 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
@@ -29,32 +29,37 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)fgetline.3 5.4 (Berkeley) 4/19/91
+.\" from: @(#)fgetline.3 8.1 (Berkeley) 6/9/93
+.\" $Id: fgetln.3,v 1.1 1994/04/17 09:16:36 alm Exp $
.\"
-.Dd April 19, 1991
-.Dt FGETLINE 3
+.Dd June 9, 1993
+.Dt FGETLN 3
.Os
.Sh NAME
-.Nm fgetline
+.Nm fgetln
.Nd get a line from a stream
.Sh SYNOPSIS
.Fd #include <stdio.h>
.Ft char *
-.Fn fgetline "FILE *stream" "size_t *len"
+.Fn fgetln "FILE *stream" "size_t *len"
.Sh DESCRIPTION
The
-.Fn fgetline
+.Fn fgetln
function
returns a pointer to the next line from the stream referenced by
.Fa stream .
-The newline character at the end of the line is replaced by a
-.Dv NUL .
-.Pp
-If
+This line is
+.Em not
+a C string as it does not end with a terminating
+.Dv NUL
+character.
+The length of the line, including the final newline,
+is stored in the memory location to which
.Fa len
-is non-NULL, the length of the line, not counting the terminating
-.Dv NUL ,
-is stored in the memory location it references.
+points.
+(Note, however, that if the line is the last
+in a file that does not end in a newline,
+the returned text will not contain a newline.)
.Sh RETURN VALUES
Upon successful completion a pointer is returned;
this pointer becomes invalid after the next
@@ -67,7 +72,7 @@ Otherwise,
.Dv NULL
is returned.
The
-.Fn fgetline
+.Fn fgetln
function
does not distinguish between end-of-file and error; the routines
.Xr feof 3
@@ -75,7 +80,7 @@ and
.Xr ferror 3
must be used
to determine which occurred.
-If an error occurrs, the global variable
+If an error occurs, the global variable
.Va errno
is set to indicate the error.
The end-of-file condition is remembered, even on a terminal, and all
@@ -86,8 +91,7 @@ cleared with
.Xr clearerr 3 .
.Pp
The text to which the returned pointer points may be modified,
-provided that no changes are made beyond the terminating
-.Dv NUL .
+provided that no changes are made beyond the returned size.
These changes are lost as soon as the pointer becomes invalid.
.Sh ERRORS
.Bl -tag -width [EBADF]
@@ -98,7 +102,7 @@ is not a stream open for reading.
.El
.Pp
The
-.Fn fgetline
+.Fn fgetln
function
may also fail and set
.Va errno
@@ -116,9 +120,5 @@ or
.Xr putc 3
.Sh HISTORY
The
-.Fn fgetline
-function is
-.Ud .
-.Sh BUGS
-It is not possible to tell whether the final line of an input file
-was terminated with a newline.
+.Fn fgetln
+function first appeared in 4.4BSD.
diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c
new file mode 100644
index 000000000000..992b4b57e088
--- /dev/null
+++ b/lib/libc/stdio/fgetln.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+/* from: static char sccsid[] = "@(#)fgetline.c 8.1 (Berkeley) 6/4/93"; */
+static char *rcsid = "$Id: fgetln.c,v 1.1 1994/04/17 09:16:39 alm Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "local.h"
+
+/*
+ * Expand the line buffer. Return -1 on error.
+#ifdef notdef
+ * The `new size' does not account for a terminating '\0',
+ * so we add 1 here.
+#endif
+ */
+int
+__slbexpand(fp, newsize)
+ FILE *fp;
+ size_t newsize;
+{
+ void *p;
+
+#ifdef notdef
+ ++newsize;
+#endif
+ if (fp->_lb._size >= newsize)
+ return (0);
+ if ((p = realloc(fp->_lb._base, newsize)) == NULL)
+ return (-1);
+ fp->_lb._base = p;
+ fp->_lb._size = newsize;
+ return (0);
+}
+
+/*
+ * Get an input line. The returned pointer often (but not always)
+ * points into a stdio buffer. Fgetline does not alter the text of
+ * the returned line (which is thus not a C string because it will
+ * not necessarily end with '\0'), but does allow callers to modify
+ * it if they wish. Thus, we set __SMOD in case the caller does.
+ */
+char *
+fgetln(fp, lenp)
+ register FILE *fp;
+ size_t *lenp;
+{
+ register unsigned char *p;
+ register size_t len;
+ size_t off;
+
+ /* make sure there is input */
+ if (fp->_r <= 0 && __srefill(fp)) {
+ *lenp = 0;
+ return (NULL);
+ }
+
+ /* look for a newline in the input */
+ if ((p = memchr((void *)fp->_p, '\n', fp->_r)) != NULL) {
+ register char *ret;
+
+ /*
+ * Found one. Flag buffer as modified to keep fseek from
+ * `optimising' a backward seek, in case the user stomps on
+ * the text.
+ */
+ p++; /* advance over it */
+ ret = (char *)fp->_p;
+ *lenp = len = p - fp->_p;
+ fp->_flags |= __SMOD;
+ fp->_r -= len;
+ fp->_p = p;
+ return (ret);
+ }
+
+ /*
+ * We have to copy the current buffered data to the line buffer.
+ * As a bonus, though, we can leave off the __SMOD.
+ *
+ * OPTIMISTIC is length that we (optimistically) expect will
+ * accomodate the `rest' of the string, on each trip through the
+ * loop below.
+ */
+#define OPTIMISTIC 80
+
+ for (len = fp->_r, off = 0;; len += fp->_r) {
+ register size_t diff;
+
+ /*
+ * Make sure there is room for more bytes. Copy data from
+ * file buffer to line buffer, refill file and look for
+ * newline. The loop stops only when we find a newline.
+ */
+ if (__slbexpand(fp, len + OPTIMISTIC))
+ goto error;
+ (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ len - off);
+ off = len;
+ if (__srefill(fp))
+ break; /* EOF or error: return partial line */
+ if ((p = memchr((void *)fp->_p, '\n', fp->_r)) == NULL)
+ continue;
+
+ /* got it: finish up the line (like code above) */
+ p++;
+ diff = p - fp->_p;
+ len += diff;
+ if (__slbexpand(fp, len))
+ goto error;
+ (void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
+ diff);
+ fp->_r -= diff;
+ fp->_p = p;
+ break;
+ }
+ *lenp = len;
+#ifdef notdef
+ fp->_lb._base[len] = 0;
+#endif
+ return ((char *)fp->_lb._base);
+
+error:
+ *lenp = 0; /* ??? */
+ return (NULL); /* ??? */
+}
diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c
index a027109e5659..a8fb89449ed0 100644
--- a/lib/libc/stdio/fseek.c
+++ b/lib/libc/stdio/fseek.c
@@ -197,7 +197,7 @@ fseek(fp, offset, whence)
* If the target offset is within the current buffer,
* simply adjust the pointers, clear EOF, undo ungetc(),
* and return. (If the buffer was modified, we have to
- * skip this; see fgetline.c.)
+ * skip this; see fgetln.c.)
*/
if ((fp->_flags & __SMOD) == 0 &&
target >= curoff && target < curoff + n) {
diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c
index 4f1622369dbc..12fc115bc64f 100644
--- a/lib/libc/stdio/gets.c
+++ b/lib/libc/stdio/gets.c
@@ -35,11 +35,16 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)gets.c 5.3 (Berkeley) 1/20/91";
+static char sccsid[] = "From: @(#)gets.c 5.3 (Berkeley) 1/20/91";
+static char rcsid[] =
+ "$Id: gets.c,v 1.3 1994/04/23 20:35:27 wollman Exp $";
#endif /* LIBC_SCCS and not lint */
#include <unistd.h>
#include <stdio.h>
+#include <string.h>
+
+#define MESSAGE ": warning: this program uses gets(), which is unsafe.\r\n"
char *
gets(buf)
@@ -48,11 +53,11 @@ gets(buf)
register int c;
register char *s;
static int warned;
- static char w[] =
- "warning: this program uses gets(), which is unsafe.\r\n";
if (!warned) {
- (void) write(STDERR_FILENO, w, sizeof(w) - 1);
+ extern char *__progname;
+ write(2, __progname, strlen(__progname));
+ write(2, MESSAGE, sizeof(MESSAGE) - 1);
warned = 1;
}
for (s = buf; (c = getchar()) != '\n';)
diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h
index 21966d704dbd..87ed4e60d23e 100644
--- a/lib/libc/stdio/local.h
+++ b/lib/libc/stdio/local.h
@@ -78,7 +78,7 @@ extern int __sdidinit;
}
/*
- * test for an fgetline() buffer.
+ * test for an fgetln() buffer.
*/
#define HASLB(fp) ((fp)->_lb._base != NULL)
#define FREELB(fp) { \
diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3
index 130246ea1b0a..0d7c52873881 100644
--- a/lib/libc/stdio/printf.3
+++ b/lib/libc/stdio/printf.3
@@ -402,7 +402,7 @@ are used for
conversions; the letters
.Cm ABCDEF
are used for
-.m X
+.Cm X
conversions.
The precision, if any, gives the minimum number of digits that must
appear; if the converted value requires fewer digits, it is padded on
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index 0bd1a90ab56a..c5736ba7172f 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -4,7 +4,7 @@
.PATH: ${.CURDIR}/${MACHINE}/stdlib ${.CURDIR}/stdlib
SRCS+= abort.c atexit.c atoi.c atol.c bsearch.c calloc.c exit.c \
- getenv.c getopt.c heapsort.c malloc.c multibyte.c \
+ getenv.c getopt.c heapsort.c malloc.c \
putenv.c qsort.c radixsort.c rand.c random.c setenv.c strtod.c \
strtol.c strtoul.c system.c \
_rand48.c drand48.c erand48.c jrand48.c lcong48.c lrand48.c \
diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c
index f96af3005605..3879281d2581 100644
--- a/lib/libc/stdlib/rand.c
+++ b/lib/libc/stdlib/rand.c
@@ -43,7 +43,7 @@ static u_long next = 1;
int
rand()
{
- return ((next = next * 1103515245 + 12345) % (RAND_MAX + 1));
+ return ((next = next * 1103515245 + 12345) % ((u_long)RAND_MAX + 1));
}
void
diff --git a/lib/libc/string/index.3 b/lib/libc/string/index.3
index 12ca7112a402..f387409fc51f 100644
--- a/lib/libc/string/index.3
+++ b/lib/libc/string/index.3
@@ -54,7 +54,7 @@ locates the first character matching
in the null-terminated string
.Fa s .
.Sh RETURN VALUES
-The character
+The location of the character
.Fa c
is returned if it is found; otherwise
.Dv NULL
diff --git a/lib/libc/string/strftime.c b/lib/libc/string/strftime.c
index 16879d256821..99c68f9b31e2 100644
--- a/lib/libc/string/strftime.c
+++ b/lib/libc/string/strftime.c
@@ -196,6 +196,7 @@ _fmt(format, t)
case 'R':
if (!_fmt("%H:%M", t))
return(0);
+ continue;
case 'r':
if (!_fmt(t_fmt_ampm, t))
return(0);
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 3deb3bbcc702..d0689839bf9d 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -1,4 +1,5 @@
-# @(#)Makefile.inc 5.11 (Berkeley) 6/23/91
+# From: @(#)Makefile.inc 5.11 (Berkeley) 6/23/91
+# $Id: Makefile.inc,v 1.16 1994/03/16 19:01:06 wollman Exp $
# sys sources
.PATH: ${.CURDIR}/${MACHINE}/sys ${.CURDIR}/sys
@@ -19,7 +20,8 @@ ASM= accept.o access.o acct.o adjtime.o async_daemon.o bind.o chdir.o \
getpriority.o getrlimit.o getrusage.o getsockname.o getsockopt.o \
gettimeofday.o getuid.o ioctl.o kill.o ktrace.o link.o listen.o \
lseek.o lstat.o madvise.o mincore.o mkdir.o mkfifo.o mknod.o \
- mmap.o mount.o mprotect.o msgsys.o msync.o munmap.o nfssvc.o open.o \
+ mmap.o mount.o mprotect.o msgsys.o msync.o munmap.o nfssvc.o \
+ ntp_adjtime.o ntp_gettime.o open.o \
profil.o quotactl.o read.o readlink.o readv.o recvfrom.o recvmsg.o \
rename.o revoke.o rmdir.o select.o semsys.o sendmsg.o sendto.o \
setdomainname.o setegid.o seteuid.o setgid.o setgroups.o sethostid.o \
@@ -96,7 +98,7 @@ MAN2+= sys/accept.2 sys/access.2 sys/acct.2 sys/adjtime.2 sys/async_daemon.2 \
sys/msync.2 sys/munmap.2 sys/nfssvc.2 sys/open.2 sys/pipe.2 \
sys/quotactl.2 sys/read.2 sys/readlink.2 sys/reboot.2 sys/recv.2 \
sys/rename.2 sys/rmdir.2 sys/select.2 sys/send.2 sys/setgroups.2 \
- sys/setpgid.2 sys/setregid.2 sys/setreuid.2 sys/setsid.2 \
+ sys/setpgid.2 sys/setregid.2 sys/setreuid.2 sys/setsid.2 sys/setuid.2 \
sys/shutdown.2 sys/sigaction.2 sys/sigprocmask.2 sys/sigreturn.2 \
sys/sigstack.2 sys/sigsuspend.2 sys/socket.2 sys/socketpair.2 \
sys/stat.2 sys/statfs.2 sys/swapon.2 sys/symlink.2 sys/sync.2 \
@@ -127,6 +129,7 @@ MLINKS+=mount.2 unmount.2
MLINKS+=read.2 readv.2
MLINKS+=recv.2 recvfrom.2 recv.2 recvmsg.2
MLINKS+=send.2 sendmsg.2 send.2 sendto.2
+MLINKS+=setuid.2 setegid.2 setuid.2 seteuid.2 setuid.2 setgid.2
MLINKS+=setpgid.2 setpgrp.2
MLINKS+=stat.2 fstat.2 stat.2 lstat.2
MLINKS+=statfs.2 fstatfs.2
diff --git a/lib/libc/sys/execve.2 b/lib/libc/sys/execve.2
index 726de1f88448..48405320181d 100644
--- a/lib/libc/sys/execve.2
+++ b/lib/libc/sys/execve.2
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)execve.2 6.9 (Berkeley) 3/10/91
-.\" $Id: execve.2,v 1.2.2.1 1994/05/01 16:06:05 jkh Exp $
+.\" $Id: execve.2,v 1.4 1994/03/16 19:10:39 wollman Exp $
.\"
.Dd March 16, 1994
.Dt EXECVE 2
diff --git a/lib/libc/sys/setregid.2 b/lib/libc/sys/setregid.2
index 86b0aa7949be..764f89403e3a 100644
--- a/lib/libc/sys/setregid.2
+++ b/lib/libc/sys/setregid.2
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)setregid.2 6.4 (Berkeley) 3/10/91
-.\" $Id: setregid.2,v 1.1.1.1.2.1 1994/05/01 16:06:13 jkh Exp $
+.\" $Id: setregid.2,v 1.2 1994/03/16 19:01:08 wollman Exp $
.\"
.Dd March 16, 1994
.Dt SETREGID 2
diff --git a/lib/libc/sys/setreuid.2 b/lib/libc/sys/setreuid.2
index de34b029ab57..62f5dcdae68d 100644
--- a/lib/libc/sys/setreuid.2
+++ b/lib/libc/sys/setreuid.2
@@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" From: @(#)setreuid.2 6.4 (Berkeley) 3/10/91
-.\" $Id: setreuid.2,v 1.1.1.1.2.1 1994/05/01 16:06:14 jkh Exp $
+.\" $Id: setreuid.2,v 1.2 1994/03/16 19:01:09 wollman Exp $
.\"
.Dd March 16, 1994
.Dt SETREUID 2
diff --git a/lib/libc/gen/setuid.3 b/lib/libc/sys/setuid.2
index 4e0e4c3c9ea5..eb596cc4918f 100644
--- a/lib/libc/gen/setuid.3
+++ b/lib/libc/sys/setuid.2
@@ -29,18 +29,19 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)setuid.3 6.4 (Berkeley) 4/19/91
+.\" From: @(#)setuid.3 6.4 (Berkeley) 4/19/91
+.\" $Id: setuid.2,v 1.2 1994/04/21 21:30:20 wollman Exp $
.\"
-.Dd April 19, 1991
-.Dt SETUID 3
-.Os BSD 4.2
+.Dd March 16, 1994
+.Dt SETUID 2
+.Os
.Sh NAME
.Nm setuid ,
.Nm seteuid ,
-.Nm setruid ,
+.\" .Nm setruid ,
.Nm setgid ,
.Nm setegid ,
-.Nm setrgid
+.\" .Nm setrgid
.Nd set user and group ID
.Sh SYNOPSIS
.Fd #include <sys/types.h>
@@ -48,21 +49,21 @@
.Fn setuid "uid_t uid"
.Ft int
.Fn seteuid "uid_t euid"
-.Ft int
-.Fn setruid "uid_t ruid"
+.\" .Ft int
+.\" .Fn setruid "uid_t ruid"
.Ft int
.Fn setgid "gid_t gid"
.Ft int
.Fn setegid "gid_t egid"
-.Ft int
-.Fn setrgid "gid_t rgid"
+.\" .Ft int
+.\" .Fn setrgid "gid_t rgid"
.Sh DESCRIPTION
The
.Fn setuid
function
.Pq Fn setgid
-sets both the real and effective
-user ID (group ID) of the current process
+sets the real, effective, and saved
+user IDs (group IDs) of the current process
as specified.
.Pp
The
@@ -71,25 +72,46 @@ function
.Pq Fn setegid
sets the effective user ID (group ID) of the
current process.
+.\".Pp
+.\" The
+.\" .Fn setruid
+.\" function
+.\" .Pq Fn setrgid
+.\" sets the real user ID (group ID) of the
+.\" current process.
.Pp
-The
-.Fn setruid
-function
-.Pq Fn setrgid
-sets the real user ID (group ID) of the
-current process.
+When any of these calls succeed, the
+.Dv SUGID
+process flag is turned on, and remains on until the process calls
+.Xr execve 2 ;
+this flag can be inspected with
+.Xr ps 1 .
.Sh RETURN VALUES
Upon success, these functions return 0;
otherwise \-1 is returned.
.Pp
-If the user is not the super user, or the uid
-specified is not the real or effective ID, these
+If the user is not the super user, and the ID specified is not the
+current real ID, the
+.Nm setuid
+and
+.Nm setgid
+functions return \-1.
+.Pp
+If the user is not the super user, and the ID specfied is not the
+current real ID, the
+.\" nor the saved ID, the
+.\" should this really be true that setuid(geteuid()) is not allowed?
+.Nm seteuid
+and
+.Nm setegid
functions return \-1.
.Sh SEE ALSO
.Xr setreuid 2 ,
.Xr setregid 2 ,
.Xr getuid 2 ,
-.Xr getgid 2
+.Xr getgid 2 ,
+.Xr execve 2 ,
+.Xr ps 1
.Sh HISTORY
A
.Fn setuid
diff --git a/lib/libc/sys/sigsuspend.2 b/lib/libc/sys/sigsuspend.2
index 8e0c73001c10..2b09e707f5e5 100644
--- a/lib/libc/sys/sigsuspend.2
+++ b/lib/libc/sys/sigsuspend.2
@@ -36,7 +36,7 @@
.Os
.Sh NAME
.Nm sigsuspend
-.Nd automatically release blocked signals and wait for interrupt
+.Nd atomically release blocked signals and wait for interrupt
.Sh SYNOPSIS
.Fd #include <sys/signal.h>
.Ft int
@@ -74,7 +74,7 @@ set to
.Xr sigsetops 3
.Sh STANDARDS
The
-.Nm sigsupend
+.Nm sigsuspend
function call
conforms to
.St -p1003.1-88 .
diff --git a/lib/libcompat/Makefile b/lib/libcompat/Makefile
new file mode 100644
index 000000000000..b4209eef15b8
--- /dev/null
+++ b/lib/libcompat/Makefile
@@ -0,0 +1,18 @@
+LIB= compat
+NOPIC= we dont need PIC for these puppies
+
+SRCS= sgtty.c ftime.c cftime.c regex.c setrgid.c setruid.c
+
+MAN3= libcompat.3
+
+MLINKS= libcompat.3 stty.3 libcompat.3 gtty.3 \
+ libcompat.3 ftime.3 \
+ libcompat.3 cftime.3 libcompat.3 ascftime.3 \
+ libcompat.3 re_exec.3 libcompat.3 re_comp.3 \
+ libcompat.3 setrgid.3 libcompat.3 setruid.3
+
+# Henry Spencer's regexp library from the UoT is
+# kept in a separate subdirectory
+.include "${.CURDIR}/regexp/Makefile.inc"
+
+.include <bsd.lib.mk>
diff --git a/lib/libcompat/cftime.c b/lib/libcompat/cftime.c
new file mode 100644
index 000000000000..8edb078b64ea
--- /dev/null
+++ b/lib/libcompat/cftime.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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 <time.h>
+
+#define MAXLEN 1000 /* just a guess, only the user knows... */
+
+int
+#if __STDC__
+cftime(char *s, char *format, const time_t *clock)
+#else
+cftime(s, format, clock)
+ char *s;
+ char *format;
+ time_t *clock;
+#endif
+{
+ return strftime(s, MAXLEN, format? format: "%C", localtime(clock));
+}
+
+int
+#if __STDC__
+ascftime(char *s, const char *format, const struct tm *tmptr)
+#else
+ascftime(s, format, tmptr)
+ char *s;
+ char *format;
+ struct tm *tmptr;
+#endif
+{
+ return strftime(s, MAXLEN, format? format: "%C", tmptr);
+}
diff --git a/lib/libcompat/ftime.c b/lib/libcompat/ftime.c
new file mode 100644
index 000000000000..74c1c21f9992
--- /dev/null
+++ b/lib/libcompat/ftime.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+/*
+ * ftime.c
+ * get time, OBSOLETED BY gettimeofday(2)
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+
+int
+#if __STDC__
+ftime(struct timeb *tp)
+#else
+ftime(tp)
+ struct timeb *tp;
+#endif
+{
+ struct timeval tv;
+ struct timezone tz;
+
+ if(gettimeofday(&tv, &tz) < 0)
+ return -1; /* any error */
+
+ tp->time = tv.tv_sec;
+ tp->millitm = tv.tv_usec / 1000;
+ /*
+ * timezone and dstflag below are bogus
+ * the timezone is no longer part of the kernel, thus the information
+ * obtained by gettimeofday() wrt. the timezone is useless
+ */
+ tp->timezone = tz.tz_minuteswest;
+ tp->dstflag = tz.tz_dsttime != DST_NONE;
+ return 0;
+}
diff --git a/lib/libcompat/libcompat.3 b/lib/libcompat/libcompat.3
new file mode 100644
index 000000000000..b18d0b79f3ba
--- /dev/null
+++ b/lib/libcompat/libcompat.3
@@ -0,0 +1,205 @@
+.\"
+.\" Copyright (c) 1994 Joerg Wunsch
+.\"
+.\" All rights reserved.
+.\"
+.\" This program is free software.
+.\"
+.\" 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 Joerg Wunsch
+.\" 4. The name of the developer may not be used to endorse or promote
+.\" products derived from this software without specific prior written
+.\" permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+.\"
+.\"
+.\" libcompat man page,
+.\" written June 15, 1993 by Joerg Wunsch
+.\"
+.Dd June 15, 1993
+.Os
+.Dt LIBCOMPAT 3
+.Sh NAME
+.Nm libcompat
+.Nd compatibility library for older programs
+.Sh SYNOPSIS
+.Fd #include <sgtty.h>
+.Fn "int stty" "int fd" "struct sgttyb *s" ;
+.Fn "int gtty" "int fd" "struct sgttyb *s" ;
+.Fd #include <sys/timeb.h>
+.Fn "int ftime" "struct timeb *tp" ;
+.Fd #include <time.h>
+.Fn "int cftime" "char *s" "char *format" "const time_t *clock" ;
+.Fn "int ascftime" "char *s" "const char *format" "const struct tm *tmptr" ;
+
+.Fn "char *re_comp" "char *s" ;
+.Fn "int re_exec" "char *s" ;
+.Fd #include <sys/types.h>
+.Fn "int setruid" "uid_t uid" ;
+.Fn "int setrgid" "gid_t gid" ;
+.Sh DESCRIPTION
+.Em The functions described here are obsoleted .
+.Em The sole purpose \&of this library \&is providing
+.Em a compatibility module for older programs .
+To use the library, an option of
+.Fl lcompat
+has to be specified when linking those programs.
+
+The functions
+.Nm stty
+and
+.Nm gtty
+set or get, respectively, the terminal control flags from/into a
+variable of type
+.Em struct sgttyb .
+They are obsoleted by the new terminal controlling interface, see
+.Xr termios 3 .
+There used to be macros instead of functions, too.
+
+The function
+.Nm ftime
+returns information on the current time as well as the timezone.
+It is obsoleted by
+.Xr gettimeofday 3 .
+Note further that the timezone information is no longer kept inside
+the kernel, hence neither
+.Xr gettimeofday 3 ,
+nor
+.Nm ftime
+will return useful values for their timezone-related arguments. See
+.Xr tzset 3
+and
+.Xr ctime 3
+for an up-to-date timezone handling.
+
+Use of the functions
+.Nm cftime
+and
+.Nm ascftime
+is strongly deprecated, since there is no way to check for a buffer
+overflow condition. Use
+.Xr strftime 3
+instead.
+
+.Nm Ascftime
+is almost identical with
+.Xr strftime 3 ,
+with the only exception there's no parameter to tell about the
+maximal buffer length, and the
+.Ar format
+parameter defaults to
+.Dq %C
+if a
+.Em NULL
+pointer is given.
+
+.Nm Cftime
+does the same job, but it first invokes
+.Xr localtime 3
+in order to convert the given
+.Ar clock ,
+then also performs the conversions as requested by the
+.Ar format
+argument.
+
+.Nm Setruid
+and
+.Nm setrgid
+have been used previously to set the real user-ID or real group-ID,
+respectively. They are no longer available, because they are
+incompatible with the POSIX security model. If a process wants to set
+its real user-ID, then it must also simultaneously set its effective and
+saved IDs, which is what
+.Nm setuid
+does. Similiar considerations apply to
+.Nm setrgid .
+
+The functions
+.Nm re_comp
+and
+.Nm re_exec
+provide a traditional interface to the regular expression matching
+routines
+.Xr regcomp 3
+and
+.Xr regexec 3 .
+
+.Nm Re_comp
+compiles a string into an internal form suitable for pattern
+matching.
+.Nm Re_exec
+checks the argument string against the last string
+passed to
+.Nm re_comp .
+
+.Nm Re_comp
+returns 0 if the string s was compiled successfully;
+otherwise a string containing an error message is returned. If
+.Nm re_comp
+is passed 0 or a null string, it returns without changing the
+currently compiled regular expression.
+
+.Nm Re_exec
+returns 1 if the string s matches the last compiled regular
+expression, 0 if the string s failed to match the last compiled
+regular expression, and -1 if the compiled regular expression was
+invalid
+.Pq indicating an internal error .
+
+Note that
+.Nm re_comp
+and
+.Nm re_exec
+need the
+.Xr regexp 3
+library with the traditional
+.Pq V8
+function call interface rather than the new library as
+contained in the standard C library. The
+.Xr regexp 3
+library is also part of libcompat.a.
+
+.Sh RETURN VALUES
+The functions usually return with a negative value on error.
+
+The
+.Nm cftime
+and
+.Nm ascftime
+function return the number of characters written to the output
+buffer
+.Ar s ,
+not counting the trailing null character.
+
+.Sh SEE ALSO
+.Xr termios 3 ;
+.Xr gettimeofday 3 ;
+.Xr strftime 3 ,
+.Xr tzset 3 ,
+.Xr ctime 3 ,
+.Xr localtime 3 ;
+.Xr setreuid 2 ,
+.Xr setuid 3 ,
+.Xr setregid 2 ,
+.Xr setgid 3 ;
+.Xr regcomp 3 ,
+.Xr regexec 3 .
diff --git a/lib/libcompat/regex.c b/lib/libcompat/regex.c
new file mode 100644
index 000000000000..7760f9f87a4f
--- /dev/null
+++ b/lib/libcompat/regex.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1992 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James da Silva at the University of Maryland at College Park.
+ *
+ * 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.
+ */
+
+/*
+ * Compatibility routines that implement the old re_comp/re_exec interface in
+ * terms of the regcomp/regexec interface. It's possible that some programs
+ * rely on dark corners of re_comp/re_exec and won't work with this version,
+ * but most programs should be fine.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)regex.c 5.1 (Berkeley) 3/29/92";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <regexp.h>
+#include <string.h>
+#include <stdlib.h>
+
+static regexp *re_regexp;
+static int re_goterr;
+static char *re_errstr;
+
+char *
+re_comp(s)
+ char *s;
+{
+ if (s == NULL)
+ return (NULL);
+ if (re_regexp)
+ free(re_regexp);
+ if (re_errstr)
+ free(re_errstr);
+ re_goterr = 0;
+ re_regexp = regcomp(s);
+ return (re_goterr ? re_errstr : NULL);
+}
+
+int
+re_exec(s)
+ char *s;
+{
+ int rc;
+
+ re_goterr = 0;
+ rc = regexec(re_regexp, s);
+ return (re_goterr ? -1 : rc);
+}
+
+void
+regerror(s)
+ const char *s;
+{
+ re_goterr = 1;
+ if (re_errstr)
+ free(re_errstr);
+ re_errstr = strdup(s);
+}
+
diff --git a/lib/libcompat/regexp/COPYRIGHT b/lib/libcompat/regexp/COPYRIGHT
new file mode 100644
index 000000000000..48b3f4339171
--- /dev/null
+++ b/lib/libcompat/regexp/COPYRIGHT
@@ -0,0 +1,22 @@
+This entire subtree is copyright the University of Toronto.
+The following copyright notice applies to all files found here. None of
+these files contain AT&T proprietary source code.
+_____________________________________________________________________________
+
+ Copyright (c) 1986 by University of Toronto.
+ Written by Henry Spencer. Not derived from licensed software.
+
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The author is not responsible for the consequences of use of
+ this software, no matter how awful, even if they arise
+ from defects in it.
+
+ 2. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission.
+
+ 3. Altered versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
diff --git a/lib/libcompat/regexp/Makefile.inc b/lib/libcompat/regexp/Makefile.inc
new file mode 100644
index 000000000000..ba2d95367129
--- /dev/null
+++ b/lib/libcompat/regexp/Makefile.inc
@@ -0,0 +1,20 @@
+.PATH: ${.CURDIR}/regexp
+
+SRCS += regexp.c regsub.c regerror.c
+CFLAGS += -I ${.CURDIR}/regexp
+
+MAN3 += regexp/regexp.3
+
+# We need a different suffix for the man page links, so
+# we could have `man 3 regcomp' telling about both
+# libraries.
+# <bsd.man.mk> is not clever enough to handle this...
+
+M3COMPATLINKS = regcomp.3c regexec.3c regsub.3c regerror.3c
+
+afterinstall:
+ for link in ${M3COMPATLINKS} ; do \
+ rm -f ${DESTDIR}${MANDIR}3${MANSUBDIR}/$$link; \
+ ln ${DESTDIR}${MANDIR}3${MANSUBDIR}/regexp.3 \
+ ${DESTDIR}${MANDIR}3${MANSUBDIR}/$$link; \
+ done
diff --git a/lib/libcompat/regexp/README b/lib/libcompat/regexp/README
new file mode 100644
index 000000000000..37d6f51c7119
--- /dev/null
+++ b/lib/libcompat/regexp/README
@@ -0,0 +1,84 @@
+This is a nearly-public-domain reimplementation of the V8 regexp(3) package.
+It gives C programs the ability to use egrep-style regular expressions, and
+does it in a much cleaner fashion than the analogous routines in SysV.
+
+ Copyright (c) 1986 by University of Toronto.
+ Written by Henry Spencer. Not derived from licensed software.
+
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ subject to the following restrictions:
+
+ 1. The author is not responsible for the consequences of use of
+ this software, no matter how awful, even if they arise
+ from defects in it.
+
+ 2. The origin of this software must not be misrepresented, either
+ by explicit claim or by omission.
+
+ 3. Altered versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+Barring a couple of small items in the BUGS list, this implementation is
+believed 100% compatible with V8. It should even be binary-compatible,
+sort of, since the only fields in a "struct regexp" that other people have
+any business touching are declared in exactly the same way at the same
+location in the struct (the beginning).
+
+This implementation is *NOT* AT&T/Bell code, and is not derived from licensed
+software. Even though U of T is a V8 licensee. This software is based on
+a V8 manual page sent to me by Dennis Ritchie (the manual page enclosed
+here is a complete rewrite and hence is not covered by AT&T copyright).
+The software was nearly complete at the time of arrival of our V8 tape.
+I haven't even looked at V8 yet, although a friend elsewhere at U of T has
+been kind enough to run a few test programs using the V8 regexp(3) to resolve
+a few fine points. I admit to some familiarity with regular-expression
+implementations of the past, but the only one that this code traces any
+ancestry to is the one published in Kernighan & Plauger (from which this
+one draws ideas but not code).
+
+Simplistically: put this stuff into a source directory, copy regexp.h into
+/usr/include, inspect Makefile for compilation options that need changing
+to suit your local environment, and then do "make r". This compiles the
+regexp(3) functions, compiles a test program, and runs a large set of
+regression tests. If there are no complaints, then put regexp.o, regsub.o,
+and regerror.o into your C library, and regexp.3 into your manual-pages
+directory.
+
+Note that if you don't put regexp.h into /usr/include *before* compiling,
+you'll have to add "-I." to CFLAGS before compiling.
+
+The files are:
+
+Makefile instructions to make everything
+regexp.3 manual page
+regexp.h header file, for /usr/include
+regexp.c source for regcomp() and regexec()
+regsub.c source for regsub()
+regerror.c source for default regerror()
+regmagic.h internal header file
+try.c source for test program
+timer.c source for timing program
+tests test list for try and timer
+
+This implementation uses nondeterministic automata rather than the
+deterministic ones found in some other implementations, which makes it
+simpler, smaller, and faster at compiling regular expressions, but slower
+at executing them. In theory, anyway. This implementation does employ
+some special-case optimizations to make the simpler cases (which do make
+up the bulk of regular expressions actually used) run quickly. In general,
+if you want blazing speed you're in the wrong place. Replacing the insides
+of egrep with this stuff is probably a mistake; if you want your own egrep
+you're going to have to do a lot more work. But if you want to use regular
+expressions a little bit in something else, you're in luck. Note that many
+existing text editors use nondeterministic regular-expression implementations,
+so you're in good company.
+
+This stuff should be pretty portable, given appropriate option settings.
+If your chars have less than 8 bits, you're going to have to change the
+internal representation of the automaton, although knowledge of the details
+of this is fairly localized. There are no "reserved" char values except for
+NUL, and no special significance is attached to the top bit of chars.
+The string(3) functions are used a fair bit, on the grounds that they are
+probably faster than coding the operations in line. Some attempts at code
+tuning have been made, but this is invariably a bit machine-specific.
diff --git a/lib/libcompat/regexp/regerror.c b/lib/libcompat/regexp/regerror.c
new file mode 100644
index 000000000000..6d0077d63429
--- /dev/null
+++ b/lib/libcompat/regexp/regerror.c
@@ -0,0 +1,18 @@
+#include <regexp.h>
+#include <stdio.h>
+
+void
+regerror(s)
+const char *s;
+{
+#ifdef ERRAVAIL
+ error("regexp: %s", s);
+#else
+/*
+ fprintf(stderr, "regexp(3): %s\n", s);
+ exit(1);
+*/
+ return; /* let std. egrep handle errors */
+#endif
+ /* NOTREACHED */
+}
diff --git a/lib/libcompat/regexp/regexp.3 b/lib/libcompat/regexp/regexp.3
new file mode 100644
index 000000000000..b8ca3047cd91
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.3
@@ -0,0 +1,321 @@
+.\" Copyright 1991 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.
+.\"
+.\" @(#)regexp.3 5.2 (Berkeley) 4/20/91
+.\"
+.Dd April 20, 1991
+.Dt REGEXP 3
+.Os
+.Sh NAME
+.Nm regcomp ,
+.Nm regexec ,
+.Nm regsub ,
+.Nm regerror
+.Nd regular expression handlers
+.Sh SYNOPSIS
+.Fd #include <regexp.h>
+.Ft regexp *
+.Fn regcomp "const char *exp"
+.Ft int
+.Fn regexec "const regexp *prog" "const char *string"
+.Ft void
+.Fn regsub "const regexp *prog" "const char *source" "char *dest"
+.Sh DESCRIPTION
+.Em The functions described here are obsoleted, see
+.Xr regex 3
+.Em for the new interface .
+.Em To use these functions, the program must be linked
+.Em against -lcompat .
+
+The
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+functions
+implement
+.Xr egrep 1 Ns -style
+regular expressions and supporting facilities.
+.Pp
+The
+.Fn regcomp
+function
+compiles a regular expression into a structure of type
+.Xr regexp ,
+and returns a pointer to it.
+The space has been allocated using
+.Xr malloc 3
+and may be released by
+.Xr free .
+.Pp
+The
+.Fn regexec
+function
+matches a
+.Dv NUL Ns -terminated
+.Fa string
+against the compiled regular expression
+in
+.Fa prog .
+It returns 1 for success and 0 for failure, and adjusts the contents of
+.Fa prog Ns 's
+.Em startp
+and
+.Em endp
+(see below) accordingly.
+.Pp
+The members of a
+.Xr regexp
+structure include at least the following (not necessarily in order):
+.Bd -literal -offset indent
+char *startp[NSUBEXP];
+char *endp[NSUBEXP];
+.Ed
+.Pp
+where
+.Dv NSUBEXP
+is defined (as 10) in the header file.
+Once a successful
+.Fn regexec
+has been done using the
+.Fn regexp ,
+each
+.Em startp Ns - Em endp
+pair describes one substring
+within the
+.Fa string ,
+with the
+.Em startp
+pointing to the first character of the substring and
+the
+.Em endp
+pointing to the first character following the substring.
+The 0th substring is the substring of
+.Fa string
+that matched the whole
+regular expression.
+The others are those substrings that matched parenthesized expressions
+within the regular expression, with parenthesized expressions numbered
+in left-to-right order of their opening parentheses.
+.Pp
+The
+.Fn regsub
+function
+copies
+.Fa source
+to
+.Fa dest ,
+making substitutions according to the
+most recent
+.Fn regexec
+performed using
+.Fa prog .
+Each instance of `&' in
+.Fa source
+is replaced by the substring
+indicated by
+.Em startp Ns Bq
+and
+.Em endp Ns Bq .
+Each instance of
+.Sq \e Ns Em n ,
+where
+.Em n
+is a digit, is replaced by
+the substring indicated by
+.Em startp Ns Bq Em n
+and
+.Em endp Ns Bq Em n .
+To get a literal `&' or
+.Sq \e Ns Em n
+into
+.Fa dest ,
+prefix it with `\e';
+to get a literal `\e' preceding `&' or
+.Sq \e Ns Em n ,
+prefix it with
+another `\e'.
+.Pp
+The
+.Fn regerror
+function
+is called whenever an error is detected in
+.Fn regcomp ,
+.Fn regexec ,
+or
+.Fn regsub .
+The default
+.Fn regerror
+writes the string
+.Fa msg ,
+with a suitable indicator of origin,
+on the standard
+error output
+and invokes
+.Xr exit 2 .
+The
+.Fn regerror
+function
+can be replaced by the user if other actions are desirable.
+.Sh REGULAR EXPRESSION SYNTAX
+A regular expression is zero or more
+.Em branches ,
+separated by `|'.
+It matches anything that matches one of the branches.
+.Pp
+A branch is zero or more
+.Em pieces ,
+concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.Pp
+A piece is an
+.Em atom
+possibly followed by `*', `+', or `?'.
+An atom followed by `*' matches a sequence of 0 or more matches of the atom.
+An atom followed by `+' matches a sequence of 1 or more matches of the atom.
+An atom followed by `?' matches a match of the atom, or the null string.
+.Pp
+An atom is a regular expression in parentheses (matching a match for the
+regular expression), a
+.Em range
+(see below), `.'
+(matching any single character), `^' (matching the null string at the
+beginning of the input string), `$' (matching the null string at the
+end of the input string), a `\e' followed by a single character (matching
+that character), or a single character with no other significance
+(matching that character).
+.Pp
+A
+.Em range
+is a sequence of characters enclosed in `[]'.
+It normally matches any single character from the sequence.
+If the sequence begins with `^',
+it matches any single character
+.Em not
+from the rest of the sequence.
+If two characters in the sequence are separated by `\-', this is shorthand
+for the full list of
+.Tn ASCII
+characters between them
+(e.g. `[0-9]' matches any decimal digit).
+To include a literal `]' in the sequence, make it the first character
+(following a possible `^').
+To include a literal `\-', make it the first or last character.
+.Sh AMBIGUITY
+If a regular expression could match two different parts of the input string,
+it will match the one which begins earliest.
+If both begin in the same place but match different lengths, or match
+the same length in different ways, life gets messier, as follows.
+.Pp
+In general, the possibilities in a list of branches are considered in
+left-to-right order, the possibilities for `*', `+', and `?' are
+considered longest-first, nested constructs are considered from the
+outermost in, and concatenated constructs are considered leftmost-first.
+The match that will be chosen is the one that uses the earliest
+possibility in the first choice that has to be made.
+If there is more than one choice, the next will be made in the same manner
+(earliest possibility) subject to the decision on the first choice.
+And so forth.
+.Pp
+For example,
+.Sq Li (ab|a)b*c
+could match
+`abc' in one of two ways.
+The first choice is between `ab' and `a'; since `ab' is earlier, and does
+lead to a successful overall match, it is chosen.
+Since the `b' is already spoken for,
+the `b*' must match its last possibility\(emthe empty string\(emsince
+it must respect the earlier choice.
+.Pp
+In the particular case where no `|'s are present and there is only one
+`*', `+', or `?', the net effect is that the longest possible
+match will be chosen.
+So
+.Sq Li ab* ,
+presented with `xabbbby', will match `abbbb'.
+Note that if
+.Sq Li ab* ,
+is tried against `xabyabbbz', it
+will match `ab' just after `x', due to the begins-earliest rule.
+(In effect, the decision on where to start the match is the first choice
+to be made, hence subsequent choices must respect it even if this leads them
+to less-preferred alternatives.)
+.Sh RETURN VALUES
+The
+.Fn regcomp
+function
+returns
+.Dv NULL
+for a failure
+.Pf ( Fn regerror
+permitting),
+where failures are syntax errors, exceeding implementation limits,
+or applying `+' or `*' to a possibly-null operand.
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr ex 1 ,
+.Xr expr 1 ,
+.Xr egrep 1 ,
+.Xr fgrep 1 ,
+.Xr grep 1 ,
+.Xr regex 3
+.Sh HISTORY
+Both code and manual page for
+.Fn regcomp ,
+.Fn regexec ,
+.Fn regsub ,
+and
+.Fn regerror
+were written at the University of Toronto
+and appeared in
+.Bx 4.3 tahoe .
+They are intended to be compatible with the Bell V8
+.Xr regexp 3 ,
+but are not derived from Bell code.
+.Sh BUGS
+Empty branches and empty regular expressions are not portable to V8.
+.Pp
+The restriction against
+applying `*' or `+' to a possibly-null operand is an artifact of the
+simplistic implementation.
+.Pp
+Does not support
+.Xr egrep Ns 's
+newline-separated branches;
+neither does the V8
+.Xr regexp 3 ,
+though.
+.Pp
+Due to emphasis on
+compactness and simplicity,
+it's not strikingly fast.
+It does give special attention to handling simple cases quickly.
diff --git a/lib/libcompat/regexp/regexp.c b/lib/libcompat/regexp/regexp.c
new file mode 100644
index 000000000000..0084295bfb37
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.c
@@ -0,0 +1,1320 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
+ *** to assist in implementing egrep.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
+ *** as in BSD grep and ex.
+ *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
+ *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
+ *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
+ *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions. Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+#include <regexp.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "regmagic.h"
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases. They are:
+ *
+ * regstart char that must begin a match; '\0' if none obvious
+ * reganch is the match anchored (at beginning-of-line only)?
+ * regmust string (pointer into program) that match must include, or NULL
+ * regmlen length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot. Regmust permits fast rejection
+ * of lines that cannot possibly match. The regmust tests are costly enough
+ * that regcomp() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup). Regmlen is
+ * supplied because the test in regexec() needs it and regcomp() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program". This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology). Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand. "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives. (Here we
+ * have one of the subtle syntax dependencies: an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.) The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM. In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure: the tail of the branch connects
+ * to the thing following the set of BRANCHes.) The opcodes are:
+ */
+
+/* definition number opnd? meaning */
+#define END 0 /* no End of program. */
+#define BOL 1 /* no Match "" at beginning of line. */
+#define EOL 2 /* no Match "" at end of line. */
+#define ANY 3 /* no Match any one character. */
+#define ANYOF 4 /* str Match any character in this string. */
+#define ANYBUT 5 /* str Match any character not in this string. */
+#define BRANCH 6 /* node Match this alternative, or the next... */
+#define BACK 7 /* no Match "", "next" ptr points backward. */
+#define EXACTLY 8 /* str Match this string. */
+#define NOTHING 9 /* no Match empty string. */
+#define STAR 10 /* node Match this (simple) thing 0 or more times. */
+#define PLUS 11 /* node Match this (simple) thing 1 or more times. */
+#define WORDA 12 /* no Match "" at wordchar, where prev is nonword */
+#define WORDZ 13 /* no Match "" at nonwordchar, where prev is word */
+#define OPEN 20 /* no Mark this point in input as start of #n. */
+ /* OPEN+1 is number 1, etc. */
+#define CLOSE 30 /* no Analogous to OPEN. */
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH The set of branches constituting a single choice are hooked
+ * together with their "next" pointers, since precedence prevents
+ * anything being concatenated to any individual branch. The
+ * "next" pointer of the last BRANCH in a choice points to the
+ * thing following the whole choice. This is also where the
+ * final "next" pointer of each individual branch points; each
+ * branch starts with the operand node of a BRANCH node.
+ *
+ * BACK Normal "next" pointers all implicitly point forward; BACK
+ * exists to make loop structures possible.
+ *
+ * STAR,PLUS '?', and complex '*' and '+', are implemented as circular
+ * BRANCH structures using BACK. Simple cases (one character
+ * per match) are implemented with STAR and PLUS for speed
+ * and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first. The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node. (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+#define OP(p) (*(p))
+#define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p) ((p) + 3)
+
+/*
+ * See regmagic.h for one further detail of program structure.
+ */
+
+
+/*
+ * Utility definitions.
+ */
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+#define FAIL(m) { regerror(m); return(NULL); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?')
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH 01 /* Known never to match null string. */
+#define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */
+#define SPSTART 04 /* Starts with * or +. */
+#define WORST 0 /* Worst case. */
+
+/*
+ * Global work variables for regcomp().
+ */
+static char *regparse; /* Input-scan pointer. */
+static int regnpar; /* () count. */
+static char regdummy;
+static char *regcode; /* Code-emit pointer; &regdummy = don't. */
+static long regsize; /* Code size. */
+
+/*
+ * Forward declarations for regcomp()'s friends.
+ */
+#ifndef STATIC
+#define STATIC static
+#endif
+STATIC char *reg();
+STATIC char *regbranch();
+STATIC char *regpiece();
+STATIC char *regatom();
+STATIC char *regnode();
+STATIC char *regnext();
+STATIC void regc();
+STATIC void reginsert();
+STATIC void regtail();
+STATIC void regoptail();
+#ifdef STRCSPN
+STATIC int strcspn();
+#endif
+
+/*
+ - regcomp - compile a regular expression into internal code
+ *
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code. So we cheat: we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it. (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+regexp *
+regcomp(exp)
+const char *exp;
+{
+ register regexp *r;
+ register char *scan;
+ register char *longest;
+ register int len;
+ int flags;
+
+ if (exp == NULL)
+ FAIL("NULL argument");
+
+ /* First pass: determine size, legality. */
+#ifdef notdef
+ if (exp[0] == '.' && exp[1] == '*') exp += 2; /* aid grep */
+#endif
+ regparse = (char *)exp;
+ regnpar = 1;
+ regsize = 0L;
+ regcode = &regdummy;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Small enough for pointer-storage convention? */
+ if (regsize >= 32767L) /* Probably could be 65535L. */
+ FAIL("regexp too big");
+
+ /* Allocate space. */
+ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
+ if (r == NULL)
+ FAIL("out of space");
+
+ /* Second pass: emit code. */
+ regparse = (char *)exp;
+ regnpar = 1;
+ regcode = r->program;
+ regc(MAGIC);
+ if (reg(0, &flags) == NULL)
+ return(NULL);
+
+ /* Dig out information for optimizations. */
+ r->regstart = '\0'; /* Worst-case defaults. */
+ r->reganch = 0;
+ r->regmust = NULL;
+ r->regmlen = 0;
+ scan = r->program+1; /* First BRANCH. */
+ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */
+ scan = OPERAND(scan);
+
+ /* Starting-point info. */
+ if (OP(scan) == EXACTLY)
+ r->regstart = *OPERAND(scan);
+ else if (OP(scan) == BOL)
+ r->reganch++;
+
+ /*
+ * If there's something expensive in the r.e., find the
+ * longest literal string that must appear and make it the
+ * regmust. Resolve ties in favor of later strings, since
+ * the regstart check works with the beginning of the r.e.
+ * and avoiding duplication strengthens checking. Not a
+ * strong reason, but sufficient in the absence of others.
+ */
+ if (flags&SPSTART) {
+ longest = NULL;
+ len = 0;
+ for (; scan != NULL; scan = regnext(scan))
+ if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+ longest = OPERAND(scan);
+ len = strlen(OPERAND(scan));
+ }
+ r->regmust = longest;
+ r->regmlen = len;
+ }
+ }
+
+ return(r);
+}
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char *
+reg(paren, flagp)
+int paren; /* Parenthesized? */
+int *flagp;
+{
+ register char *ret;
+ register char *br;
+ register char *ender;
+ register int parno;
+ int flags;
+
+ *flagp = HASWIDTH; /* Tentatively. */
+
+ /* Make an OPEN node, if parenthesized. */
+ if (paren) {
+ if (regnpar >= NSUBEXP)
+ FAIL("too many ()");
+ parno = regnpar;
+ regnpar++;
+ ret = regnode(OPEN+parno);
+ } else
+ ret = NULL;
+
+ /* Pick up the branches, linking them together. */
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ if (ret != NULL)
+ regtail(ret, br); /* OPEN -> first. */
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*regparse == '|' || *regparse == '\n') {
+ regparse++;
+ br = regbranch(&flags);
+ if (br == NULL)
+ return(NULL);
+ regtail(ret, br); /* BRANCH -> BRANCH. */
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+ /* Make a closing node, and hook it on the end. */
+ ender = regnode((paren) ? CLOSE+parno : END);
+ regtail(ret, ender);
+
+ /* Hook the tails of the branches to the closing node. */
+ for (br = ret; br != NULL; br = regnext(br))
+ regoptail(br, ender);
+
+ /* Check for proper termination. */
+ if (paren && *regparse++ != ')') {
+ FAIL("unmatched ()");
+ } else if (!paren && *regparse != '\0') {
+ if (*regparse == ')') {
+ FAIL("unmatched ()");
+ } else
+ FAIL("junk on end"); /* "Can't happen". */
+ /* NOTREACHED */
+ }
+
+ return(ret);
+}
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char *
+regbranch(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char *chain;
+ register char *latest;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ ret = regnode(BRANCH);
+ chain = NULL;
+ while (*regparse != '\0' && *regparse != ')' &&
+ *regparse != '\n' && *regparse != '|') {
+ latest = regpiece(&flags);
+ if (latest == NULL)
+ return(NULL);
+ *flagp |= flags&HASWIDTH;
+ if (chain == NULL) /* First piece. */
+ *flagp |= flags&SPSTART;
+ else
+ regtail(chain, latest);
+ chain = latest;
+ }
+ if (chain == NULL) /* Loop ran zero times. */
+ (void) regnode(NOTHING);
+
+ return(ret);
+}
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized: they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char *
+regpiece(flagp)
+int *flagp;
+{
+ register char *ret;
+ register char op;
+ register char *next;
+ int flags;
+
+ ret = regatom(&flags);
+ if (ret == NULL)
+ return(NULL);
+
+ op = *regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?')
+ FAIL("*+ operand could be empty");
+ *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
+
+ if (op == '*' && (flags&SIMPLE))
+ reginsert(STAR, ret);
+ else if (op == '*') {
+ /* Emit x* as (x&|), where & means "self". */
+ reginsert(BRANCH, ret); /* Either x */
+ regoptail(ret, regnode(BACK)); /* and loop */
+ regoptail(ret, ret); /* back */
+ regtail(ret, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '+' && (flags&SIMPLE))
+ reginsert(PLUS, ret);
+ else if (op == '+') {
+ /* Emit x+ as x(&|), where & means "self". */
+ next = regnode(BRANCH); /* Either */
+ regtail(ret, next);
+ regtail(regnode(BACK), ret); /* loop back */
+ regtail(next, regnode(BRANCH)); /* or */
+ regtail(ret, regnode(NOTHING)); /* null. */
+ } else if (op == '?') {
+ /* Emit x? as (x|) */
+ reginsert(BRANCH, ret); /* Either x */
+ regtail(ret, regnode(BRANCH)); /* or */
+ next = regnode(NOTHING); /* null. */
+ regtail(ret, next);
+ regoptail(ret, next);
+ }
+ regparse++;
+ if (ISMULT(*regparse))
+ FAIL("nested *?+");
+
+ return(ret);
+}
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization: gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run. Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char *
+regatom(flagp)
+int *flagp;
+{
+ register char *ret;
+ int flags;
+
+ *flagp = WORST; /* Tentatively. */
+
+ switch (*regparse++) {
+ /* FIXME: these chars only have meaning at beg/end of pat? */
+ case '^':
+ ret = regnode(BOL);
+ break;
+ case '$':
+ ret = regnode(EOL);
+ break;
+ case '.':
+ ret = regnode(ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ register int class;
+ register int classend;
+
+ if (*regparse == '^') { /* Complement of range. */
+ ret = regnode(ANYBUT);
+ regparse++;
+ } else
+ ret = regnode(ANYOF);
+ if (*regparse == ']' || *regparse == '-')
+ regc(*regparse++);
+ while (*regparse != '\0' && *regparse != ']') {
+ if (*regparse == '-') {
+ regparse++;
+ if (*regparse == ']' || *regparse == '\0')
+ regc('-');
+ else {
+ class = UCHARAT(regparse-2)+1;
+ classend = UCHARAT(regparse);
+ if (class > classend+1)
+ FAIL("invalid [] range");
+ for (; class <= classend; class++)
+ regc(class);
+ regparse++;
+ }
+ } else
+ regc(*regparse++);
+ }
+ regc('\0');
+ if (*regparse != ']')
+ FAIL("unmatched []");
+ regparse++;
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(1, &flags);
+ if (ret == NULL)
+ return(NULL);
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case '\n':
+ case ')':
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing");
+ break;
+ case '\\':
+ switch (*regparse++) {
+ case '\0':
+ FAIL("trailing \\");
+ break;
+ case '<':
+ ret = regnode(WORDA);
+ break;
+ case '>':
+ ret = regnode(WORDZ);
+ break;
+ /* FIXME: Someday handle \1, \2, ... */
+ default:
+ /* Handle general quoted chars in exact-match routine */
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default:
+ /*
+ * Encode a string of characters to be matched exactly.
+ *
+ * This is a bit tricky due to quoted chars and due to
+ * '*', '+', and '?' taking the SINGLE char previous
+ * as their operand.
+ *
+ * On entry, the char at regparse[-1] is going to go
+ * into the string, no matter what it is. (It could be
+ * following a \ if we are entered from the '\' case.)
+ *
+ * Basic idea is to pick up a good char in ch and
+ * examine the next char. If it's *+? then we twiddle.
+ * If it's \ then we frozzle. If it's other magic char
+ * we push ch and terminate the string. If none of the
+ * above, we push ch on the string and go around again.
+ *
+ * regprev is used to remember where "the current char"
+ * starts in the string, if due to a *+? we need to back
+ * up and put the current char in a separate, 1-char, string.
+ * When regprev is NULL, ch is the only char in the
+ * string; this is used in *+? handling, and in setting
+ * flags |= SIMPLE at the end.
+ */
+ {
+ char *regprev;
+ register char ch;
+
+ regparse--; /* Look at cur char */
+ ret = regnode(EXACTLY);
+ for ( regprev = 0 ; ; ) {
+ ch = *regparse++; /* Get current char */
+ switch (*regparse) { /* look at next one */
+
+ default:
+ regc(ch); /* Add cur to string */
+ break;
+
+ case '.': case '[': case '(':
+ case ')': case '|': case '\n':
+ case '$': case '^':
+ case '\0':
+ /* FIXME, $ and ^ should not always be magic */
+ magic:
+ regc(ch); /* dump cur char */
+ goto done; /* and we are done */
+
+ case '?': case '+': case '*':
+ if (!regprev) /* If just ch in str, */
+ goto magic; /* use it */
+ /* End mult-char string one early */
+ regparse = regprev; /* Back up parse */
+ goto done;
+
+ case '\\':
+ regc(ch); /* Cur char OK */
+ switch (regparse[1]){ /* Look after \ */
+ case '\0':
+ case '<':
+ case '>':
+ /* FIXME: Someday handle \1, \2, ... */
+ goto done; /* Not quoted */
+ default:
+ /* Backup point is \, scan * point is after it. */
+ regprev = regparse;
+ regparse++;
+ continue; /* NOT break; */
+ }
+ }
+ regprev = regparse; /* Set backup point */
+ }
+ done:
+ regc('\0');
+ *flagp |= HASWIDTH;
+ if (!regprev) /* One char? */
+ *flagp |= SIMPLE;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+/*
+ - regnode - emit a node
+ */
+static char * /* Location. */
+regnode(op)
+char op;
+{
+ register char *ret;
+ register char *ptr;
+
+ ret = regcode;
+ if (ret == &regdummy) {
+ regsize += 3;
+ return(ret);
+ }
+
+ ptr = ret;
+ *ptr++ = op;
+ *ptr++ = '\0'; /* Null "next" pointer. */
+ *ptr++ = '\0';
+ regcode = ptr;
+
+ return(ret);
+}
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void
+regc(b)
+char b;
+{
+ if (regcode != &regdummy)
+ *regcode++ = b;
+ else
+ regsize++;
+}
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void
+reginsert(op, opnd)
+char op;
+char *opnd;
+{
+ register char *src;
+ register char *dst;
+ register char *place;
+
+ if (regcode == &regdummy) {
+ regsize += 3;
+ return;
+ }
+
+ src = regcode;
+ regcode += 3;
+ dst = regcode;
+ while (src > opnd)
+ *--dst = *--src;
+
+ place = opnd; /* Op node, where operand used to be. */
+ *place++ = op;
+ *place++ = '\0';
+ *place++ = '\0';
+}
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void
+regtail(p, val)
+char *p;
+char *val;
+{
+ register char *scan;
+ register char *temp;
+ register int offset;
+
+ if (p == &regdummy)
+ return;
+
+ /* Find last node. */
+ scan = p;
+ for (;;) {
+ temp = regnext(scan);
+ if (temp == NULL)
+ break;
+ scan = temp;
+ }
+
+ if (OP(scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+ *(scan+1) = (offset>>8)&0377;
+ *(scan+2) = offset&0377;
+}
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void
+regoptail(p, val)
+char *p;
+char *val;
+{
+ /* "Operandless" and "op != BRANCH" are synonymous in practice. */
+ if (p == NULL || p == &regdummy || OP(p) != BRANCH)
+ return;
+ regtail(OPERAND(p), val);
+}
+
+/*
+ * regexec and friends
+ */
+
+/*
+ * Global work variables for regexec().
+ */
+static char *reginput; /* String-input pointer. */
+static char *regbol; /* Beginning of input, for ^ check. */
+static char **regstartp; /* Pointer to startp array. */
+static char **regendp; /* Ditto for endp. */
+
+/*
+ * Forwards.
+ */
+STATIC int regtry();
+STATIC int regmatch();
+STATIC int regrepeat();
+
+#ifdef DEBUG
+int regnarrate = 0;
+void regdump();
+STATIC char *regprop();
+#endif
+
+/*
+ - regexec - match a regexp against a string
+ */
+int
+regexec(prog, string)
+register const regexp *prog;
+register const char *string;
+{
+ register char *s;
+ extern char *strchr();
+
+ /* Be paranoid... */
+ if (prog == NULL || string == NULL) {
+ regerror("NULL parameter");
+ return(0);
+ }
+
+ /* Check validity of program. */
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("corrupted program");
+ return(0);
+ }
+
+ /* If there is a "must appear" string, look for it. */
+ if (prog->regmust != NULL) {
+ s = (char *)string;
+ while ((s = strchr(s, prog->regmust[0])) != NULL) {
+ if (strncmp(s, prog->regmust, prog->regmlen) == 0)
+ break; /* Found it. */
+ s++;
+ }
+ if (s == NULL) /* Not present. */
+ return(0);
+ }
+
+ /* Mark beginning of line for ^ . */
+ regbol = (char *)string;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = (char *)string;
+ if (prog->regstart != '\0')
+ /* We know what char it must start with. */
+ while ((s = strchr(s, prog->regstart)) != NULL) {
+ if (regtry(prog, s))
+ return(1);
+ s++;
+ }
+ else
+ /* We don't -- general case. */
+ do {
+ if (regtry(prog, s))
+ return(1);
+ } while (*s++ != '\0');
+
+ /* Failure. */
+ return(0);
+}
+
+/*
+ - regtry - try match at specific point
+ */
+static int /* 0 failure, 1 success */
+regtry(prog, string)
+regexp *prog;
+char *string;
+{
+ register int i;
+ register char **sp;
+ register char **ep;
+
+ reginput = string;
+ regstartp = prog->startp;
+ regendp = prog->endp;
+
+ sp = prog->startp;
+ ep = prog->endp;
+ for (i = NSUBEXP; i > 0; i--) {
+ *sp++ = NULL;
+ *ep++ = NULL;
+ }
+ if (regmatch(prog->program + 1)) {
+ prog->startp[0] = string;
+ prog->endp[0] = reginput;
+ return(1);
+ } else
+ return(0);
+}
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple: check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly. In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ */
+static int /* 0 failure, 1 success */
+regmatch(prog)
+char *prog;
+{
+ register char *scan; /* Current node. */
+ char *next; /* Next node. */
+ extern char *strchr();
+
+ scan = prog;
+#ifdef DEBUG
+ if (scan != NULL && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != NULL) {
+#ifdef DEBUG
+ if (regnarrate)
+ fprintf(stderr, "%s...\n", regprop(scan));
+#endif
+ next = regnext(scan);
+
+ switch (OP(scan)) {
+ case BOL:
+ if (reginput != regbol)
+ return(0);
+ break;
+ case EOL:
+ if (*reginput != '\0')
+ return(0);
+ break;
+ case WORDA:
+ /* Must be looking at a letter, digit, or _ */
+ if ((!isalnum(*reginput)) && *reginput != '_')
+ return(0);
+ /* Prev must be BOL or nonword */
+ if (reginput > regbol &&
+ (isalnum(reginput[-1]) || reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+ /* Must be looking at non letter, digit, or _ */
+ if (isalnum(*reginput) || *reginput == '_')
+ return(0);
+ /* We don't care what the previous char was */
+ break;
+ case ANY:
+ if (*reginput == '\0')
+ return(0);
+ reginput++;
+ break;
+ case EXACTLY: {
+ register int len;
+ register char *opnd;
+
+ opnd = OPERAND(scan);
+ /* Inline the first character, for speed. */
+ if (*opnd != *reginput)
+ return(0);
+ len = strlen(opnd);
+ if (len > 1 && strncmp(opnd, reginput, len) != 0)
+ return(0);
+ reginput += len;
+ }
+ break;
+ case ANYOF:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+ return(0);
+ reginput++;
+ break;
+ case ANYBUT:
+ if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+ return(0);
+ reginput++;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - OPEN;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set startp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regstartp[no] == NULL)
+ regstartp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9: {
+ register int no;
+ register char *save;
+
+ no = OP(scan) - CLOSE;
+ save = reginput;
+
+ if (regmatch(next)) {
+ /*
+ * Don't set endp if some later
+ * invocation of the same parentheses
+ * already has.
+ */
+ if (regendp[no] == NULL)
+ regendp[no] = save;
+ return(1);
+ } else
+ return(0);
+ }
+ break;
+ case BRANCH: {
+ register char *save;
+
+ if (OP(next) != BRANCH) /* No choice. */
+ next = OPERAND(scan); /* Avoid recursion. */
+ else {
+ do {
+ save = reginput;
+ if (regmatch(OPERAND(scan)))
+ return(1);
+ reginput = save;
+ scan = regnext(scan);
+ } while (scan != NULL && OP(scan) == BRANCH);
+ return(0);
+ /* NOTREACHED */
+ }
+ }
+ break;
+ case STAR:
+ case PLUS: {
+ register char nextch;
+ register int no;
+ register char *save;
+ register int min;
+
+ /*
+ * Lookahead to avoid useless match attempts
+ * when we know what character comes next.
+ */
+ nextch = '\0';
+ if (OP(next) == EXACTLY)
+ nextch = *OPERAND(next);
+ min = (OP(scan) == STAR) ? 0 : 1;
+ save = reginput;
+ no = regrepeat(OPERAND(scan));
+ while (no >= min) {
+ /* If it could work, try it. */
+ if (nextch == '\0' || *reginput == nextch)
+ if (regmatch(next))
+ return(1);
+ /* Couldn't or didn't -- back up. */
+ no--;
+ reginput = save + no;
+ }
+ return(0);
+ }
+ break;
+ case END:
+ return(1); /* Success! */
+ break;
+ default:
+ regerror("memory corruption");
+ return(0);
+ break;
+ }
+
+ scan = next;
+ }
+
+ /*
+ * We get here only if there's trouble -- normally "case END" is
+ * the terminating point.
+ */
+ regerror("corrupted pointers");
+ return(0);
+}
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int
+regrepeat(p)
+char *p;
+{
+ register int count = 0;
+ register char *scan;
+ register char *opnd;
+
+ scan = reginput;
+ opnd = OPERAND(p);
+ switch (OP(p)) {
+ case ANY:
+ count = strlen(scan);
+ scan += count;
+ break;
+ case EXACTLY:
+ while (*opnd == *scan) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYOF:
+ while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ case ANYBUT:
+ while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
+ count++;
+ scan++;
+ }
+ break;
+ default: /* Oh dear. Called inappropriately. */
+ regerror("internal foulup");
+ count = 0; /* Best compromise. */
+ break;
+ }
+ reginput = scan;
+
+ return(count);
+}
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static char *
+regnext(p)
+register char *p;
+{
+ register int offset;
+
+ if (p == &regdummy)
+ return(NULL);
+
+ offset = NEXT(p);
+ if (offset == 0)
+ return(NULL);
+
+ if (OP(p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+#ifdef DEBUG
+
+STATIC char *regprop();
+
+/*
+ - regdump - dump a regexp onto stdout in vaguely comprehensible form
+ */
+void
+regdump(r)
+regexp *r;
+{
+ register char *s;
+ register char op = EXACTLY; /* Arbitrary non-END op. */
+ register char *next;
+ extern char *strchr();
+
+
+ s = r->program + 1;
+ while (op != END) { /* While that wasn't END last time... */
+ op = OP(s);
+ printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */
+ next = regnext(s);
+ if (next == NULL) /* Next ptr. */
+ printf("(0)");
+ else
+ printf("(%d)", (s-r->program)+(next-s));
+ s += 3;
+ if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
+ /* Literal string, where present. */
+ while (*s != '\0') {
+ putchar(*s);
+ s++;
+ }
+ s++;
+ }
+ putchar('\n');
+ }
+
+ /* Header fields of interest. */
+ if (r->regstart != '\0')
+ printf("start `%c' ", r->regstart);
+ if (r->reganch)
+ printf("anchored ");
+ if (r->regmust != NULL)
+ printf("must have \"%s\"", r->regmust);
+ printf("\n");
+}
+
+/*
+ - regprop - printable representation of opcode
+ */
+static char *
+regprop(op)
+char *op;
+{
+ register char *p;
+ static char buf[50];
+
+ (void) strcpy(buf, ":");
+
+ switch (OP(op)) {
+ case BOL:
+ p = "BOL";
+ break;
+ case EOL:
+ p = "EOL";
+ break;
+ case ANY:
+ p = "ANY";
+ break;
+ case ANYOF:
+ p = "ANYOF";
+ break;
+ case ANYBUT:
+ p = "ANYBUT";
+ break;
+ case BRANCH:
+ p = "BRANCH";
+ break;
+ case EXACTLY:
+ p = "EXACTLY";
+ break;
+ case NOTHING:
+ p = "NOTHING";
+ break;
+ case BACK:
+ p = "BACK";
+ break;
+ case END:
+ p = "END";
+ break;
+ case OPEN+1:
+ case OPEN+2:
+ case OPEN+3:
+ case OPEN+4:
+ case OPEN+5:
+ case OPEN+6:
+ case OPEN+7:
+ case OPEN+8:
+ case OPEN+9:
+ sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
+ p = NULL;
+ break;
+ case CLOSE+1:
+ case CLOSE+2:
+ case CLOSE+3:
+ case CLOSE+4:
+ case CLOSE+5:
+ case CLOSE+6:
+ case CLOSE+7:
+ case CLOSE+8:
+ case CLOSE+9:
+ sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
+ p = NULL;
+ break;
+ case STAR:
+ p = "STAR";
+ break;
+ case PLUS:
+ p = "PLUS";
+ break;
+ case WORDA:
+ p = "WORDA";
+ break;
+ case WORDZ:
+ p = "WORDZ";
+ break;
+ default:
+ regerror("corrupted opcode");
+ break;
+ }
+ if (p != NULL)
+ (void) strcat(buf, p);
+ return(buf);
+}
+#endif
+
+/*
+ * The following is provided for those people who do not have strcspn() in
+ * their C libraries. They should get off their butts and do something
+ * about it; at least one public-domain implementation of those (highly
+ * useful) string routines has been published on Usenet.
+ */
+#ifdef STRCSPN
+/*
+ * strcspn - find length of initial segment of s1 consisting entirely
+ * of characters not from s2
+ */
+
+static int
+strcspn(s1, s2)
+char *s1;
+char *s2;
+{
+ register char *scan1;
+ register char *scan2;
+ register int count;
+
+ count = 0;
+ for (scan1 = s1; *scan1 != '\0'; scan1++) {
+ for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */
+ if (*scan1 == *scan2++)
+ return(count);
+ count++;
+ }
+ return(count);
+}
+#endif
diff --git a/lib/libcompat/regexp/regexp.h b/lib/libcompat/regexp/regexp.h
new file mode 100644
index 000000000000..73d6bf412424
--- /dev/null
+++ b/lib/libcompat/regexp/regexp.h
@@ -0,0 +1,21 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+#define NSUBEXP 10
+typedef struct regexp {
+ char *startp[NSUBEXP];
+ char *endp[NSUBEXP];
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+extern regexp *regcomp();
+extern int regexec();
+extern void regsub();
+extern void regerror();
diff --git a/lib/libcompat/regexp/regmagic.h b/lib/libcompat/regexp/regmagic.h
new file mode 100644
index 000000000000..5acf4478ff71
--- /dev/null
+++ b/lib/libcompat/regexp/regmagic.h
@@ -0,0 +1,5 @@
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
diff --git a/lib/libcompat/regexp/regsub.c b/lib/libcompat/regexp/regsub.c
new file mode 100644
index 000000000000..e55b9b624d1d
--- /dev/null
+++ b/lib/libcompat/regexp/regsub.c
@@ -0,0 +1,81 @@
+/*
+ * regsub
+ *
+ * Copyright (c) 1986 by University of Toronto.
+ * Written by Henry Spencer. Not derived from licensed software.
+ *
+ * Permission is granted to anyone to use this software for any
+ * purpose on any computer system, and to redistribute it freely,
+ * subject to the following restrictions:
+ *
+ * 1. The author is not responsible for the consequences of use of
+ * this software, no matter how awful, even if they arise
+ * from defects in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either
+ * by explicit claim or by omission.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not
+ * be misrepresented as being the original software.
+ */
+#include <regexp.h>
+#include <stdio.h>
+#include <string.h>
+#include "regmagic.h"
+
+#ifndef CHARBITS
+#define UCHARAT(p) ((int)*(unsigned char *)(p))
+#else
+#define UCHARAT(p) ((int)*(p)&CHARBITS)
+#endif
+
+/*
+ - regsub - perform substitutions after a regexp match
+ */
+void
+regsub(prog, source, dest)
+const regexp *prog;
+const char *source;
+char *dest;
+{
+ register char *src;
+ register char *dst;
+ register char c;
+ register int no;
+ register int len;
+ extern char *strncpy();
+
+ if (prog == NULL || source == NULL || dest == NULL) {
+ regerror("NULL parm to regsub");
+ return;
+ }
+ if (UCHARAT(prog->program) != MAGIC) {
+ regerror("damaged regexp fed to regsub");
+ return;
+ }
+
+ src = (char *)source;
+ dst = dest;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && '0' <= *src && *src <= '9')
+ no = *src++ - '0';
+ else
+ no = -1;
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&'))
+ c = *src++;
+ *dst++ = c;
+ } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+ len = prog->endp[no] - prog->startp[no];
+ (void) strncpy(dst, prog->startp[no], len);
+ dst += len;
+ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
+ regerror("damaged match string");
+ return;
+ }
+ }
+ }
+ *dst++ = '\0';
+}
diff --git a/lib/libcompat/setrgid.c b/lib/libcompat/setrgid.c
new file mode 100644
index 000000000000..c0766d71fbf7
--- /dev/null
+++ b/lib/libcompat/setrgid.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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 <sys/types.h>
+#include <unistd.h>
+
+int
+#if __STDC__
+setrgid(gid_t gid)
+#else
+setrgid(gid)
+ gid_t gid;
+#endif
+{
+ return setgid(gid);
+}
+
diff --git a/lib/libcompat/setruid.c b/lib/libcompat/setruid.c
new file mode 100644
index 000000000000..9fd649e810a0
--- /dev/null
+++ b/lib/libcompat/setruid.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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 <sys/types.h>
+#include <unistd.h>
+
+int
+#if __STDC__
+setruid(uid_t uid)
+#else
+setruid(uid)
+ uid_t uid;
+#endif
+{
+ return setuid(uid);
+}
+
diff --git a/lib/libcompat/sgtty.c b/lib/libcompat/sgtty.c
new file mode 100644
index 000000000000..3c3730d30a8d
--- /dev/null
+++ b/lib/libcompat/sgtty.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1994 Joerg Wunsch
+ *
+ * All rights reserved.
+ *
+ * This program is free software.
+ *
+ * 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 Joerg Wunsch
+ * 4. The name of the developer may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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 DEVELOPERS 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.
+ */
+
+/* the V7-style interface to modify the terminals characteristics */
+
+#include <sgtty.h>
+
+/* these functions are just in case someone even did not get the macros... */
+#undef stty
+#undef gtty
+
+int
+#if __STDC__
+stty(int fd, struct sgttyb *s)
+#else
+stty(fd, s)
+ int fd;
+ struct sgttyb *s;
+#endif
+{
+ return ioctl(fd, TIOCSETP, s);
+}
+
+int
+#if __STDC__
+gtty(int fd, struct sgttyb *s)
+#else
+gtty(fd, s)
+ int fd;
+ struct sgttyb *s;
+#endif
+{
+ return ioctl(fd, TIOCGETP, s);
+}
+
+
diff --git a/lib/libcurses/Makefile b/lib/libcurses/Makefile
index 74baf7974571..b089a988b78a 100644
--- a/lib/libcurses/Makefile
+++ b/lib/libcurses/Makefile
@@ -9,7 +9,8 @@ SRCS= addbytes.c addch.c addnstr.c box.c clear.c clrtobot.c clrtoeol.c \
standout.c toucholap.c touchwin.c tscroll.c tstp.c tty.c unctrl.c
MAN3= curses.3
-CFLAGS+=-D_CURSES_PRIVATE -I${.CURDIR}
+CFLAGS+=-D_CURSES_PRIVATE
+SHARED_LDADD+= -ltermcap
beforeinstall:
-cd ${.CURDIR}; cmp -s curses.h ${DESTDIR}/usr/include/curses.h > \
diff --git a/lib/libcurses/cr_put.c b/lib/libcurses/cr_put.c
index b50875c91211..0afaf3a344d7 100644
--- a/lib/libcurses/cr_put.c
+++ b/lib/libcurses/cr_put.c
@@ -101,11 +101,11 @@ fgoto(in_refresh)
while (l > 0) {
if (__pfast)
if (CR)
- tputs(CR, 0, __cputchar);
+ tputs(CR, 1, __cputchar);
else
putchar('\r');
if (NL)
- tputs(NL, 0, __cputchar);
+ tputs(NL, 1, __cputchar);
else
putchar('\n');
l--;
@@ -146,7 +146,7 @@ fgoto(in_refresh)
* Eggert's Superbee description which wins better.
*/
if (NL /* && !XB */ && __pfast)
- tputs(NL, 0, __cputchar);
+ tputs(NL, 1, __cputchar);
else
putchar('\n');
l--;
@@ -166,7 +166,7 @@ fgoto(in_refresh)
if (outcol != COLS - 1 && plod(strlen(cgp), in_refresh) > 0)
plod(0, in_refresh);
else
- tputs(cgp, 0, __cputchar);
+ tputs(cgp, 1, __cputchar);
} else
plod(0, in_refresh);
outline = destline;
@@ -243,7 +243,7 @@ plod(cnt, in_refresh)
* Cheaper to home. Do it now and pretend it's a
* regular local motion.
*/
- tputs(HO, 0, plodput);
+ tputs(HO, 1, plodput);
outcol = outline = 0;
} else if (LL) {
/*
@@ -252,7 +252,7 @@ plod(cnt, in_refresh)
*/
k = (LINES - 1) - destline;
if (i + k + 2 < j && (k <= 0 || UP)) {
- tputs(LL, 0, plodput);
+ tputs(LL, 1, plodput);
outcol = 0;
outline = LINES - 1;
}
@@ -302,12 +302,12 @@ plod(cnt, in_refresh)
* into account.
*/
if (CR)
- tputs(CR, 0, plodput);
+ tputs(CR, 1, plodput);
else
plodput('\r');
if (NC) {
if (NL)
- tputs(NL, 0, plodput);
+ tputs(NL, 1, plodput);
else
plodput('\n');
outline++;
@@ -318,7 +318,7 @@ plod(cnt, in_refresh)
dontcr: while (outline < destline) {
outline++;
if (NL)
- tputs(NL, 0, plodput);
+ tputs(NL, 1, plodput);
else
plodput('\n');
if (plodcnt < 0)
@@ -333,7 +333,7 @@ dontcr: while (outline < destline) {
goto out;
#ifdef notdef
if (BT && outcol - destcol > k + 4) {
- tputs(BT, 0, plodput);
+ tputs(BT, 1, plodput);
outcol--;
outcol &= ~7;
continue;
@@ -357,14 +357,14 @@ dontcr: while (outline < destline) {
if (i > destcol)
break;
if (TA)
- tputs(TA, 0, plodput);
+ tputs(TA, 1, plodput);
else
plodput('\t');
outcol = i;
}
if (destcol - outcol > 4 && i < COLS && (BC || BS)) {
if (TA)
- tputs(TA, 0, plodput);
+ tputs(TA, 1, plodput);
else
plodput('\t');
outcol = i;
diff --git a/lib/libcurses/curses.h b/lib/libcurses/curses.h
index 14e82deac58a..fa68e08c79dc 100644
--- a/lib/libcurses/curses.h
+++ b/lib/libcurses/curses.h
@@ -199,6 +199,7 @@ typedef struct termios SGTTY;
extern SGTTY __orig_termios; /* Terminal state before curses */
extern SGTTY __baset; /* Our base terminal state */
extern int __tcaction; /* If terminal hardware set. */
+extern int __tty_fileno; /* Terminal file descriptor */
extern int COLS; /* Columns on the screen. */
extern int LINES; /* Lines on the screen. */
diff --git a/lib/libcurses/refresh.c b/lib/libcurses/refresh.c
index 1a371fe45b2a..b0a84b1dc4f2 100644
--- a/lib/libcurses/refresh.c
+++ b/lib/libcurses/refresh.c
@@ -76,7 +76,11 @@ wrefresh(win)
if (win->flags & __CLEAROK || curscr->flags & __CLEAROK || curwin) {
if ((win->flags & __FULLWIN) || curscr->flags & __CLEAROK) {
- tputs(CL, 0, __cputchar);
+ if (curscr->flags & __WSTANDOUT) {
+ tputs(SE, 0, __cputchar);
+ curscr->flags &= ~__WSTANDOUT;
+ }
+ tputs(CL, win->maxy, __cputchar);
ly = 0;
lx = 0;
if (!curwin) {
@@ -266,9 +270,9 @@ makech(win, wy)
if (force) {
if (CM)
- tputs(tgoto(CM, lx, ly), 0, __cputchar);
+ tputs(tgoto(CM, lx, ly), 1, __cputchar);
else {
- tputs(HO, 0, __cputchar);
+ tputs(HO, 1, __cputchar);
__mvcur(0, 0, ly, lx, 1);
}
}
@@ -298,7 +302,7 @@ makech(win, wy)
&& wx <= lch) {
if (ce != NULL && win->maxx + win->begx ==
- curscr->maxx && wx >= nlsp && nsp->ch == ' ') {
+ curscr->maxx && wx >= nlsp && nsp->ch == ' ' && nsp->attr == 0) {
/* Check for clear to end-of-line. */
cep = &curscr->lines[win->begy + wy]->line[win->begx + win->maxx - 1];
while (cep->ch == ' ' && cep->attr == 0)
@@ -315,7 +319,11 @@ makech(win, wy)
#ifdef DEBUG
__CTRACE("makech: using CE\n");
#endif
- tputs(CE, 0, __cputchar);
+ if (curscr->flags & __WSTANDOUT) {
+ tputs(SE, 0, __cputchar);
+ curscr->flags &= ~__WSTANDOUT;
+ }
+ tputs(CE, 1, __cputchar);
lx = wx + win->begx;
while (wx++ <= clsp) {
csp->ch = ' ';
@@ -695,37 +703,37 @@ scrolln(starts, startw, curs, bot, top)
__mvcur(oy, ox, top, 0, 1);
/* Scroll up the block */
if (DL && (!dl || n > 1))
- tputs(__tscroll(DL, n), 0, __cputchar);
+ tputs(__tscroll(DL, n), n, __cputchar);
else
for(i = 0; i < n; i++)
- tputs(dl, 0, __cputchar);
+ tputs(dl, 1, __cputchar);
/*
* Push down the bottom region.
*/
__mvcur(top, 0, bot - n + 1, 0, 1);
if (AL && (!al || n > 1))
- tputs(__tscroll(AL, n), 0, __cputchar);
+ tputs(__tscroll(AL, n), n, __cputchar);
else
for(i = 0; i < n; i++)
- tputs(al, 0, __cputchar);
+ tputs(al, 1, __cputchar);
__mvcur(bot - n + 1, 0, oy, ox, 1);
} else {
/* Preserve the bottom lines */
__mvcur(oy, ox, bot + n + 1, 0, 1); /* n < 0 */
if (DL && (!dl || -n > 1))
- tputs(__tscroll(DL, -n), 0, __cputchar);
+ tputs(__tscroll(DL, -n), -n, __cputchar);
else
for(i = n; i < 0; i++)
- tputs(dl, 0, __cputchar);
+ tputs(dl, 1, __cputchar);
__mvcur(bot + n + 1, 0, top, 0, 1);
/* Scroll the block down */
if (AL && (!al || -n > 1))
- tputs(__tscroll(AL, -n), 0, __cputchar);
+ tputs(__tscroll(AL, -n), -n, __cputchar);
else
for(i = n; i < 0; i++)
- tputs(al, 0, __cputchar);
+ tputs(al, 1, __cputchar);
__mvcur(top, 0, oy, ox, 1);
}
} else { /* Use change scroll region */
@@ -735,11 +743,11 @@ scrolln(starts, startw, curs, bot, top)
__mvcur(oy, ox, bot, 0, 1);
/* Scroll up the block */
if (SF && n > 1)
- tputs(__tscroll(SF, n), 0, __cputchar);
+ tputs(__tscroll(SF, n), n, __cputchar);
else
for(i = 0; i < n; i++)
if (NL && __pfast)
- tputs(NL, 0, __cputchar);
+ tputs(NL, 1, __cputchar);
else
putchar('\n');
__mvcur(bot, 0, oy, ox, 1);
@@ -747,10 +755,10 @@ scrolln(starts, startw, curs, bot, top)
__mvcur(oy, ox, top, 0, 1);
/* Scroll the block down */
if (SR && (!sr || -n > 1))
- tputs(__tscroll(SR, -n), 0, __cputchar);
+ tputs(__tscroll(SR, -n), -n, __cputchar);
else
for(i = n; i < 0; i++)
- tputs(sr, 0, __cputchar);
+ tputs(sr, 1, __cputchar);
__mvcur(top, 0, oy, ox, 1);
}
if (bot != curscr->maxy - 1 || top != 0)
diff --git a/lib/libcurses/setterm.c b/lib/libcurses/setterm.c
index 35e4e55b26d6..b949ae337843 100644
--- a/lib/libcurses/setterm.c
+++ b/lib/libcurses/setterm.c
@@ -35,6 +35,7 @@
static char sccsid[] = "@(#)setterm.c 8.3 (Berkeley) 1/2/94";
#endif /* not lint */
+#include <termios.h>
#include <sys/ioctl.h>
#include <curses.h>
@@ -42,6 +43,9 @@ static char sccsid[] = "@(#)setterm.c 8.3 (Berkeley) 1/2/94";
#include <string.h>
#include <unistd.h>
+#undef ospeed
+extern short ospeed;
+
static void zap __P((void));
static char *sflags[] = {
@@ -149,6 +153,29 @@ setterm(type)
CA = 1;
PC = _PC ? _PC[0] : 0;
+
+ switch(cfgetospeed(&__baset)) {
+ case B0: ospeed = 0; break;
+ case B50: ospeed = 1; break;
+ case B75: ospeed = 2; break;
+ case B110: ospeed = 3; break;
+ case B134: ospeed = 4; break;
+ case B150: ospeed = 5; break;
+ case B200: ospeed = 6; break;
+ case B300: ospeed = 7; break;
+ case B600: ospeed = 8; break;
+ case B1200: ospeed = 9; break;
+ case B1800: ospeed = 10; break;
+ case B2400: ospeed = 11; break;
+ case B4800: ospeed = 12; break;
+ case B9600: ospeed = 13; break;
+ case EXTA: ospeed = 14; break;
+ case EXTB: ospeed = 15; break;
+ case B57600: ospeed = 16; break;
+ default:
+ case B115200: ospeed = 17; break;
+ }
+
aoftspace = tspace;
ttytype = longname(genbuf, __ttytype);
diff --git a/lib/libcurses/tstp.c b/lib/libcurses/tstp.c
index daac9174d745..164f10bdd8b0 100644
--- a/lib/libcurses/tstp.c
+++ b/lib/libcurses/tstp.c
@@ -54,8 +54,8 @@ __stop_signal_handler(signo)
sigset_t oset, set;
/* Get the current terminal state (which the user may have changed). */
- if (tcgetattr(STDIN_FILENO, &save))
- return;
+ if (tcgetattr(__tty_fileno, &save))
+ return;
/*
* Block window change and timer signals. The latter is because
@@ -87,10 +87,10 @@ __stop_signal_handler(signo)
__set_stophandler();
/* save the new "default" terminal state */
- (void)tcgetattr(STDIN_FILENO, &__orig_termios);
+ (void)tcgetattr(__tty_fileno, &__orig_termios);
/* Reset the terminal state to the mode just before we stopped. */
- (void)tcsetattr(STDIN_FILENO, __tcaction ?
+ (void)tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, &save);
/* Restart the screen. */
diff --git a/lib/libcurses/tty.c b/lib/libcurses/tty.c
index d0345bfba993..3f9eabdb3a98 100644
--- a/lib/libcurses/tty.c
+++ b/lib/libcurses/tty.c
@@ -36,10 +36,12 @@ static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 1/2/94";
#endif /* not lint */
#include <sys/ioctl.h>
+#include <sys/file.h>
#include <curses.h>
#include <termios.h>
#include <unistd.h>
+#include <paths.h>
/*
* In general, curses should leave tty hardware settings alone (speed, parity,
@@ -54,6 +56,7 @@ int __tcaction = 1; /* Ignore hardware settings. */
int __tcaction = 0;
#endif
+int __tty_fileno;
struct termios __orig_termios, __baset;
static struct termios cbreakt, rawt, *curt;
static int useraw;
@@ -75,8 +78,12 @@ gettmode()
{
useraw = 0;
- if (tcgetattr(STDIN_FILENO, &__orig_termios))
- return (ERR);
+ if (tcgetattr(__tty_fileno = STDIN_FILENO, &__orig_termios)) {
+ if ((__tty_fileno = open(_PATH_TTY, O_RDONLY, 0)) < 0)
+ return (ERR);
+ else if (tcgetattr(__tty_fileno, &__orig_termios))
+ return (ERR);
+ }
__baset = __orig_termios;
__baset.c_oflag &= ~OXTABS;
@@ -116,7 +123,7 @@ gettmode()
}
curt = &__baset;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
}
@@ -125,7 +132,7 @@ raw()
{
useraw = __pfast = __rawmode = 1;
curt = &rawt;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -134,7 +141,7 @@ noraw()
{
useraw = __pfast = __rawmode = 0;
curt = &__baset;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -144,7 +151,7 @@ cbreak()
__rawmode = 1;
curt = useraw ? &rawt : &cbreakt;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -154,7 +161,7 @@ nocbreak()
__rawmode = 0;
curt = useraw ? &rawt : &__baset;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -166,7 +173,7 @@ echo()
__baset.c_lflag |= ECHO;
__echoit = 1;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -178,7 +185,7 @@ noecho()
__baset.c_lflag &= ~ECHO;
__echoit = 0;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -193,7 +200,7 @@ nl()
__baset.c_oflag |= ONLCR;
__pfast = __rawmode;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -208,7 +215,7 @@ nonl()
__baset.c_oflag &= ~ONLCR;
__pfast = 1;
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, curt));
}
@@ -216,9 +223,9 @@ void
__set_scroll_region(top, bot)
int top, bot;
{
- tputs(SC, 0, __cputchar);
- tputs(tgoto(CS, bot, top), 0, __cputchar);
- tputs(RC, 0, __cputchar);
+ tputs(SC, 1, __cputchar);
+ tputs(tgoto(CS, bot, top), 1, __cputchar);
+ tputs(RC, 1, __cputchar);
}
void
@@ -253,7 +260,7 @@ endwin()
(void)fflush(stdout);
(void)setvbuf(stdout, NULL, _IOLBF, 0);
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, &__orig_termios));
}
@@ -266,12 +273,12 @@ static struct termios savedtty;
int
savetty()
{
- return (tcgetattr(STDIN_FILENO, &savedtty));
+ return (tcgetattr(__tty_fileno, &savedtty));
}
int
resetty()
{
- return (tcsetattr(STDIN_FILENO, __tcaction ?
+ return (tcsetattr(__tty_fileno, __tcaction ?
TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty));
}
diff --git a/lib/libmalloc/CHANGES b/lib/libmalloc/CHANGES
new file mode 100644
index 000000000000..eaade6259236
--- /dev/null
+++ b/lib/libmalloc/CHANGES
@@ -0,0 +1,58 @@
+Jan 29, 1994 v1.13
+
+Subtle realloc bug uncovered by Gianni Mariani's super malloc stress test.
+(realloc could return a block less than _malloc_minchunk which could cause
+free to die under certain conditions). testmalloc now checks this case.
+
+Dec 15, 1993
+
+Fixed various problems with formats (printing ints for longs or vice versa)
+pointed out by der Mouse. Integrated old fix to make grabhunk work if
+blocks returned by the memfunc routine (sbrk, etc) are lower than the
+previous blocks. Not well-tested yet.
+
+Jul 30, 1993
+
+Bunch of fixes from mds@ilight.com (Mike Schechterman) to make it compile
+and work on Alpha/OSF1, RS6000/AIX3.2, SGI/Irix4.0.5, HP720/HP-UX8.0.7,
+DEC5000/Ultrix4.2. Thanks, Mike.
+
+Major user visible change is that 'make onefile' becomes 'make one' because
+of overly-smart 'make's. Minor change is that testmalloc, teststomp and
+simumalloc all want stdlib.h or proper stdio.h, else they have implicit
+ints. I don't want to declare libc functions.
+
+Added ecalloc, _ecalloc.
+
+--
+Added mmap() support.
+
+Cleaned up externs.h a bit more, added sysconf() call for Posix
+
+Merged some of the smaller files into larger ones.
+
+Added mal_contents from ZMailer version of malloc, changed counters in
+leak.c from long to unsigned long.
+
+On a pure allocation pattern, the old one started to take a bad
+performance hit on the search that precedes an sbrk, because of the
+wilderness preservation problem -- we search through every block in
+the free list before the sbrk, even though none of them will satisfy
+the request, since they're all probably little chunks left over from
+the last sbrk chunk. So our performance reduces to the same as that of
+the 4.1 malloc. Yech. If we were to preserve the wilderness, we
+wouldn't have these little chunks. Good enough reason to reverse the
+philosophy and cut blocks from the start, not the end. To minimize
+pointer munging, means we have to make the block pointer p point to
+the end of the block (i.e the end tag) NEXT becomes (p-1)->next, PREV
+becomes (p-2)->prev, and the start tag becomes (p + 1 -
+p->size)->size. The free logic is reversed -- preceding block merge
+needs pointer shuffle, following block merge doesn't require pointer
+shuffle. (has the additional advantage that realloc is more likely to
+grow into a free area) Did this -- malloc, free stayed as complex/big,
+but realloc and memalign simplified a fair bit. Now much faster on
+pure allocation pattern, as well as any pattern where allocation
+dominates, since fragmentation is less. Also much less wastage.
+
+Also trimmed down the search loop in malloc.c to make it much smaller
+and simpler, also a mite faster.
diff --git a/lib/libmalloc/COPYRIGHT b/lib/libmalloc/COPYRIGHT
new file mode 100644
index 000000000000..5c3c417945d3
--- /dev/null
+++ b/lib/libmalloc/COPYRIGHT
@@ -0,0 +1,23 @@
+/*
+ * Copyright University of Toronto 1988, 1989, 1993.
+ * Written by Mark Moraes
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author and the University of Toronto are not responsible
+ * for the consequences of use of this software, no matter how awful,
+ * even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ */
+/* This COPYRIGHT does not apply to the subdirectory splay and its contents */
diff --git a/lib/libmalloc/Makefile b/lib/libmalloc/Makefile
new file mode 100644
index 000000000000..2ff0abf62b7f
--- /dev/null
+++ b/lib/libmalloc/Makefile
@@ -0,0 +1,17 @@
+# $Id: Makefile,v 1.2 1994/05/27 10:42:42 csgr Exp $
+
+CFLAGS+= -I${.CURDIR} -DHAVE_MMAP -DSTDHEADERS -fno-builtin
+PFLAGS+= -DTRACE -DPROFILESIZES
+
+LIB= malloc
+
+SRCS+= _emalloc.c _malloc.c _memalign.c _strdup.c _strsave.c botch.c \
+ dumpheap.c emalloc.c getmem.c leak.c malloc.c memalign.c setopts.c \
+ sptree.c stats.c strdup.c strsave.c verify.c
+NOMAN= noman
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/malloc.h \
+ ${DESTDIR}/usr/include
+
+.include <bsd.lib.mk>
diff --git a/lib/libmalloc/Makefile.moraes b/lib/libmalloc/Makefile.moraes
new file mode 100644
index 000000000000..c9d7fa3d45f6
--- /dev/null
+++ b/lib/libmalloc/Makefile.moraes
@@ -0,0 +1,187 @@
+# $Id: Makefile.moraes,v 1.1 1994/03/06 22:59:15 nate Exp $
+#
+# This Makefile is set up to make a debugging malloc called libmalloc_d.a
+# Also generates testmalloc and simumalloc, two regression tests.
+#
+# To make a production malloc, type 'make clean libmalloc'
+#
+# If you're impatient, and want it all in one file, type 'make one'
+# and it'll merge the all the source into one file. Bit bigger, but
+# avoids Unix linker misunderstandings if these are not in libc, and
+# ensures the debugging routines are linked in whether called or not.
+# On some machines, mv onefile.o libmalloc_d.a will work. On some, it
+# upsets the linker and you will need to "ar ruv libmalloc_d.a onefile.o".
+#
+# 'make dist' runs 'bundle' to create a shell archive on stdout.
+#
+# 'make veryclean' cleans out lib*.a as well.
+#
+# 'make depend' runs 'mkdep' (from BSD src or named) to create dependencies.
+#
+# 'make install' puts all the OBJS in $(ARCHIVE), ranlibs it, and
+# puts malloc.h in INCDIR.
+#
+
+# neutralize SystemV genius
+SHELL=/bin/sh
+
+# DEBUGDEFS are set for libmalloc_d.a. Say 'make libmalloc' for nondebug
+# version. (DEBUGDEFS=$(FASTDEFS))
+#
+DEBUGDEFS=-DDEBUG -DTRACE -DPROFILESIZES
+
+# FASTDEFS are used when the 'libmalloc' target is made.
+#
+# -DTRACE and -DPROFILESIZES shouldn't introduce very much overhead since the
+# former is turned off (one 'if'), and the latter is one 'if' + increment.
+# So you can keep them even in the fast production version.
+# You may want to define -DBUGCOMPATIBILITY if you want malloc(0) to
+# do the same thing as malloc(1). Some suntools programs expect this
+# behaviour. So does Xlib, and the X server has done it at least once.
+# (Note that SVID requires malloc(0) to return NULL, and the
+# May 13, 1988 ANSI C draft says that you can either return a NULL pointer
+# or a unique pointer (typically decisive standard...)
+#
+FASTDEFS=#-DBUGCOMPATIBILITY -DTRACE -DPROFILESIZES
+
+
+# NORMALDEFS are used for both debugging and non-debugging versions
+# -DSHORTNAMES makes sure all internal global symbols are unique within 6
+# characters. Avoid defining unless your linker is braindead.
+# -DUSESTDIO is to make this use fputs() instead of write() for trace
+# and debugging output. write() is preferable since it is unbuffered,
+# and does not call malloc() or suchlike. Avoid defining if possible.
+# -DSTDHEADERS if you have ANSI standard header files (stdlib.h, string.h)
+# This can be defined on Solaris2.1, Irix3.3.x, BSD3.3,
+# 386BSD, BSD386 and other sufficiently Posix systems.
+# -DHAVE_MMAP should be defined for SunOS4.x and other systems
+# that have a general purpose mmap call that allows memory-mapped files.
+#
+NORMALDEFS=-DHAVE_MMAP -DSTDHEADERS # -DSHORTNAMES -DUSESTDIO
+
+LIBMALLOC=libmalloc_d.a
+ARCHIVE = $(HOME)/lib/$(LIBMALLOC)
+
+DEFINES= $(NORMALDEFS) $(DEBUGDEFS)
+
+LIBDIR=$(HOME)/lib
+INCDIR=$(HOME)/include
+
+CC = gcc -Wall # -pedantic # add -pedantic if you fixed your includes.
+# SGI needs cc -xansi -D__STDC__ on Irix4.0.5.
+
+EXTRAINCLUDES=-I$(HOME)/include
+CDEBUGFLAGS=-g -O
+
+SPLAYOBJ = splay/sptree.o
+SPLAYSRC = splay/sptree.c
+SPLAYHDR = splay/sptree.h
+
+SRCS = _emalloc.c _malloc.c _memalign.c \
+ _strdup.c _strsave.c botch.c \
+ dumpheap.c emalloc.c getmem.c leak.c \
+ malloc.c memalign.c setopts.c \
+ stats.c strdup.c strsave.c verify.c
+
+OBJS = _emalloc.o _malloc.o _memalign.o \
+ _strdup.o _strsave.o botch.o \
+ dumpheap.o emalloc.o getmem.o leak.o \
+ malloc.o memalign.o setopts.o \
+ stats.o strdup.o strsave.o verify.o
+
+# HDRS, DOCS, TESTS and EXTRAS are used when making distributions.
+# so please keep them uptodate.
+# bundle is smart enough not to include object files, RCS, executables,
+# etc, and does subdirectories right, but there's often other files
+# in the development directory...
+
+# globals.c, version.c are included in malloc.c.
+HDRS = align.h assert.h defs.h externs.h globals.c globals.h globrename.h \
+ malloc.h trace.h version.c
+
+DOCS = README NOTE TODO CHANGES malloc.doc Makefile
+
+TESTS = testmalloc.c test.out testsbrk.c teststomp.c tests regress \
+ simumalloc.c testrun.sh plot.sh munge.sh
+
+EXTRAS = splay
+
+INCLUDES=-I./splay $(EXTRAINCLUDES)
+
+LN = ln -s
+OLDCC = cc
+OLDCFLAGS = -O
+AR = ar
+ARFLAGS = ruv
+RANLIB = ranlib
+
+LDFLAGS=#-Bstatic
+
+CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(DEFINES)
+
+all: $(LIBMALLOC) testmalloc simumalloc teststomp
+
+libmalloc:
+ make -f Makefile $(MFLAGS) CC="$(CC)" DEBUGDEFS="$(FASTDEFS)" \
+ LIBMALLOC=libmalloc.a CDEBUGFLAGS="$(CDEBUGFLAGS)"
+
+testmalloc: testmalloc.o $(LIBMALLOC)
+ $(CC) $(CFLAGS) -o testmalloc testmalloc.o $(LIBMALLOC) ${LDFLAGS}
+
+teststomp: teststomp.o $(LIBMALLOC)
+ $(CC) $(CFLAGS) -o teststomp teststomp.o $(LIBMALLOC) ${LDFLAGS}
+
+simumalloc: simumalloc.c $(LIBMALLOC)
+ $(CC) $(CFLAGS) -DMYMALLOC -o simumalloc \
+ simumalloc.c $(LIBMALLOC) ${LDFLAGS}
+
+$(LIBMALLOC): $(OBJS) $(SPLAYOBJ)
+ rm -f $(LIBMALLOC)
+ $(AR) $(ARFLAGS) $(LIBMALLOC) $(OBJS) $(SPLAYOBJ)
+ -$(RANLIB) $(LIBMALLOC)
+
+$(SPLAYOBJ): .foo
+ cd splay; make $(MFLAGS) DEFINES="$(DEFINES)" \
+ LIBMALLOC=../$(LIBMALLOC) CC="$(CC)"
+
+one: onefile.o
+
+onefile.c: $(SRCS) $(SPLAYSRC)
+ rm -f onefile.c
+ cat $(SRCS) $(SPLAYSRC) | sed '/RCSID/d' > onefile.c
+
+.foo:
+
+clean:
+ -rm -f *.o \#* *~ core a.out gmon.out mon.out testmalloc simumalloc \
+ teststomp onefile.c *.sL prof.out
+ cd splay; make clean
+
+veryclean: clean
+ -rm -f libmalloc.a libmalloc_d.a make.log make.out
+
+install:
+ $(AR) $(ARFLAGS) $(ARCHIVE) $(OBJS) $(SPLAYOBJ)
+ -$(RANLIB) $(ARCHIVE)
+ install -c -m 644 malloc.h $(INCDIR)
+
+.id: $(SRCS)
+ mkid $(SRCS) $(SPLAYSRC) $(HDRS) $(SPLAYHDR)
+ touch .id
+
+dist:
+ @rm -f Makefile.bak
+ @mv Makefile Makefile.bak;\
+ sed '/^# DO NOT PUT ANYTHING/,$$d' Makefile.bak > Makefile; \
+ (bundle -v $(DOCS) $(SRCS) $(HDRS) $(TESTS) $(EXTRAS)); \
+ mv Makefile.bak Makefile
+
+files:
+ find * -type f -print | \
+ egrep -v '(,v|\.o|core|make.log|simumalloc|testmalloc|teststomp)$$' | \
+ egrep -v '(libmalloc.*\.a|res\..*)$$' > FILES
+
+depend: onefile.c
+ mkdep $(INCLUDES) $(DEFINES) $(SRCS) onefile.c
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/lib/libmalloc/NOTE b/lib/libmalloc/NOTE
new file mode 100644
index 000000000000..dede8664d38e
--- /dev/null
+++ b/lib/libmalloc/NOTE
@@ -0,0 +1,151 @@
+Miscellaneous notes on the malloc internals.
+
+First fit malloc with boundary tags for fast freeing - based on the
+techniques described in 'The Art of Computer Programming' by Donald
+Knuth. The essential features of the boundary tag are described in
+Algorithm C, Section 2.5. The actual algorithms here incorporate the
+improvements suggested in Exercises 12 and and 15 (I think), and
+adaptations to the C/Un*x environment, plus some performance
+improvements. By keeping the list circular, we don't have an AVAIL at
+all - just use ROVER as the pointer into the list. It also tries to
+"preserve the wilderness" -- i.e. try to keep the block nearest the
+data break free as far as possible, but it does go overboard about it.
+(i.e. it is a simple first fit -- many wilderness preservation schemes
+tend to keep the wilderness block out of the free list, and search the
+rest of the free list first. I find that degrades performance
+somewhat, even if it keeps memory slightly less fragmented)
+
+This has a lot of debugging and tracing support built in - compiling
+with -DDEBUG provides fairly comprehensive ASSERT protection to detect
+heap corruption. (It aborts on the first sign of trouble). I hope that
+every pointer reference is protected with an assertion, so the malloc
+should never dump core or behave weirdly because of user program
+misbehaviour -- it should blow an assertion instead. If the debugging
+version ever gets a segmentation fault, bus error and dumps core
+instead of blowing an assertion and then dumping core on an IO trap or
+Illegal Instruction (depending on how your system does an abort()), I
+want to know...
+
+For the non-debugging malloc:
+
+A minimum size for an allocated block is 4 units - two for the
+leading and trailing size word, and two for the next and previous
+pointers. Therefore the minimum size that we can allocate is 2
+units, since allocated and freed blocks both have the leading and
+trailing size blocks. Only freed blocks have the next, prev
+pointers. The size block is actually a signed - the sign bit
+indicates whether it is a free or allocated block. i.e the tag.
+
+For the debugging malloc:
+
+The minimum size for an allocated block is still 4 units - two for the
+leading and trailing size word, and two for the next and previous
+pointers. But the minimum size that we can allocate is 1 units, since
+allocated and freed blocks both have the leading and trailing size
+blocks. Only freed blocks have the next, prev pointers. Only allocated
+blocks have the realsize word, which indicates the size of the block
+requested by the user in bytes. The next pointer and the realsize word
+share the same header word. So the overhead for an allocated block is
+3 words when debugging, as opposed to 2 words when not debugging.
+(even though the minimum block size is still 4 words)
+
+The size block is actually a signed - the sign bit indicates whether
+it is a free or allocated block. i.e the tag. Since the size is in
+words, this loss of a bit is no big deal. The realsize block is a full
+unsigned word, since it stores the size in bytes.
+
+For the leak tracing malloc
+
+The _*.c files all have the extra macros that record the blocks as
+they are allocated, and deleted. The extra tracing macro also prints
+the file name and line number before the usual tracing information
+about size etc. This permits you to find out where block xxx was
+freed, so that you can do an address to name mapping more easily.
+
+Note that to use this stuff, you HAVE to include malloc.h and define
+MALLOC_TRACE when compiling. It still works correctly when you don't
+include malloc.h, but you won't get all the information.
+
+Performance
+
+The fastest malloc I know of is the BSD4.3 malloc, which uses a number
+of bins with different sized blocks, sized in powers of two. All it
+has to do to find a free block is an iterated shift to compute the
+bin, if the bin is empty then split a block from one of the higher
+bins. Unfortunately, it can waste spectacular amounts of space for
+many programs.
+
+The most space efficient malloc I know is Sun's Cartesian tree "better
+fit" malloc (It has a hidden overhead of 8K of static data, though).
+It is also unpleasantly slow.
+
+My malloc is close to the BSD4.3 malloc in performance - the
+difference starts to become obvious only as the number of blocks in
+the free list climbs towards the 100000 to million range at which
+point the 4.3 malloc starts to pull ahead in user time, but quite
+often, its VM behaviour deteriorates and makes its elapsed times very
+large. My malloc is close to Sun's malloc in space efficiency.
+
+The key to the improved performance over typical first fit allocators
+is the roving pointer, as well as the coalescing of freed blocks,
+which keeps memory fragmentation and the size of the free list down.
+The wilderness preservation heuristic also helps a lot.
+
+Guide to porting it:
+
+Should port without trouble to machines where any ugliness or
+weirdness in pointers or segmentation is hidden from the programmer. I
+haven't tried porting it to the 286 and below under DOS, nor do I
+intend to at present.
+
+You may need to check align.h if your machine has non-standard
+alignment requirements. (I interpret standard alignment to be
+alignenment on one of char, int, char *, int *, char **, int **,
+whichever requires the strictest alignment) If not, define ALIGN and
+NALIGN.
+
+PLEASE LEAVE THE MAIN CODE FREE FROM #ifdefs. I'm interested in fixes
+for porting it to new machines, only if they do not damage the code.
+I'd prefer to find a least common denominator, or hide the difference
+in a macro.
+
+People interested in reading and understanding this code should start
+in defs.h (after this file, of course) -- it contains all the macros.
+It'll help if you've read the following references. After that, study
+globals.c, malloc.c, verify.c and dumpheap.c. Running testmalloc and
+following the development of the heap is recommended.
+
+After you've ported it, you should be able to run testmalloc without
+trouble, as well as the few runs of simumalloc listed in regress,
+compiled with the debugging version of malloc. (-DDEBUG defined)
+
+If you uncover a bug, please enhance testmalloc.c with a case that
+triggers the bug, if you can. That way, I can make sure future changes
+to malloc don't re-introduce that bug.
+
+References:
+
+%A Donald E. Knuth
+%T The Art of Computer Programming (Fundamental Algorithms)
+%V 1
+%I Addison Wesley
+%C Reading, Mass.
+%D 1973
+
+%A David G. Korn
+%A Kiem-Phong Vo
+%T In search of a better malloc
+%J Proceedings of the USENIX 1985 Summer Conference
+%C Portland, Oregon
+%D June 1985
+%P 489-506
+
+%A C.J. Stephenson
+%T Fast fits: new methods for dynamic storage allocation
+%J Proceedings of the Ninth ACM Symposium on Operating Systems Principles
+%C Bretton Woods, New Hampshire
+%D October 1983
+%P 30-32
+%O abstract only - paper to be published in TOCS
+%O published as Operating Systems Review 17:5
+%O also appeared in Scientific American somewhere -- reference in Korn and Vo
diff --git a/lib/libmalloc/README b/lib/libmalloc/README
new file mode 100644
index 000000000000..6d508d37477e
--- /dev/null
+++ b/lib/libmalloc/README
@@ -0,0 +1,68 @@
+This is a complete set of memory allocation functions (malloc and
+friends).
+ The allocator is small, fast and space-efficient.
+
+ It performs coalescing on frees.
+
+ It has hooks for profiling, tracing and memory leak detection.
+
+ It has very comprehensive and paranoid errorchecking as a compile
+ time option, enough to detect most forms of heap corruption.
+
+ Optionally, it attempts to be compatible with the proposed ANSI C
+ Standard definition for the standard library functions malloc(),
+ calloc(), realloc() and free(). By default, it is more or less
+ compatible with existing Unix malloc() functions - some
+ differences do exist. (Notably free(), cfree() returning void,
+ realloc() not accepting a freed block)
+
+See the file malloc.doc for the full details.
+
+Porting to other machines shouldn't be hard if they have a civilized C
+compiler, and an sbrk().
+
+Eventually, the goal is to make this malloc() conformant with ANSI C -
+it's getting there. It can be convinced to return void * and accept
+size_t, so you can use it for ANSI C conformant programs by defining
+ANSI_TYPES. Till then it's meant to be broadly conformant with Unix
+malloc()s.
+
+To compile it, make sure ALIGN (in align.h) is correct for your machine, and
+make it. testmalloc should run correctly and say Test done if it is
+working, producing amazing amounts of heap trace. If it dumps core, it
+isn't working...
+
+Depending on which end of the philosophical spectrum you lie, define
+-DBUGCOMPATIBILITY. If defined, malloc(0) will do the same thing as
+malloc(1). If not defined, the debugging malloc will abort() with an
+error, while the non-debugging malloc will return NULL. (and set errno
+to EINVAL). Note that the SVID requires malloc(0) to return NULL, and
+the May 13, 1988 ANSI C draft says that you can either return a NULL
+pointer or a unique pointer (typically decisive standard...)
+
+libmalloc.a is a fast, small version, with no
+debugging/profiling/tracing, while libmalloc_d.a is the version with
+all those three. (Profiling and tracing should not introduce serious
+overhead, since profiling is simple and fast, (one 'if' and increment),
+while tracing is turned off by default. So you may want to keep
+profiling and tracing in the fast version as well)
+ make clean all
+will make libmalloc_d.a and the test programs.
+
+ make clean libmalloc
+will make libmalloc.a.
+
+For linking convenience, you may want to compile the malloc as one
+file instead. To do that, simply make onefile.o. It concatenates all
+the src together and compiles it - the include files are protected
+against multiple inclusion. This has the advantage of compiling in
+things like mal_verify() and mal_trace() even if they aren't used, so
+you can use them when debugging.
+
+ Mark Moraes.
+ Computer Systems Research Institute,
+ Univerity of Toronto.
+ moraes@csri.toronto.{edu,cdn}
+ moraes@csri.utoronto.ca
+ moraes@utcsri.uucp
+ {your favourite backbone}!uunet!utai!utcsri!moraes
diff --git a/lib/libmalloc/TODO b/lib/libmalloc/TODO
new file mode 100644
index 000000000000..ae4430a74516
--- /dev/null
+++ b/lib/libmalloc/TODO
@@ -0,0 +1,62 @@
+alloca-like allocation with malloc -- mark()/release() paradigm. specify a
+point where one starts a stack (stk_create), and stk_alloc from that.
+stk_free releases the specified stack. This speeds up frees, doesn't speed
+up mallocs too much? Time it in trace situations.
+
+Tests all in subdirectory.
+
+sbrk stuff for Mach.
+
+Scan all my email on malloc?
+
+Make the document a manual page. Terser, less cutesy.
+
+mal_size() returns size of a malloc'ed block in bytes.
+
+before starting a search in malloc(), if rover points to wilderness, and
+wilderness->next is not null, rover = wilderness->next. need to keep
+wilderness uptodate. should help rayan.
+
+check alignment in IS_VALID_PTR.
+
+Adaptive sbrk size. Keep increasing it by DEF_SBRKUNITS, then if sbrk fails,
+half the sbrkunits till we're smaller than the request (in which case it's
+all over). Should reduce the number of calls to sbrk without increasing
+wastage too much.
+
+Generalize grabhunk() to work properly if new arenas are lower than the old
+ones - i.e. don't rely on sbrk() semantics at all. I already did some of
+this work in the port to the Firefly. [DONE -- Dec 15, 1993]
+
+Check that totalavail works right for realloc. Should we scrap totalavail
+and save a pointer to the max block, so that can both tell if we need to
+sbrk without a search, as well as realize if the max block has shrunk.
+Problem: how do we know if the max block shrank below the size of some other
+block? Heuristic? Average block size? Some adapting fraction of totalavail?
+We sbrk if request is greater than (1+fraction)*totalavail/nfree is what
+Korn and Vo suggest. Assuming fraction is always 1/K, we get
+(K+1)*totalavail/K/nfree. We can double K everytime we fail a search. To
+provide some negative feedback, we can change the 1 to M, and increment M
+everytime we succeed in a search. Doesn't sound good. Need a better
+heuristic. Grump. Avoid this stuff for now.
+
+Separate all system dependent stuff into a sysdep header where these things
+can fight it out.
+
+create stdlib.h and move std. decls there. keep malloc.h as a value added
+thing and declare new stuff there. decide on malloc(0).
+(malloc 0 should return 0 sized block by default, I think)
+
+setopt Non-ansi should cause malloc(0), realloc(0, *) or realloc(*, 0)
+to fail.
+
+some way to report when the last free happened when you try to use a freed
+pointer. maintain a splay tree where you add ptrs when you free'em and
+delete when you malloc them?
+
+finish my trace driven simulation stuff in ../maltrace.
+
+way to walk the heap. if it is a macro, then the other two could use it too.
+should probably switch to arena before all these changes.
+
+interns.h from externs.h. Then we don't need aexterns.h.
diff --git a/lib/libmalloc/_emalloc.c b/lib/libmalloc/_emalloc.c
new file mode 100644
index 000000000000..347e8960f088
--- /dev/null
+++ b/lib/libmalloc/_emalloc.c
@@ -0,0 +1,55 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _emalloc.c,v 1.1 1994/03/06 22:59:19 nate Exp $")
+
+univptr_t
+__emalloc(nbytes, fname, linenum)
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = emalloc(nbytes);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+
+univptr_t
+__erealloc(ptr, nbytes, fname, linenum)
+univptr_t ptr;
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = erealloc(ptr, nbytes);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+univptr_t
+__ecalloc(nelem, sz, fname, linenum)
+size_t nelem, sz;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = ecalloc(nelem, sz);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+
diff --git a/lib/libmalloc/_malloc.c b/lib/libmalloc/_malloc.c
new file mode 100644
index 000000000000..34104e47f8c7
--- /dev/null
+++ b/lib/libmalloc/_malloc.c
@@ -0,0 +1,88 @@
+/*
+ * These are the wrappers around malloc for detailed tracing and leak
+ * detection. Allocation routines call RECORD_FILE_AND_LINE to record the
+ * filename/line number keyed on the block address in the splay tree,
+ * de-allocation functions call DELETE_RECORD to delete the specified block
+ * address and its associated file/line from the splay tree.
+ */
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _malloc.c,v 1.1 1994/03/06 22:59:20 nate Exp $")
+
+univptr_t
+__malloc(nbytes, fname, linenum)
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = malloc(nbytes);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+/* ARGSUSED if TRACE is not defined */
+void
+__free(cp, fname, linenum)
+univptr_t cp;
+const char *fname;
+int linenum;
+{
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ DELETE_RECORD(cp);
+ free(cp);
+}
+
+univptr_t
+__realloc(cp, nbytes, fname, linenum)
+univptr_t cp;
+size_t nbytes;
+const char *fname;
+int linenum;
+{
+ univptr_t old;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ old = cp;
+ cp = realloc(cp, nbytes);
+ if (old != cp) {
+ DELETE_RECORD(old);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ }
+ return(cp);
+}
+
+univptr_t
+__calloc(nelem, elsize, fname, linenum)
+size_t nelem, elsize;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = calloc(nelem, elsize);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+/* ARGSUSED if TRACE is not defined */
+void
+__cfree(cp, fname, linenum)
+univptr_t cp;
+const char *fname;
+int linenum;
+{
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ DELETE_RECORD(cp);
+ /* No point calling cfree() - it just calls free() */
+ free(cp);
+}
diff --git a/lib/libmalloc/_memalign.c b/lib/libmalloc/_memalign.c
new file mode 100644
index 000000000000..c39b3d269065
--- /dev/null
+++ b/lib/libmalloc/_memalign.c
@@ -0,0 +1,37 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _memalign.c,v 1.1 1994/03/06 22:59:21 nate Exp $")
+
+univptr_t
+__memalign(alignment, size, fname, linenum)
+size_t alignment, size;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = memalign(alignment, size);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
+
+univptr_t
+__valloc(size, fname, linenum)
+size_t size;
+const char *fname;
+int linenum;
+{
+ univptr_t cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = valloc(size);
+ RECORD_FILE_AND_LINE(cp, fname, linenum);
+ return(cp);
+}
diff --git a/lib/libmalloc/_strdup.c b/lib/libmalloc/_strdup.c
new file mode 100644
index 000000000000..074bc1d68916
--- /dev/null
+++ b/lib/libmalloc/_strdup.c
@@ -0,0 +1,23 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _strdup.c,v 1.1 1994/03/06 22:59:21 nate Exp $")
+
+char *
+__strdup(s, fname, linenum)
+char *s;
+const char *fname;
+int linenum;
+{
+ char *cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = strdup(s);
+ RECORD_FILE_AND_LINE((univptr_t) cp, fname, linenum);
+ return(cp);
+}
diff --git a/lib/libmalloc/_strsave.c b/lib/libmalloc/_strsave.c
new file mode 100644
index 000000000000..1db174d73d39
--- /dev/null
+++ b/lib/libmalloc/_strsave.c
@@ -0,0 +1,23 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "trace.h"
+
+RCSID("$Id: _strsave.c,v 1.1 1994/03/06 22:59:22 nate Exp $")
+
+char *
+__strsave(s, fname, linenum)
+char *s;
+const char *fname;
+int linenum;
+{
+ char *cp;
+
+ PRTRACE(sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum));
+ cp = strsave(s);
+ RECORD_FILE_AND_LINE((univptr_t) cp, fname, linenum);
+ return(cp);
+}
diff --git a/lib/libmalloc/align.h b/lib/libmalloc/align.h
new file mode 100644
index 000000000000..c1424895a9a3
--- /dev/null
+++ b/lib/libmalloc/align.h
@@ -0,0 +1,94 @@
+/* $Id: align.h,v 1.1 1994/03/06 22:59:26 nate Exp $ */
+#ifndef __ALIGN_H__
+#define __ALIGN_H__
+/*
+ * 'union word' must be aligned to the most pessimistic alignment needed
+ * on the architecture (See align.h) since all pointers returned by
+ * malloc and friends are really pointers to a Word. This is the job of
+ * the 'foo' field in the union, which actually decides the size. (On
+ * Sun3s, 1 int/long (4 bytes) is good enough, on Sun4s, 8 bytes are
+ * necessary, i.e. 2 ints/longs)
+ */
+/*
+ * 'union word' should also be the size necessary to ensure that an
+ * sbrk() immediately following an sbrk(sizeof(union word) * n) returns
+ * an address one higher than the first sbrk. i.e. contiguous space from
+ * successive sbrks. (Most sbrks will do this regardless of the size -
+ * Sun's doesnt) This is not vital - the malloc will work, but will not
+ * be able to coalesce between sbrk'ed segments.
+ */
+
+#if defined(sparc) || defined(__sparc__) || defined(__sgi)
+/*
+ * Sparcs require doubles to be aligned on double word, SGI R4000 based
+ * machines are 64 bit, this is the conservative way out
+ */
+/* this will waste space on R4000s or the 64bit UltraSparc */
+# define ALIGN long foo[2]
+# define NALIGN 8
+#endif
+
+#if defined(__alpha)
+/* 64 bit */
+# define ALIGN long foo
+# define NALIGN 8
+#endif
+
+/* This default seems to work on most 32bit machines */
+#ifndef ALIGN
+# define ALIGN long foo
+# define NALIGN 4
+#endif
+
+/* Align with power of 2 */
+#define SIMPLEALIGN(X, N) (univptr_t)(((size_t)((char *)(X) + (N-1))) & ~(N-1))
+
+#if NALIGN == 2 || NALIGN == 4 || NALIGN == 8 || NALIGN == 16
+ /* if NALIGN is a power of 2, the next line will do ok */
+# define ALIGNPTR(X) SIMPLEALIGN(X, NALIGN)
+#else
+ /* otherwise we need the generic version; hope the compiler isn't too smart */
+ static size_t _N = NALIGN;
+# define ALIGNPTR(X) (univptr_t)((((size_t)((univptr_t)(X)+(NALIGN-1)))/_N)*_N)
+#endif
+
+/*
+ * If your sbrk does not return blocks that are aligned to the
+ * requirements of malloc(), as specified by ALIGN above, then you need
+ * to define SBRKEXTRA so that it gets the extra memory needed to find
+ * an alignment point. Not needed on Suns on which sbrk does return
+ * properly aligned blocks. But on U*x Vaxen, A/UX and UMIPS at least,
+ * you need to do this. It is safer to take the non Sun route (!! since
+ * the non-sun part also works on Suns, maybe we should just remove the
+ * Sun ifdef)
+ */
+#if ! (defined(sun) || defined(__sun__))
+# define SBRKEXTRA (sizeof(Word) - 1)
+# define SBRKALIGN(x) ALIGNPTR(x)
+#else
+# define SBRKEXTRA 0
+# define SBRKALIGN(x) (x)
+#endif
+
+#ifndef BITSPERBYTE
+ /*
+ * These values should work with any binary representation of integers
+ * where the high-order bit contains the sign. Should be in values.h,
+ * but just in case...
+ */
+ /* a number used normally for size of a shift */
+# if gcos
+# define BITSPERBYTE 9
+# else /* ! gcos */
+# define BITSPERBYTE 8
+# endif /* gcos */
+#endif /* BITSPERBYTE */
+
+#ifndef BITS
+# define BITS(type) (BITSPERBYTE * (int) sizeof(type))
+#endif /* BITS */
+
+/* size_t with only the high-order bit turned on */
+#define HIBITSZ (((size_t) 1) << (BITS(size_t) - 1))
+
+#endif /* __ALIGN_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/assert.h b/lib/libmalloc/assert.h
new file mode 100644
index 000000000000..08f11ff87994
--- /dev/null
+++ b/lib/libmalloc/assert.h
@@ -0,0 +1,10 @@
+/* $Id: assert.h,v 1.1 1994/05/19 14:34:09 nate Exp $ */
+#ifndef __ASSERT_H__
+#define __ASSERT_H__
+#ifdef DEBUG
+#define ASSERT(p, s) ((void) (!(p) ? __m_botch(s, __FILE__, __LINE__) : 0))
+extern int __m_botch proto((const char *, const char *, int));
+#else
+#define ASSERT(p, s)
+#endif
+#endif /* __ASSERT_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/botch.c b/lib/libmalloc/botch.c
new file mode 100644
index 000000000000..93b28b4938c8
--- /dev/null
+++ b/lib/libmalloc/botch.c
@@ -0,0 +1,45 @@
+#include "defs.h"
+#include "globals.h"
+
+int
+__nothing()
+{
+ return 0;
+}
+
+/*
+ * Simple botch routine - writes directly to stderr. CAREFUL -- do not use
+ * printf because of the vile hack we use to redefine fputs with write for
+ * normal systems (i.e not super-pure ANSI)!
+ */
+int
+__m_botch(s, filename, linenumber)
+const char *s;
+const char *filename;
+int linenumber;
+{
+ static char linebuf[32]; /* Enough for a BIG linenumber! */
+ static int notagain = 0;
+
+ if (notagain == 0) {
+ /* Try to flush the trace file and unbuffer stderr */
+ (void) fflush(_malloc_statsfile);
+ (void) setvbuf(stderr, (char *) 0, _IONBF, 0);
+ (void) sprintf(linebuf, "%d: ", linenumber);
+ (void) fputs("memory corruption error detected, file ",
+ stderr);
+ (void) fputs(filename, stderr);
+ (void) fputs(", line ", stderr);
+ (void) fputs(linebuf, stderr);
+ (void) fputs(s, stderr);
+ (void) fputs("\n", stderr);
+ /*
+ * In case stderr is buffered and was written to before we
+ * tried to unbuffer it
+ */
+ (void) fflush(stderr);
+ notagain++; /* just in case abort() tries to cleanup */
+ abort();
+ }
+ return 0; /* SHOULDNTHAPPEN */
+}
diff --git a/lib/libmalloc/bsd.lib.mk b/lib/libmalloc/bsd.lib.mk
new file mode 100644
index 000000000000..4e4c51298e8d
--- /dev/null
+++ b/lib/libmalloc/bsd.lib.mk
@@ -0,0 +1,269 @@
+# from: @(#)bsd.lib.mk 5.26 (Berkeley) 5/2/91
+# $Id: bsd.lib.mk,v 1.1 1994/03/06 22:59:28 nate Exp $
+#
+
+.if exists(${.CURDIR}/../Makefile.inc)
+.include "${.CURDIR}/../Makefile.inc"
+.endif
+
+.if exists(${.CURDIR}/shlib_version)
+SHLIB_MAJOR != . ${.CURDIR}/shlib_version ; echo $$major
+SHLIB_MINOR != . ${.CURDIR}/shlib_version ; echo $$minor
+.endif
+
+
+LIBDIR?= /usr/lib
+LINTLIBDIR?= /usr/libdata/lint
+LIBGRP?= bin
+LIBOWN?= bin
+LIBMODE?= 444
+
+STRIP?= -s
+
+BINGRP?= bin
+BINOWN?= bin
+BINMODE?= 555
+
+.MAIN: all
+
+# prefer .s to a .c, add .po, remove stuff not used in the BSD libraries
+# .so used for PIC object files
+.SUFFIXES:
+.SUFFIXES: .out .o .po .so .s .S .c .cc .cxx .m .C .f .y .l
+
+.c.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.c.po:
+ ${CC} -p ${CFLAGS} ${PFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.c.so:
+ ${CC} ${PICFLAG} -DPIC ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+.cc.o .cxx.o .C.o:
+ ${CXX} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.cc.po .C.po .cxx.o:
+ ${CXX} -p ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.cc.so .C.so:
+ ${CXX} ${PICFLAG} -DPIC ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+
+.f.o:
+ ${FC} ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.f.po:
+ ${FC} -p ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.f.so:
+ ${FC} ${PICFLAG} -DPIC ${FFLAGS} -o ${.TARGET} -c ${.IMPSRC}
+
+.s.o:
+ ${CPP} -E ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+ @${LD} -x -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.s.po:
+ ${CPP} -E -DPROF ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.s.so:
+ ${CPP} -E -DPIC ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -k -o ${.TARGET}
+
+.S.o:
+ ${CPP} -E ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+
+.S.po:
+ ${CPP} -E -DPROF ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -o ${.TARGET}
+
+.S.so:
+ ${CPP} -E -DPIC ${CFLAGS:M-[ID]*} ${AINC} ${.IMPSRC} | \
+ ${AS} -k -o ${.TARGET}
+
+.m.po:
+ ${CC} ${CFLAGS} -p -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.m.o:
+ ${CC} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET}
+ @${LD} -X -r ${.TARGET}
+ @mv a.out ${.TARGET}
+
+.if defined(PROFILE)
+_LIBS=lib${LIB}.a lib${LIB}_p.a
+.else
+_LIBS=lib${LIB}.a
+.endif
+
+.if !defined(NOPIC)
+.if defined(SHLIB_MAJOR) && defined(SHLIB_MINOR)
+_LIBS+=lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}
+.endif
+.if defined(INSTALL_PIC_ARCHIVE)
+_LIBS+=lib${LIB}_pic.a
+.endif
+.endif
+
+.if !defined(PICFLAG)
+PICFLAG=-fpic
+.endif
+
+all: ${_LIBS} # llib-l${LIB}.ln
+
+OBJS+= ${SRCS:N*.h:R:S/$/.o/g}
+
+lib${LIB}.a:: ${OBJS}
+ @echo building standard ${LIB} library
+ @rm -f lib${LIB}.a
+ @${AR} cTq lib${LIB}.a `lorder ${OBJS} | tsort` ${LDADD}
+ ${RANLIB} lib${LIB}.a
+
+POBJS+= ${OBJS:.o=.po}
+lib${LIB}_p.a:: ${POBJS}
+ @echo building profiled ${LIB} library
+ @rm -f lib${LIB}_p.a
+ @${AR} cTq lib${LIB}_p.a `lorder ${POBJS} | tsort` ${LDADD}
+ ${RANLIB} lib${LIB}_p.a
+
+SOBJS+= ${OBJS:.o=.so}
+lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}: ${SOBJS}
+ @echo building shared ${LIB} library \(version ${SHLIB_MAJOR}.${SHLIB_MINOR}\)
+ @rm -f lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR}
+ @$(LD) -Bshareable \
+ -o lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} \
+ ${SOBJS} ${LDADD}
+
+lib${LIB}_pic.a:: ${SOBJS}
+ @echo building special pic ${LIB} library
+ @rm -f lib${LIB}_pic.a
+ @${AR} cTq lib${LIB}_pic.a ${SOBJS} ${LDADD}
+ ${RANLIB} lib${LIB}_pic.a
+
+llib-l${LIB}.ln: ${SRCS}
+ ${LINT} -C${LIB} ${CFLAGS} ${.ALLSRC:M*.c}
+
+.if !target(clean)
+clean:
+ rm -f a.out Errs errs mklog ${CLEANFILES} ${OBJS}
+ rm -f lib${LIB}.a llib-l${LIB}.ln
+ rm -f ${POBJS} profiled/*.o lib${LIB}_p.a
+ rm -f ${SOBJS} shared/*.o
+ rm -f lib${LIB}.so.*.* lib${LIB}_pic.a
+.endif
+
+.if !target(cleandir)
+cleandir:
+ rm -f a.out Errs errs mklog ${CLEANFILES} ${OBJS}
+ rm -f lib${LIB}.a llib-l${LIB}.ln
+ rm -f ${.CURDIR}/tags .depend
+ rm -f ${POBJS} profiled/*.o lib${LIB}_p.a
+ rm -f ${SOBJS} shared/*.o
+ rm -f lib${LIB}.so.*.* lib${LIB}_pic.a
+ cd ${.CURDIR}; rm -rf obj;
+.endif
+
+.if defined(SRCS)
+afterdepend:
+ @(TMP=/tmp/_depend$$$$; \
+ sed -e 's/^\([^\.]*\).o[ ]*:/\1.o \1.po \1.so:/' < .depend > $$TMP; \
+ mv $$TMP .depend)
+.endif
+
+.if !target(install)
+.if !target(beforeinstall)
+beforeinstall:
+.endif
+
+realinstall: beforeinstall
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} lib${LIB}.a \
+ ${DESTDIR}${LIBDIR}
+ ${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}.a
+.if defined(PROFILE)
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ lib${LIB}_p.a ${DESTDIR}${LIBDIR}
+ ${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}_p.a
+.endif
+.if !defined(NOPIC)
+.if defined(SHLIB_MAJOR) && defined(SHLIB_MINOR)
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ lib${LIB}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} ${DESTDIR}${LIBDIR}
+.endif
+.if defined(INSTALL_PIC_ARCHIVE)
+ install ${COPY} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ lib${LIB}_pic.a ${DESTDIR}${LIBDIR}
+ ${RANLIB} -t ${DESTDIR}${LIBDIR}/lib${LIB}_pic.a
+.endif
+.endif
+.if defined(LINKS) && !empty(LINKS)
+ @set ${LINKS}; \
+ while test $$# -ge 2; do \
+ l=${DESTDIR}$$1; \
+ shift; \
+ t=${DESTDIR}$$1; \
+ shift; \
+ echo $$t -\> $$l; \
+ rm -f $$t; \
+ ln $$l $$t; \
+ done; true
+.endif
+
+install: afterinstall
+.if !defined(NOMAN)
+afterinstall: realinstall maninstall
+.else
+afterinstall: realinstall
+.endif
+.endif
+
+.if !target(lint)
+lint:
+.endif
+
+.if !target(tags)
+tags: ${SRCS}
+ -cd ${.CURDIR}; ctags -f /dev/stdout ${.ALLSRC:M*.c} | \
+ sed "s;\${.CURDIR}/;;" > tags
+.endif
+
+.if !defined(NOMAN)
+.include <bsd.man.mk>
+.elif !target(maninstall)
+maninstall:
+.endif
+
+.if !target(obj)
+.if defined(NOOBJ)
+obj:
+.else
+obj:
+ @cd ${.CURDIR}; rm -rf obj; \
+ here=`pwd`; dest=/usr/obj`echo $$here | sed 's,^/usr/src,,'`; \
+ echo "$$here -> $$dest"; ln -s $$dest obj; \
+ if test -d /usr/obj -a ! -d $$dest; then \
+ mkdir -p $$dest; \
+ else \
+ true; \
+ fi;
+.endif
+.endif
+
+.include <bsd.dep.mk>
diff --git a/lib/libmalloc/defs.h b/lib/libmalloc/defs.h
new file mode 100644
index 000000000000..0f794f1cee71
--- /dev/null
+++ b/lib/libmalloc/defs.h
@@ -0,0 +1,386 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+/* $Id: defs.h,v 1.1 1994/03/06 22:59:29 nate Exp $ */
+#ifndef __DEFS_H__
+#define __DEFS_H__
+/*
+ * This file includes all relevant include files, and defines various
+ * types and constants. It also defines lots of macros which operate on
+ * the malloc blocks and pointers, to try and keep the ugliness
+ * abstracted away from the source code.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+extern int errno; /* Some errno.h don't declare this */
+
+/*
+ * ANSI defines malloc to return void *, and take size_t as an
+ * argument, while present Unix convention is char * and unsigned int
+ * respectively. This is not ifdef'ed with STDC because you may want to
+ * compile a Unix malloc with an ANSI C compiler or vice versa. Note
+ * that sys/types.h on BSD Unix systems defines size_t to be int or
+ * long. memsize_t is for routines that expect int in Unix and size_t
+ * in ANSI.
+ */
+#ifdef STDHEADERS
+# define univptr_t void *
+# define memsize_t size_t
+#else /* ! STDHEADERS */
+# define univptr_t char *
+# define size_t unsigned int
+# define memsize_t int
+#endif /* STDHEADERS */
+
+#ifndef REGISTER
+# ifdef __GNUC__
+ /* gcc probably does better register allocation than I do */
+# define REGISTER
+# else
+# define REGISTER register
+# endif
+#endif
+
+/*
+ * Just in case you want an ANSI malloc without an ANSI compiler, or
+ * ANSI includes
+ */
+#if defined(STDHEADERS) && !defined(offsetof) && !defined(__FreeBSD__)
+# define size_t unsigned long
+#endif
+
+#if defined(__STDC__)
+# define proto(x) x
+#else
+# define proto(x) ()
+# define const
+# define volatile
+#endif
+
+#include "externs.h"
+#include "assert.h"
+
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#ifdef __STDC__
+# include <limits.h>
+# ifndef BITSPERBYTE
+# define BITSPERBYTE CHAR_BIT
+# endif
+#else
+# include <values.h>
+#endif
+#include "align.h" /* Needs BITSPERBYTE */
+
+/*
+ * We assume that FREE is a 0 bit, and the for a free block,
+ * SIZE(p) == SIZEMASK(p) as an optimization to avoid an unnecessary
+ * masking operation with SIZEMASK. See FREESIZE below. Or'ing with
+ * ALLOCED should turn on the high bit, And'ing with SIZEMASK should
+ * turn it off.
+ */
+
+#define FREE ((size_t) 0)
+#define ALLOCED (HIBITSZ)
+#define SIZEMASK (~HIBITSZ)
+
+union word { /* basic unit of storage */
+ size_t size; /* size of this block + 1 bit status */
+ union word *next; /* next free block */
+ union word *prev; /* prev free block */
+ univptr_t ptr; /* stops lint complaining, keeps alignment */
+ char c;
+ int i;
+ char *cp;
+ char **cpp;
+ int *ip;
+ int **ipp;
+ ALIGN; /* alignment stuff - wild fun */
+};
+
+typedef union word Word;
+
+/*
+ * WARNING - Many of these macros are UNSAFE because they have multiple
+ * evaluations of the arguments. Use with care, avoid side-effects.
+ */
+/*
+ * These macros define operations on a pointer to a block. The zero'th
+ * word of a block is the size field, where the top bit is 1 if the
+ * block is allocated. This word is also referred to as the starting tag.
+ * The last word of the block is identical to the zero'th word of the
+ * block and is the end tag. IF the block is free, the second last word
+ * is a pointer to the next block in the free list (a doubly linked list
+ * of all free blocks in the heap), and the third from last word is a
+ * pointer to the previous block in the free list. HEADERWORDS is the
+ * number of words before the pointer in the block that malloc returns,
+ * TRAILERWORDS is the number of words after the returned block. Note
+ * that the zero'th and the last word MUST be the boundary tags - this
+ * is hard-wired into the algorithm. Increasing HEADERWORDS or
+ * TRAILERWORDS suitably should be accompanied by additional macros to
+ * operate on those words. The routines most likely to be affected are
+ * malloc/realloc/free/memalign/mal_verify/mal_heapdump.
+ */
+/*
+ * There are two ways we can refer to a block -- by pointing at the
+ * start tag, or by pointing at the end tag. For reasons of efficiency
+ * and performance, free blocks are always referred to by the end tag,
+ * while allocated blocks are usually referred to by the start tag.
+ * Accordingly, the following macros indicate the type of their argument
+ * by using either 'p', 'sp', or 'ep' to indicate a pointer. 'p' means
+ * the pointer could point at either the start or end tag. 'sp' means it
+ * must point at a start tag for that macro to work correctly, 'ep'
+ * means it must point at the end tag. Usually, macros operating on free
+ * blocks (NEXT, PREV, VALID_PREV_PTR, VALID_NEXT_PTR) take 'ep', while
+ * macros operating on allocated blocks (REALSIZE, MAGIC_PTR,
+ * SET_REALSIZE) take 'sp'. The size field may be validated using either
+ * VALID_START_SIZE_FIELD for an 'sp' or VALID_END_SIZE_FIELD for an
+ * 'ep'.
+ */
+/*
+ * SIZE, SIZEFIELD and TAG are valid for allocated and free blocks,
+ * REALSIZE is valid for allocated blocks when debugging, and NEXT and
+ * PREV are valid for free blocks. We could speed things up by making
+ * the free list singly linked when not debugging - the double link are
+ * just so we can check for pointer validity. (PREV(NEXT(ep)) == ep and
+ * NEXT(PREV(ep)) == ep). FREESIZE is used only to get the size field
+ * from FREE blocks - in this implementation, free blocks have a tag
+ * bit of 0 so no masking is necessary to operate on the SIZEFIELD when
+ * a block is free. We take advantage of that as a minor optimization.
+ */
+#define SIZEFIELD(p) ((p)->size)
+#define SIZE(p) ((size_t) (SIZEFIELD(p) & SIZEMASK))
+#define ALLOCMASK(n) ((n) | ALLOCED)
+#define FREESIZE(p) SIZEFIELD(p)
+/*
+ * FREEMASK should be (n) & SIZEMASK, but since (n) will always have
+ * the hi bit off after the conversion from bytes requested by the user
+ * to words.
+ */
+#define FREEMASK(n) (n)
+#define TAG(p) (SIZEFIELD(p) & ~SIZEMASK)
+
+#ifdef DEBUG
+# define REALSIZE(sp) (((sp)+1)->size)
+#endif /* DEBUG */
+
+#define NEXT(ep) (((ep)-1)->next)
+#define PREV(ep) (((ep)-2)->prev)
+
+/*
+ * HEADERWORDS is the real block header in an allocated block - the
+ * free block header uses extra words in the block itself
+ */
+#ifdef DEBUG
+# define HEADERWORDS 2 /* Start boundary tag + real size in bytes */
+#else /* ! DEBUG */
+# define HEADERWORDS 1 /* Start boundary tag */
+#endif /* DEBUG */
+
+#define TRAILERWORDS 1
+
+#define FREEHEADERWORDS 1 /* Start boundary tag */
+
+#define FREETRAILERWORDS 3 /* next and prev, end boundary tag */
+
+#define ALLOC_OVERHEAD (HEADERWORDS + TRAILERWORDS)
+#define FREE_OVERHEAD (FREEHEADERWORDS + FREETRAILERWORDS)
+
+/*
+ * The allocator views memory as a list of non-contiguous arenas. (If
+ * successive sbrks() return contiguous blocks, they are colaesced into
+ * one arena - if a program never calls sbrk() other than malloc(),
+ * then there should only be one arena. This malloc will however
+ * happily coexist with other allocators calling sbrk() and uses only
+ * the blocks given to it by sbrk. It expects the same courtesy from
+ * other allocators. The arenas are chained into a linked list using
+ * the first word of each block as a pointer to the next arena. The
+ * second word of the arena, and the last word, contain fake boundary
+ * tags that are permanantly marked allocated, so that no attempt is
+ * made to coalesce past them. See the code in dumpheap for more info.
+ */
+#define ARENASTART 2 /* next ptr + fake start tag */
+
+#ifdef DEBUG
+ /*
+ * 1 for prev link in free block - next link is absorbed by header
+ * REALSIZE word
+ */
+# define FIXEDOVERHEAD (1 + ALLOC_OVERHEAD)
+#else /* ! DEBUG */
+ /* 1 for prev link, 1 for next link, + header and trailer */
+# define FIXEDOVERHEAD (2 + ALLOC_OVERHEAD)
+#endif /* DEBUG */
+
+/*
+ * Check that pointer is safe to dereference i.e. actually points
+ * somewhere within the heap and is properly aligned.
+ */
+#define PTR_IN_HEAP(p) \
+ ((p) > _malloc_loword && (p) < _malloc_hiword && \
+ ALIGNPTR(p) == ((univptr_t) (p)))
+
+/* Check that the size field is valid */
+#define VALID_START_SIZE_FIELD(sp) \
+ (PTR_IN_HEAP((sp) + SIZE(sp) - 1) && \
+ SIZEFIELD(sp) == SIZEFIELD((sp) + SIZE(sp) - 1))
+
+#define VALID_END_SIZE_FIELD(ep) \
+ (PTR_IN_HEAP((ep) - SIZE(ep) + 1) && \
+ SIZEFIELD(ep) == SIZEFIELD((ep) - SIZE(ep) + 1))
+
+
+#define ulong unsigned long
+
+#ifdef DEBUG
+ /*
+ * Byte that is stored at the end of each block if the requested size
+ * of the block is not a multiple of sizeof(Word). (If it is a multiple
+ * of sizeof(Word), then we don't need to put the magic because the
+ * endboundary tag will be corrupted and the tests that check the
+ * validity of the boundary tag should detect it
+ */
+# ifndef u_char
+# define u_char unsigned char
+# endif /* u_char */
+
+# define MAGIC_BYTE ((u_char) '\252')
+ /*
+ * Check if size of the block is identical to requested size. Typical
+ * tests will be of the form DONT_NEED_MAGIC(p) || something for
+ * short-circuited protection, because blocks where DONT_NEED_MAGIC is
+ * true will be tested for boundary tag detection so we don't need the
+ * magic byte at the end.
+ */
+# define DONT_NEED_MAGIC(sp) \
+ (REALSIZE(sp) == ((SIZE(sp) - ALLOC_OVERHEAD) * sizeof(Word)))
+
+ /* Note that VALID_REALSIZE must not be used if DONT_NEED_MAGIC is true */
+# define VALID_REALSIZE(sp) \
+ (REALSIZE(sp) < ((SIZE(sp) - ALLOC_OVERHEAD)*sizeof(Word)))
+
+ /* Location of the magic byte */
+# define MAGIC_PTR(sp) ((u_char *)((sp) + HEADERWORDS) + REALSIZE(sp))
+
+ /*
+ * malloc code should only use the next two macros SET_REALSIZE and
+ * VALID_MAGIC, since they are the only ones which have non-DEBUG
+ * (null) alternatives
+ */
+
+ /* Macro sets the realsize of a block if necessary */
+# define SET_REALSIZE(sp, n) \
+ (REALSIZE(sp) = (n), \
+ DONT_NEED_MAGIC(sp) || (*MAGIC_PTR(sp) = MAGIC_BYTE))
+
+ /* Macro tests that the magic byte is valid if it exists */
+# define VALID_MAGIC(sp) \
+ (DONT_NEED_MAGIC(sp) || \
+ (VALID_REALSIZE(sp) && (*MAGIC_PTR(sp) == MAGIC_BYTE)))
+
+#else /* ! DEBUG */
+# define SET_REALSIZE(sp, n)
+# define VALID_MAGIC(sp) (1)
+#endif /* DEBUG */
+
+/*
+ * Check that a free list ptr points to a block with something pointing
+ * back. This is the only reason we use a doubly linked free list.
+ */
+#define VALID_NEXT_PTR(ep) (PTR_IN_HEAP(NEXT(ep)) && PREV(NEXT(ep)) == (ep))
+#define VALID_PREV_PTR(ep) (PTR_IN_HEAP(PREV(ep)) && NEXT(PREV(ep)) == (ep))
+
+/*
+ * quick bit-arithmetic to check a number (including 1) is a power of two.
+ */
+#define is_power_of_2(x) ((((x) - 1) & (x)) == 0)
+
+/*
+ * An array to try and keep track of the distribution of sizes of
+ * malloc'ed blocks
+ */
+#ifdef PROFILESIZES
+# define MAXPROFILESIZE 2*1024
+# define COUNTSIZE(nw) (_malloc_scount[((nw) < MAXPROFILESIZE) ? (nw) : 0]++)
+#else
+# define COUNTSIZE(nw)
+#endif
+
+#define DEF_SBRKUNITS 1024
+
+#ifndef USESTDIO
+ /*
+ * Much better not to use stdio - stdio calls malloc() and can
+ * therefore cause problems when debugging heap corruption. However,
+ * there's no guaranteed way to turn off buffering on a FILE pointer in
+ * ANSI. This is a vile kludge!
+ */
+# define fputs(s, f) write(fileno(f), (s), strlen(s))
+# define setvbuf(f, s, n, l) __nothing()
+# define fflush(f) __nothing()
+#endif /* USESTDIO */
+
+#ifdef TRACE
+ /*
+ * Prints a trace string. For convenience, x is an
+ * sprintf(_malloc_statsbuf, ...) or strcpy(_malloc_statsbuf, ...);
+ * something which puts the appropriate text to be printed in
+ * _malloc_statsbuf - ugly, but more convenient than making x a string.
+ */
+# define PRTRACE(x) \
+ if (_malloc_tracing) { \
+ (void) x; \
+ (void) fputs(_malloc_statsbuf, _malloc_statsfile); \
+ } else \
+ _malloc_tracing += 0
+#else
+# define PRTRACE(x)
+#endif
+
+#ifdef DEBUG
+# define CHECKHEAP() \
+ if (_malloc_debugging >= 2) \
+ (void) mal_verify(_malloc_debugging >= 3); \
+ else \
+ _malloc_debugging += 0
+#else
+# define CHECKHEAP()
+#endif
+
+#define FREEMAGIC '\125'
+
+/*
+ * Memory functions but in words. We just call memset/memcpy, and hope
+ * that someone has optimized them. If you are on pure 4.2BSD, either
+ * redefine these in terms of bcopy/your own memcpy, or
+ * get the functions from one of 4.3src/Henry Spencer's strings
+ * package/C News src
+ */
+#define MEMSET(p, c, n) \
+ (void) memset((univptr_t) (p), (c), (memsize_t) ((n) * sizeof(Word)))
+#define MEMCPY(p1, p2, n) \
+ (void) memcpy((univptr_t) (p1), (univptr_t) (p2), \
+ (memsize_t) ((n) * sizeof(Word)))
+
+
+#ifdef DEBUG
+# define DMEMSET(p, n) MEMSET((p), FREEMAGIC, (n))
+#else
+# define DMEMSET(p, n)
+#endif
+
+/*
+ * Thanks to Hugh Redelmeier for pointing out that an rcsid is "a
+ * variable accessed in a way not obvious to the compiler", so should
+ * be called volatile. Amazing - a use for const volatile...
+ */
+#ifndef RCSID /* define RCSID(x) to nothing if don't want the rcs headers */
+# ifndef lint
+# define RCSID(x) static const volatile char *rcsid = x ;
+# else
+# define RCSID(x)
+# endif
+#endif
+
+#endif /* __DEFS_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/dumpheap.c b/lib/libmalloc/dumpheap.c
new file mode 100644
index 000000000000..e75ba8e8f279
--- /dev/null
+++ b/lib/libmalloc/dumpheap.c
@@ -0,0 +1,107 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: dumpheap.c,v 1.1 1994/03/06 22:59:30 nate Exp $")
+
+/*
+ * Same as malloc_verify except that it prints the heap as it goes
+ * along. Some would argue that the printout routine should not have
+ * the ASSERTS, and should print a corrupt heap as well.
+ * Unfortunately, if any of those ASSERTs is false, this routine could
+ * wander off into the sunset because of corrupt tags. I have relaxed
+ * the tests for free list pointers because this routine doesn't need
+ * them so it just whines
+ */
+void
+mal_heapdump(fd)
+FILE *fd;
+{
+ REGISTER Word *ptr;
+ REGISTER Word *blk;
+ REGISTER Word *blkend;
+ char buf[512]; /* long enough for the sprintfs below */
+
+ if (_malloc_loword == NULL) { /* Nothing malloc'ed yet */
+ (void) fputs("Null heap - nothing malloc'ed yet\n", fd);
+ return;
+ }
+
+ (void) fputs("Heap printout:\n", fd);
+ (void) sprintf(buf, "Rover pointer is 0x%lx\n", (ulong) _malloc_rover);
+ (void) fputs(buf, fd);
+ if(!(_malloc_rover == NULL
+ || PTR_IN_HEAP(_malloc_rover)
+ || VALID_END_SIZE_FIELD(_malloc_rover)
+ || VALID_NEXT_PTR(_malloc_rover)
+ || VALID_PREV_PTR(_malloc_rover)))
+ (void) fputs("corrupt Rover pointer\n", fd);
+ for(ptr = _malloc_mem; ptr != NULL; ptr = ptr->next) {
+ /* print the arena */
+ (void) sprintf(buf, "Arena from 0x%lx to 0x%lx, %lu (0x%lx) words\n",
+ (ulong) ptr, (ulong) (ptr + SIZE(ptr+1)),
+ (ulong) SIZE(ptr+1)+1, (ulong) SIZE(ptr+1)+1);
+ (void) fputs(buf, fd);
+ (void) sprintf(buf, "Next arena is 0x%lx\n", (ulong)ptr->next);
+ (void) fputs(buf, fd);
+ (void) fflush(fd);
+ ASSERT(SIZEFIELD(ptr+1) == SIZEFIELD(ptr + SIZE(ptr+1)),
+ "corrupt malloc arena");
+ blkend = ptr + SIZE(ptr + 1);
+ for(blk = ptr + ARENASTART; blk < blkend; blk += SIZE(blk)) {
+ (void) sprintf(buf, " %s blk: 0x%lx to 0x%lx, %lu (0x%lx) words",
+ TAG(blk) == FREE ? "Free" : "Allocated",
+ (ulong) blk, (ulong) (blk+SIZE(blk)-1),
+ (ulong) SIZE(blk), (ulong) SIZE(blk));
+ (void) fputs(buf, fd);
+ (void) fflush(fd);
+ ASSERT(PTR_IN_HEAP(blk), "corrupt pointer encountered");
+ if (TAG(blk) == FREE) {
+ int i, n;
+ char *cp;
+
+ (void) sprintf(buf, " next=0x%lx, prev=0x%lx\n",
+ (ulong) NEXT(blk + FREESIZE(blk) - 1),
+ (ulong) PREV(blk + FREESIZE(blk) - 1));
+ (void) fputs(buf, fd);
+ /* Make sure free block is filled with FREEMAGIC */
+ n = (SIZE(blk) - FREE_OVERHEAD) *
+ sizeof(Word);
+ cp = (char *) (blk + FREEHEADERWORDS);
+#ifdef DEBUG
+ for (i = 0; i < n; i++, cp++) {
+ if (*cp != FREEMAGIC) {
+ (void) fputs(
+ " ** free block changed after being freed.\n", fd);
+ break;
+ }
+ }
+#endif
+ } else {
+#ifdef DEBUG
+ (void) sprintf(buf, " really %lu bytes\n", (ulong) REALSIZE(blk));
+ (void) fputs(buf, fd);
+#else
+ (void) fputs("\n", fd);
+#endif
+ }
+ (void) fflush(fd);
+ ASSERT(VALID_START_SIZE_FIELD(blk),
+ "corrupt SIZE field encountered in mal_dumpheap()");
+ if (TAG(blk) == FREE) {
+ if( ! VALID_NEXT_PTR(blk + FREESIZE(blk) - 1))
+ (void) fputs(" ** bad next pointer\n", fd);
+ if( ! VALID_PREV_PTR(blk + FREESIZE(blk) - 1))
+ (void) fputs(" ** bad prev pointer\n", fd);
+ } else {
+ if ( ! VALID_MAGIC(blk))
+ (void) fputs(" ** end of block overwritten\n", fd);
+ }
+ }
+ }
+ (void) fputs("==============\n", fd);
+ (void) fflush(fd);
+}
diff --git a/lib/libmalloc/emalloc.c b/lib/libmalloc/emalloc.c
new file mode 100644
index 000000000000..13a7b9ab0244
--- /dev/null
+++ b/lib/libmalloc/emalloc.c
@@ -0,0 +1,69 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: emalloc.c,v 1.1 1994/03/06 22:59:31 nate Exp $")
+
+/*
+ * malloc which dies if it can't allocate enough storage.
+ */
+univptr_t
+emalloc(nbytes)
+size_t nbytes;
+{
+ univptr_t cp = malloc(nbytes);
+
+ if (cp == 0) {
+ (void) fputs("No more memory for emalloc\n", stderr);
+#ifdef DEBUG
+ (void) fflush(stderr);
+ (void) fflush(_malloc_statsfile);
+ abort();
+#else
+ exit(EXIT_FAILURE);
+#endif
+ }
+
+ return(cp);
+}
+
+/*
+ * realloc which dies if it can't allocate enough storage.
+ */
+univptr_t
+erealloc(ptr, nbytes)
+univptr_t ptr;
+size_t nbytes;
+{
+ univptr_t cp = realloc(ptr, nbytes);
+
+ if (cp == 0) {
+ (void) fputs("No more memory for erealloc\n", stderr);
+#ifdef DEBUG
+ (void) fflush(stderr);
+ (void) fflush(_malloc_statsfile);
+ abort();
+#else
+ exit(EXIT_FAILURE);
+#endif
+ }
+
+ return(cp);
+}
+
+/*
+ * calloc which dies if it can't allocate enough storage.
+ */
+univptr_t
+ecalloc(nelem, sz)
+size_t nelem, sz;
+{
+ size_t nbytes = nelem * sz;
+ univptr_t cp = emalloc(nbytes);
+
+ (void) memset((univptr_t) cp, 0, (memsize_t) nbytes);
+ return(cp);
+}
diff --git a/lib/libmalloc/externs.h b/lib/libmalloc/externs.h
new file mode 100644
index 000000000000..77c0b19e014c
--- /dev/null
+++ b/lib/libmalloc/externs.h
@@ -0,0 +1,113 @@
+#ifndef EXTERNS_H__
+#define EXTERNS_H__
+
+/* Lots of ugliness as we cope with non-standardness */
+
+#ifdef STDHEADERS
+ /* if we have properly prototyped standard headers, use them */
+# include <stdlib.h>
+# include <stddef.h>
+# include <stdio.h>
+# include <string.h>
+# include <unistd.h>
+
+#else /* ! STDHEADERS */
+
+/* # include <sys/types.h> */
+#define caddr_t char *
+
+/*
+ * Malloc definitions from General Utilities <stdlib.h>. Note that we
+ * disagree with Berkeley Unix on the return type of free/cfree.
+ */
+extern univptr_t malloc proto((size_t));
+extern univptr_t calloc proto((size_t, size_t));
+extern univptr_t realloc proto((univptr_t, size_t));
+extern void free proto((univptr_t));
+
+/* General Utilities <stdlib.h> */
+
+extern void abort proto((void));
+extern void exit proto((int));
+extern char *getenv proto((const char *));
+
+/*
+ * Input/Output <stdio.h> Note we disagree with Berkeley Unix on
+ * sprintf().
+ */
+
+#if 0 /* can't win with this one */
+extern int sprintf proto((char *, const char *, ...));
+#endif
+
+extern int fputs proto((const char *, FILE *));
+extern int fflush proto((FILE *));
+extern int setvbuf proto((FILE *, char *, int, memsize_t));
+
+/* Character Handling: <string.h> */
+
+extern univptr_t memset proto((univptr_t, int, memsize_t));
+
+#ifndef __GNUC__ /* clash with builtin, garn */
+extern univptr_t memcpy proto((univptr_t, const univptr_t, memsize_t));
+#endif
+
+extern char *strcpy proto((char *, const char *));
+extern memsize_t strlen proto((const char *));
+
+/* UNIX -- unistd.h */
+extern int write proto((int /*fd*/, const char * /*buf*/, int /*nbytes*/));
+extern int open proto((const char */*path*/, int /*flags*/, ...));
+
+#endif /* STDHEADERS */
+
+#ifdef _SC_PAGESIZE /* Solaris 2.x, SVR4? */
+# define getpagesize() sysconf(_SC_PAGESIZE)
+#else /* ! _SC_PAGESIZE */
+# ifdef _SC_PAGE_SIZE /* HP, IBM */
+# define getpagesize() sysconf(_SC_PAGE_SIZE)
+# else /* ! _SC_PAGE_SIZE */
+# ifndef getpagesize
+ extern int getpagesize proto((void));
+# endif /* getpagesize */
+# endif /* _SC_PAGE_SIZE */
+#endif /* _SC_PAGESIZE */
+
+extern caddr_t sbrk proto((int));
+
+/* Backwards compatibility with BSD/Sun -- these are going to vanish one day */
+extern univptr_t valloc proto((size_t));
+extern univptr_t memalign proto((size_t, size_t));
+extern void cfree proto((univptr_t));
+
+/* Malloc definitions - my additions. Yuk, should use malloc.h properly!! */
+extern univptr_t emalloc proto((size_t));
+extern univptr_t ecalloc proto((size_t, size_t));
+extern univptr_t erealloc proto((univptr_t, size_t));
+extern char *strdup proto((const char *));
+extern char *strsave proto((const char *));
+extern void mal_debug proto((int));
+extern void mal_dumpleaktrace proto((FILE *));
+extern void mal_heapdump proto((FILE *));
+extern void mal_leaktrace proto((int));
+extern void mal_mmap proto((char *));
+extern void mal_sbrkset proto((int));
+extern void mal_slopset proto((int));
+extern void mal_statsdump proto((FILE *));
+extern void mal_setstatsfile proto((FILE *));
+extern void mal_trace proto((int));
+extern int mal_verify proto((int));
+
+/* Internal definitions */
+extern int __nothing proto((void));
+extern univptr_t _mal_sbrk proto((size_t));
+extern univptr_t _mal_mmap proto((size_t));
+
+#ifdef HAVE_MMAP
+extern int madvise proto((caddr_t, size_t, int));
+#ifndef __FreeBSD__
+extern caddr_t mmap proto((caddr_t, size_t, int, int, int, off_t));
+#endif /* __FreeBSD__ */
+#endif /* HAVE_MMAP */
+
+#endif /* EXTERNS_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/getmem.c b/lib/libmalloc/getmem.c
new file mode 100644
index 000000000000..4140c6da4cc3
--- /dev/null
+++ b/lib/libmalloc/getmem.c
@@ -0,0 +1,108 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: getmem.c,v 1.1 1994/03/06 22:59:42 nate Exp $")
+
+/* gets memory from the system via the sbrk() system call. Most Un*xes */
+univptr_t
+_mal_sbrk(nbytes)
+size_t nbytes;
+{
+ return sbrk((int) nbytes);
+}
+
+/*
+ * gets memory from the system via mmaping a file. This was written for SunOS
+ * versions greater than 4.0. The filename is specified by the environment
+ * variable CSRIMALLOC_MMAPFILE or by the call to mal_mmapset(). Using this
+ * instead of sbrk() has the advantage of bypassing the swap system, allowing
+ * processes to run with huge heaps even on systems configured with small swap
+ * space.
+ */
+static char *mmap_filename;
+
+#ifdef HAVE_MMAP
+/* Sun gets size_t wrong, and these follow, thanks to my #defines! */
+#undef caddr_t
+#undef size_t
+#undef u_char
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+univptr_t
+_mal_mmap(nbytes)
+size_t nbytes;
+{
+ static struct {
+ int i_fd;
+ caddr_t i_data;
+ caddr_t i_end;
+ size_t i_size;
+ size_t i_alloced;
+ } mmf;
+ struct stat stbuf;
+
+ if (mmf.i_data != NULL) {
+ /* Already initialized & mmaped the file */
+ univptr_t p = mmf.i_data + mmf.i_alloced;
+
+ if ((char *) p + nbytes > mmf.i_end) {
+ errno = ENOMEM;
+ return (univptr_t) -1;
+ }
+ mmf.i_alloced += nbytes;
+ return p;
+ }
+
+ /*
+ * This code is run the first time the function is called, it opens
+ * the file and mmaps the
+ */
+ if (mmap_filename == NULL) {
+ mmap_filename = getenv("CSRIMALLOC_MMAPFILE");
+ if (mmap_filename == NULL) {
+ errno = ENOMEM;
+ return (univptr_t) -1;
+ }
+ }
+
+ mmf.i_fd = open(mmap_filename, O_RDWR, 0666);
+ if (mmf.i_fd < 0 || fstat(mmf.i_fd, &stbuf) < 0)
+ return (univptr_t) -1;
+ if (stbuf.st_size < nbytes) {
+ errno = ENOMEM;
+ return (univptr_t) -1;
+ }
+ mmf.i_size = stbuf.st_size;
+ mmf.i_data = mmap((caddr_t) 0, mmf.i_size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, mmf.i_fd, (off_t) 0);
+ if (mmf.i_data == (caddr_t) -1)
+ return (univptr_t) -1;
+ mmf.i_end = mmf.i_data + mmf.i_size;
+ mmf.i_alloced = nbytes;
+ /* Advise vm system of random access pattern */
+ (void) madvise(mmf.i_data, mmf.i_size, MADV_RANDOM);
+ return mmf.i_data;
+}
+#else /* !HAVE_MMAP */
+univptr_t
+_mal_mmap(nbytes)
+size_t nbytes;
+{
+ return (univptr_t) -1;
+}
+#endif /* HAVE_MMAP */
+
+void
+mal_mmap(fname)
+char *fname;
+{
+ _malloc_memfunc = _mal_mmap;
+ mmap_filename = fname;
+}
diff --git a/lib/libmalloc/globals.c b/lib/libmalloc/globals.c
new file mode 100644
index 000000000000..b1adf3d3f5a2
--- /dev/null
+++ b/lib/libmalloc/globals.c
@@ -0,0 +1,87 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*
+ * All globals are names starting with _malloc, which should not clash
+ * with anything else.
+ */
+/*
+ * Remember to initialize the variable in globals.c if you want, and
+ * provide an alternative short name in globrename.h
+ */
+#include "globrename.h"
+#include "version.c"
+
+/*
+ * _malloc_minchunk is the minimum number of units that a block can be
+ * cut down to. If the difference between the required block size, and
+ * the first available block is greater than _malloc_minchunk, the
+ * block is chopped into two pieces, else the whole block is returned.
+ * The larger this is, the less fragmentation there will be, but the
+ * greater the waste. The actual minimum size of a block is therefore
+ * _malloc_minchunk*sizeof(Word) This consists of one word each for the
+ * boundary tags, one for the next and one for the prev pointers in a
+ * free block.
+ */
+size_t _malloc_minchunk = FIXEDOVERHEAD;
+
+/*
+ * _malloc_rover is the pointer that points 'someplace' in the free
+ * list. We start our search for a block from _malloc_rover, thus
+ * starting the search at a different place everytime, rather than at
+ * the start of the list. This improves performance considerably, sez
+ * Knuth
+ */
+Word *_malloc_rover = NULL;
+Word *_malloc_hiword = NULL;
+Word *_malloc_loword = NULL;
+
+/*
+ * _malloc_sbrkunits is the multiple of sizeof(Word) to actually use in
+ * sbrk() calls - _malloc_sbrkunits should be large enough that sbrk
+ * isn't called too often, but small enough that any program that
+ * mallocs a few bytes doesn't end up being very large. I've set it to
+ * 1K resulting in a sbrk'ed size of 8K. This is (coincidentally!) the
+ * pagesize on Suns. I think that this seems a reasonable number for
+ * modern programs that malloc heavily. For small programs, you may
+ * want to set it to a lower number.
+ */
+size_t _malloc_sbrkunits = DEF_SBRKUNITS;
+
+/*
+ * optimization of keeping total amount available, so we know to sbrk
+ * without searching list. No point searching list unless we have a
+ * fair chance of success. Ideally, we'd keep the size of the largest
+ * block available and a pointer to it, so we could check definitely if
+ * we had enough space. But that is too much housekeeping - we'd have to
+ * update that on all mallocs and frees too. (Updating
+ * _malloc_totalavail is easier)
+ */
+size_t _malloc_totalavail = 0;
+
+Word *_malloc_mem = NULL;
+
+/*
+ * Do not call any output routine other than fputs() - use sprintf() if
+ * you want to format something before printing. We don't want stdio
+ * calling malloc() if we can help it
+ */
+int _malloc_tracing = 0; /* No tracing */
+FILE *_malloc_statsfile = stderr;
+char _malloc_statsbuf[128];
+
+int _malloc_leaktrace = 0;
+
+#ifdef PROFILESIZES
+int _malloc_scount[MAXPROFILESIZE];
+#endif /* PROFILESIZES */
+
+#ifdef DEBUG
+/*
+ * 0 or 1 means checking all pointers before using them. Reasonably
+ * thorough. 2 means check the entire heap on every call to
+ * malloc/free/realloc/memalign. (the rest call these)
+ */
+int _malloc_debugging = 0;
+#endif /* DEBUG */
+
+univptr_t (* _malloc_memfunc) proto((size_t)) = _mal_sbrk;
diff --git a/lib/libmalloc/globals.h b/lib/libmalloc/globals.h
new file mode 100644
index 000000000000..4d3327edd81f
--- /dev/null
+++ b/lib/libmalloc/globals.h
@@ -0,0 +1,43 @@
+/* $Id: globals.h,v 1.1 1994/03/06 22:59:44 nate Exp $ */
+#ifndef __GLOBALS_H__
+#define __GLOBALS_H__
+/*
+ * Remember to initialize the variable in globals.c if you want, and
+ * provide an alternative short name in globrename.h
+ */
+#include "globrename.h"
+
+extern size_t _malloc_minchunk;
+
+extern Word *_malloc_rover;
+extern Word *_malloc_hiword;
+extern Word *_malloc_loword;
+
+extern size_t _malloc_sbrkunits;
+
+extern size_t _malloc_totalavail;
+
+extern Word *_malloc_mem;
+
+extern int _malloc_tracing; /* No tracing */
+extern FILE *_malloc_statsfile;
+extern char _malloc_statsbuf[];
+
+extern int _malloc_leaktrace;
+
+#ifdef PROFILESIZES
+extern int _malloc_scount[];
+#endif /* PROFILESIZES */
+
+#ifdef DEBUG
+/*
+ * 0 or 1 means checking all pointers before using them. Reasonably
+ * thorough. 2 means check the entire heap on every call to
+ * malloc/free/realloc/memalign. (the rest call these)
+ */
+extern int _malloc_debugging;
+#endif /* DEBUG */
+
+extern univptr_t (* _malloc_memfunc) proto((size_t));
+
+#endif /* __GLOBALS_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/globrename.h b/lib/libmalloc/globrename.h
new file mode 100644
index 000000000000..9739f4f3ac6a
--- /dev/null
+++ b/lib/libmalloc/globrename.h
@@ -0,0 +1,46 @@
+/* $Id: globrename.h,v 1.1 1994/03/06 22:59:45 nate Exp $ */
+#ifndef __GLOBALRENAME_H__
+#define __GLOBALRENAME_H__
+/*
+ * Renaming all external symbols that are internal to the malloc to be
+ * unique within 6 characters for machines whose linkers just can't keep
+ * up. We hope the cpp is smart enough - if not, get GNU cccp or the
+ * cpp that comes with X Windows Version 11 Release 3.
+ */
+#ifdef SHORTNAMES
+#define _malloc_minchunk __MAL1_minchunk
+
+#define _malloc_rover __MAL2_rover
+#define _malloc_hiword __MAL3_hiword
+#define _malloc_loword __MAL4_loword
+
+#define _malloc_sbrkunits __MAL5_sbrkunits
+
+#define _malloc_totalavail __MAL6_totalavail
+
+#define _malloc_mem __MAL7_mem
+
+#define _malloc_tracing __MAL8_tracing
+#define _malloc_statsfile __MAL9_statsfile
+#define _malloc_statsbuf __MALA_statsbuf
+
+#define _malloc_leaktrace __MALB_leaktrace
+
+#ifdef PROFILESIZES
+#define _malloc_scount __MALC_scount
+#endif /* PROFILESIZES */
+
+#ifdef DEBUG
+/*
+ * 0 or 1 means checking all pointers before using them. Reasonably
+ * thorough. 2 means check the entire heap on every call to
+ * malloc/free/realloc/memalign. (the rest call these)
+ */
+#define _malloc_debugging __MALD_debugging
+#endif /* DEBUG */
+#define _malloc_version __MALE_version
+
+#define _malloc_memfunc __MALF_memfunc
+
+#endif /* SHORTNAMES */ /* Do not add anything after this line */
+#endif /* __GLOBALRENAME_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/leak.c b/lib/libmalloc/leak.c
new file mode 100644
index 000000000000..b4014582b32e
--- /dev/null
+++ b/lib/libmalloc/leak.c
@@ -0,0 +1,160 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+#include "sptree.h"
+
+RCSID("$Id: leak.c,v 1.1 1994/03/06 22:59:46 nate Exp $")
+
+/*
+ * These routines provide an interface for tracing memory leaks. The
+ * user can turn on leak tracing at any time by calling
+ * mal_leaktrace(1), after which every block allocated by
+ * _malloc()/_calloc()/_realloc()/_valloc()/_memalign() has a string
+ * (containing the filename and linenumber of the routine invoking it)
+ * stored in a database. When _free()/_cfree() is called on that block,
+ * the record is deleted from the database. The user can call
+ * mal_dumpleaktrace() to show the list of blocks allocated, and
+ * where they were allocated. The location of leaks can usually be
+ * detected from this.
+ */
+/*
+ * The tree implementation used to store the blocks is a splay-tree,
+ * using an implementation in C by Dave Brower (daveb@rtech.uucp),
+ * translated from Douglas Jones' original Pascal. However, any data
+ * structure that permits insert(), delete() and traverse()/apply() of
+ * key, value pairs should be suitable. Only this file needs to be
+ * changed.
+ */
+static SPTREE *sp = NULL;
+
+/*
+ * num is a sequence number, incremented for ever block. min_num gets
+ * set to num after every dumpleaktrace - subsequent dumps do not print
+ * any blocks with sequence numbers less than min_num
+ */
+static unsigned long min_num = 0;
+static unsigned long num = 0;
+
+/*
+ * These are used by mal_contents to count number of allocated blocks and the
+ * number of bytes allocated. Better way to do this is to walk the heap
+ * rather than scan the splay tree.
+ */
+static unsigned long nmallocs;
+static unsigned long nbytes;
+
+static FILE *dumpfd = NULL;
+
+/*
+ * Turns recording of FILE and LINE number of each call to
+ * malloc/free/realloc/calloc/cfree/memalign/valloc on (if value != 0)
+ * or off, (if value == 0)
+ */
+void
+mal_leaktrace(value)
+int value;
+{
+ _malloc_leaktrace = (value != 0);
+ if (sp == NULL)
+ sp = __spinit();
+}
+
+/*
+ * The routine which actually does the printing. I know it is silly to
+ * print address in decimal, but sort doesn't read hex, so sorting the
+ * printed data by address is impossible otherwise. Urr. The format is
+ * FILE:LINE: sequence_number address_in_decimal (address_in_hex)
+ */
+void
+__m_prnode(spblk)
+SPBLK *spblk;
+{
+ if ((unsigned long) spblk->datb < min_num)
+ return;
+ (void) sprintf(_malloc_statsbuf, "%s%8lu %8lu(0x%08lx)\n",
+ (char *) spblk->data, (unsigned long) spblk->datb,
+ (unsigned long) spblk->key, (unsigned long) spblk->key);
+ (void) fputs(_malloc_statsbuf, dumpfd);
+}
+
+/*
+ * Dumps all blocks which have been recorded.
+ */
+void
+mal_dumpleaktrace(fd)
+FILE *fd;
+{
+ dumpfd = fd;
+ __spscan(__m_prnode, (SPBLK *) NULL, sp);
+ (void) fflush(dumpfd);
+ min_num = num;
+}
+
+/*
+ * Inserts a copy of a string keyed by the address addr into the tree
+ * that stores the leak trace information. The string is presumably of
+ * the form "file:linenumber:". It also stores a sequence number that
+ * gets incremented with each call to this routine.
+ */
+void
+__m_install_record(addr, s)
+univptr_t addr;
+const char *s;
+{
+ num++;
+ (void) __spadd(addr, strsave(s), (char *) num, sp);
+}
+
+/* Deletes the record keyed by addr if it exists */
+void
+__m_delete_record(addr)
+univptr_t addr;
+{
+ SPBLK *result;
+
+ if ((result = __splookup(addr, sp)) != NULL) {
+ free(result->data);
+ result->data = 0;
+ __spdelete(result, sp);
+ }
+}
+
+void
+__m_count(spblk)
+SPBLK *spblk;
+{
+ Word *p;
+
+ nmallocs++;
+ p = (Word *) spblk->key;
+ p -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p), "bad pointer seen in __m_count");
+ ASSERT(TAG(p) != FREE, "freed block seen in __m_count");
+ ASSERT(VALID_START_SIZE_FIELD(p), "corrupt block seen in __m_count");
+ ASSERT(VALID_MAGIC(p), "block with end overwritten seen in __m_count");
+
+ nbytes += SIZE(p) * sizeof(Word);
+ return;
+}
+
+void
+mal_contents(fp)
+FILE *fp;
+{
+ void __m_count proto((SPBLK *));
+
+ nmallocs = 0;
+ nbytes = 0;
+ __spscan(__m_count, (SPBLK *) NULL, sp);
+ (void) sprintf(_malloc_statsbuf,
+ "%% %lu bytes %lu mallocs %lu available %lu vm\n",
+ nbytes, nmallocs, (ulong) _malloc_totalavail,
+ (ulong) sbrk(0));
+ (void) fputs(_malloc_statsbuf, fp);
+ (void) fflush(fp);
+}
diff --git a/lib/libmalloc/malloc.c b/lib/libmalloc/malloc.c
new file mode 100644
index 000000000000..354520ac3da4
--- /dev/null
+++ b/lib/libmalloc/malloc.c
@@ -0,0 +1,622 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.c"
+
+RCSID("$Id: malloc.c,v 1.1 1994/03/06 22:59:47 nate Exp $")
+
+static int
+grabhunk(nwords)
+size_t nwords;
+{
+ univptr_t cp;
+ size_t morecore;
+ Word *ptr;
+ size_t sbrkwords;
+ size_t blksize;
+ static char *spare;
+ static int nspare;
+
+ /*
+ * two words for fake boundary tags for the entire block, and one
+ * for the next ptr of the block.
+ */
+#define EXCESS 3
+ sbrkwords = (size_t) (((nwords + EXCESS) / _malloc_sbrkunits + 1) *
+ _malloc_sbrkunits);
+ morecore = sbrkwords * sizeof(Word) + SBRKEXTRA;
+ if ((cp = (* _malloc_memfunc)(morecore)) == (univptr_t) -1)
+ return(0);
+ /*
+ * Should first GUARANTEE that what sbrk returns is aligned to
+ * Word boundaries - see align.h. Unfortunately, to guarantee
+ * that the pointer returned by sbrk is aligned on a word
+ * boundary, we must ask for sizeof(Word) -1 extra bytes, since
+ * we have no guarantee what other sbrk'ed blocks exist. (Sun
+ * sbrk always returns an aligned value, that is another story!)
+ * We use spare and nspare to keep track of the bytes wasted, so
+ * that we can try and reuse them later. If no other sbrk()s are
+ * called, then nspare rotates through the values 3, 2, 1, 0,
+ * and the first branch of the if() is always taken.
+ */
+ if ((spare + nspare) == (char *) cp) {
+ ptr = (Word *) SBRKALIGN(spare);
+ morecore += nspare;
+ sbrkwords = morecore / sizeof(Word);
+ } else {
+ ptr = (Word *) SBRKALIGN(cp);
+ morecore -= (char *) ptr - (char *) cp;
+ }
+ spare = (char *) (ptr + sbrkwords);
+ nspare = (morecore - sbrkwords * sizeof(Word));
+ _malloc_totalavail += sbrkwords;
+ PRTRACE(sprintf(_malloc_statsbuf, "sbrk %lu\n",
+ (ulong) sbrkwords*sizeof(Word)));
+
+ /*
+ * Here we need to check if it adjoins the _malloc_hiword. If it
+ * does, then _malloc_hiword need not be a fake boundary tag any
+ * longer, (its a real one) and the higher end of the block we
+ * sbrk'ed is the fake tag. So we tag it appropriately, make
+ * the start of the block point to the old _malloc_hiword, and free it.
+ * If we aren't next to _malloc_hiword, then someone else sbrk'ed in
+ * between, so we can't coalesce over the boundary anyway, in
+ * which case we just change _malloc_hiword to be in the new sbrk'ed
+ * block without damaging the old one. And we free the block.
+ */
+ if (ptr != _malloc_hiword + 1 || _malloc_rover == NULL) {
+ /* Non-contiguous sbrk'ed block, or first sbrk we've done. */
+ /*
+ * First push this block on the stack of non-contiguous blocks
+ * we've sbrked. !! For real paranoia, we'd also check
+ * _malloc_mem...
+ */
+ REGISTER Word *tmp = _malloc_mem;
+
+ _malloc_mem = ptr;
+ ptr->next = tmp;
+ ptr++;
+ sbrkwords--;
+
+ _malloc_hiword = ptr;
+ if (_malloc_loword == NULL || _malloc_loword > ptr) {
+ /* First time - set lower bound. */
+ PRTRACE(sprintf(_malloc_statsbuf, "heapstart 0x%lx\n",
+ (ulong) ptr));
+ _malloc_loword = ptr;
+ }
+ /*
+ * Fake boundary tags to indicate the ends of an arena. Since they
+ * are marked as allocated, no attempt will be made to coalesce
+ * before or after them.
+ */
+ SIZEFIELD(ptr) = ALLOCED | sbrkwords;
+ _malloc_hiword += sbrkwords - 1;
+ PRTRACE(sprintf(_malloc_statsbuf, "heapend 0x%lx\n",
+ (ulong) _malloc_hiword));
+ SIZEFIELD(_malloc_hiword) = ALLOCED | sbrkwords;
+
+ ptr++;
+ /*
+ * The 2 we subtract are the special arena end tags, which is
+ * why we don't use HEADERWORDS and TRAILERWORDS
+ */
+ sbrkwords -= 2;
+ SIZEFIELD(ptr) = FREEMASK(sbrkwords);
+ DMEMSET(ptr + FREEHEADERWORDS, sbrkwords - FREE_OVERHEAD);
+ ptr = _malloc_hiword - 1;
+ SIZEFIELD(ptr) = FREEMASK(sbrkwords);
+ /* links */
+ if (_malloc_rover == NULL) {
+ /* Only block in free list - links point to itself */
+ NEXT(ptr) = ptr;
+ PREV(ptr) = ptr;
+ } else {
+ /*
+ * Non-contiguous sbrk - insert into free list. No
+ * point calling free() because we know this cannot be
+ * coalesced
+ */
+ NEXT(ptr) = _malloc_rover;
+ tmp = PREV(_malloc_rover);
+ PREV(ptr) = tmp; /* PREV(ptr) = PREV(_malloc_rover); */
+ NEXT(tmp) = ptr; /* NEXT(PREV(_malloc_rover)) = ptr; */
+ PREV(_malloc_rover) = ptr;
+ }
+ _malloc_rover = ptr;
+ return(1);
+ }
+ /* Set boundary tags and size */
+ ptr--;
+ blksize = SIZE(ptr) + sbrkwords;
+ SIZEFIELD(ptr) = ALLOCMASK(sbrkwords);
+ _malloc_hiword += sbrkwords;
+ SIZEFIELD(_malloc_hiword-1) = SIZEFIELD(ptr);
+ /* Update fake end tags of the memory chunk */
+ SIZEFIELD(_malloc_hiword) = ALLOCMASK(blksize);
+ SIZEFIELD(_malloc_hiword - blksize + 1) = ALLOCMASK(blksize);
+ SET_REALSIZE(ptr, (sbrkwords - ALLOC_OVERHEAD) * sizeof(Word));
+ free((univptr_t) (ptr + HEADERWORDS));
+ return(1);
+}
+
+univptr_t
+malloc(nbytes)
+size_t nbytes;
+{
+ REGISTER Word *start, *search;
+ REGISTER Word *p;
+ REGISTER size_t required;
+ REGISTER size_t searchsize;
+ REGISTER size_t rest;
+ size_t roversize;
+
+#ifndef BUGCOMPATIBILITY
+ ASSERT(nbytes != 0, "What do you expect when you malloc(0)?!!");
+ if (nbytes == 0) { /* If we're debugging, then we died on the ASSERT */
+ errno = EINVAL;
+ return(NULL);
+ }
+#endif /* BUGCOMPATIBILITY */
+
+ required = ALLOC_OVERHEAD + (nbytes + sizeof(Word) - 1) /
+ sizeof(Word);
+ if (required < (size_t) _malloc_minchunk)
+ required = _malloc_minchunk;
+ search = _malloc_rover;
+ if (!search || required > _malloc_totalavail) {
+ /* Not enough memory in free list - allocate enough memory. */
+ if (grabhunk(required) == 0) {
+ errno = ENOMEM;
+ return( NULL);
+ }
+ search = _malloc_rover;
+ }
+
+ ASSERT(PTR_IN_HEAP(_malloc_rover), "corrupt rover pointer in malloc()");
+ ASSERT(VALID_END_SIZE_FIELD(_malloc_rover), "corrupt block in malloc()");
+ ASSERT(VALID_NEXT_PTR(_malloc_rover), "corrupt block in malloc()");
+ ASSERT(VALID_PREV_PTR(_malloc_rover), "corrupt block in malloc()");
+ CHECKHEAP();
+
+ roversize = FREESIZE(search);
+ if (search == _malloc_hiword - 1) { /* avoid wilderness */
+ search = NEXT(search);
+#if 0
+ {
+ char buf[1024];
+ sprintf(buf, "wilderness = 0x%x, skipping to 0x%x\n",
+ _malloc_hiword - 1, search);
+ fputs(buf, stderr);
+ }
+#endif
+ }
+ start = search;
+ do {
+ ASSERT(PTR_IN_HEAP(search), "corrupt pointer in malloc()");
+ ASSERT(VALID_END_SIZE_FIELD(search), "corrupt pointer in malloc()");
+ ASSERT(VALID_NEXT_PTR(search), "corrupt pointer in malloc()");
+ ASSERT(VALID_PREV_PTR(search), "corrupt pointer in malloc()");
+ searchsize = FREESIZE(search);
+ if (searchsize >= required) {
+ break;
+ } else {
+ search = NEXT(search);
+ }
+ } while (search != start);
+
+ if (searchsize < required) {
+ if (grabhunk(required) == 0) {
+ errno = ENOMEM;
+ return( NULL);
+ }
+ /*
+ * We made sure in grabhunk() or free() that
+ * _malloc_rover is pointing to the newly sbrked (and
+ * freed) block.
+ */
+ search = _malloc_rover;
+ roversize = searchsize = FREESIZE(search);
+ }
+ rest = searchsize - required;
+ if (rest >= _malloc_minchunk) {
+ SIZEFIELD(search) = FREEMASK(rest);
+ p = search - rest;
+ SIZEFIELD(p+1) = FREEMASK(rest);
+ SIZEFIELD(p) = ALLOCMASK(required);
+ p -= required - 1;
+ SIZEFIELD(p) = ALLOCMASK(required);
+ _malloc_totalavail -= required;
+ /* keep rover at the larger block */
+ if (rest > roversize)
+ _malloc_rover = search;
+ } else {
+ /* alloc the entire block */
+ REGISTER Word *nextp = NEXT(search);
+
+ SIZEFIELD(search) |= ALLOCED;
+ p = search - searchsize + 1;
+ SIZEFIELD(p) = SIZEFIELD(search);
+ if (search == nextp) {
+ _malloc_rover = NULL;
+ } else {
+ REGISTER Word *prevp = PREV(search);
+
+ NEXT(prevp) = nextp;
+ PREV(nextp) = prevp;
+ /* keep rover at the larger block, unless we just allocated rover*/
+ if (search == _malloc_rover || FREESIZE(nextp) > roversize)
+ _malloc_rover = nextp;
+ }
+ _malloc_totalavail -= searchsize;
+ }
+ PRTRACE(sprintf(_malloc_statsbuf, "+ %lu %lu 0x%lx\n", (ulong) nbytes,
+ (ulong) (SIZE(p) - ALLOC_OVERHEAD) * sizeof(Word),
+ (ulong) (p + HEADERWORDS)));
+ COUNTSIZE(SIZE(p));
+ SET_REALSIZE(p, nbytes);
+ return((univptr_t) (p + HEADERWORDS));
+}
+
+
+
+void
+free(cp)
+univptr_t cp;
+{
+ /*
+ * This is where the boundary tags come into their own. The
+ * boundary tag guarantees a constant time insert with full
+ * coalescing (the time varies slightly for the four case possible,
+ * but still, essentially a very fast free.
+ */
+ /*
+ * P0 is the block being freed. P1 is the pointer to the block
+ * before the block being freed, and P2 is the block after it.
+ * We can either coalesce with P1, P2, both, or neither
+ */
+ REGISTER Word *p0, *p1, *p2;
+
+ if (cp == NULL)
+ return;
+
+ p0 = (Word *) cp;
+ p0 -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p0), "bad pointer passed to free()");
+ ASSERT(TAG(p0) != FREE, "freed block passed to free()");
+ ASSERT(VALID_START_SIZE_FIELD(p0), "corrupt block passed to free()");
+ ASSERT(VALID_MAGIC(p0), "block with end overwritten passed to free()");
+ /* With debugging, the assert would have already aborted */
+ if (TAG(p0) == FREE) {
+ errno = EINVAL;
+ return;
+ }
+
+ /*
+ * clear the entire block that used to be p0's, just in case someone
+ * tries to refer to it or anything in it again. We leave the end tags
+ * alone for now - we'll smash them individually depending on the way p0
+ * merges with p1 and/or p2.
+ */
+ DMEMSET(p0 + FREEHEADERWORDS, SIZE(p0) - FREE_OVERHEAD);
+ PRTRACE(sprintf(_malloc_statsbuf, "- %lu 0x%lx\n",
+ (ulong) (SIZE(p0) - ALLOC_OVERHEAD) * sizeof(Word),
+ (ulong) (p0 + HEADERWORDS)));
+ _malloc_totalavail += SIZE(p0);
+
+ p1 = p0 - 1;
+ /*
+ * p0 now points to the end of the block -- we start treating it as
+ * a free block
+ */
+ p0 += SIZE(p0) - 1;
+ p2 = p0 + 1;
+
+ /*
+ * More paranoia.... We can't match the SIZEFIELDs of p1/p2 with
+ * p1/p2 + SIZE(p1/p2) -1 because they might be a fake tag to
+ * indicate the bounds of the arena. Further, we should only check
+ * p1 if p0-1 is not the _malloc_loword or an arena bound - else p1 is
+ * probably not a valid pointer. If tag p0-1 is allocated, then it
+ * could be an arena bound.
+ */
+
+ if (TAG(p2) == FREE) {
+ /*
+ * Aha - block which is physically after p0 is free.
+ * Merging with it merely means increasing its size to
+ * incorporate the block being freed - no pointer
+ * shuffling.
+ */
+ p2 += FREESIZE(p2) - 1;
+ ASSERT(PTR_IN_HEAP(p2), "corrupt block in free()");
+ ASSERT(TAG(p2)==FREE, "corrupt block in free()");
+ ASSERT(VALID_END_SIZE_FIELD(p2), "corrupt block in free()");
+ ASSERT(VALID_NEXT_PTR(p2), "corrupt block in free()");
+ ASSERT(VALID_PREV_PTR(p2), "corrupt block in free()");
+
+ SIZEFIELD(p2) = FREEMASK(FREESIZE(p2) + SIZE(p0));
+ SIZEFIELD(p2 - FREESIZE(p2) + 1) = SIZEFIELD(p2);
+ /*
+ * Smash p0's old end tag and p2's old start tag.
+ */
+ DMEMSET(p0 - FREETRAILERWORDS + 1, FREETRAILERWORDS + FREEHEADERWORDS);
+ p0 = p2; /* p0 just vanished - became part of p2 */
+ }
+ if (TAG(p1) == FREE) {
+ /*
+ * Block that physically precedes p0 in memory is free. Merging
+ * with it means rearranging the links to because the end of
+ * the block (the handle it is known by) is now the end of p0
+ * rather than itself. So the blocks after and before it in the
+ * free list need to be told.
+ */
+ REGISTER Word *nextp1, *prevp1;
+
+ ASSERT(PTR_IN_HEAP(p1), "corrupt block in free()");
+ ASSERT(VALID_END_SIZE_FIELD(p1), "corrupt block in free()");
+ ASSERT(VALID_NEXT_PTR(p1), "corrupt block in free()");
+ ASSERT(VALID_PREV_PTR(p1), "corrupt block in free()");
+
+ /* p0 grows to absorb p1 */
+ SIZEFIELD(p0) = FREEMASK(SIZE(p0) + FREESIZE(p1));
+ SIZEFIELD(p0 - FREESIZE(p0) + 1) = SIZEFIELD(p0);
+ nextp1 = NEXT(p1);
+ prevp1 = PREV(p1);
+ /*
+ * We smash the free list pointers in p1 (SIZE, NEXT, PREV) to
+ * make sure no one refers to them again. We cannot smash the
+ * start boundary tag because in both cases, it becomes the start
+ * tag for the new block. We also trash p0's start tag.
+ */
+ DMEMSET(p1 - FREETRAILERWORDS + 1, FREETRAILERWORDS + FREEHEADERWORDS);
+ if (p0 != p2) {
+ /*
+ * Ok - p0 coalesced with the block physically
+ * before it (p1) (which is why we're here, but
+ * it didn't coalesce with the block after it
+ * (p2) which is why p0 != p2. So we need to
+ * insert p0 in the list in place of p1.
+ */
+
+ if (nextp1 != p1) {
+ /* Fix the PREV ptr of the next blk in the list */
+ PREV(nextp1) = p0;
+ /* Fix the NEXT ptr of the previous blk in the list */
+ NEXT(prevp1) = p0;
+ /* Copy the link info from p1 to p0 */
+ NEXT(p0) = nextp1;
+ PREV(p0) = prevp1;
+ } else {
+ NEXT(p0) = p0;
+ PREV(p0) = p0;
+ }
+ /* p1 just vanished - became part of p0 */
+ _malloc_rover = p0;
+ CHECKHEAP();
+ return;
+ } else {
+ /*
+ * p0 merged with p2, and with p1, which
+ * essentially means that p2 grows to absorb p1
+ * in the free list (bridged by p0). So we
+ * simply delete p1. Free list reduces by one blk.
+ */
+ /* Fix the PREV ptr of the next blk in the list */
+ PREV(nextp1) = prevp1;
+ /* Fix the NEXT ptr of the previous blk in the list */
+ NEXT(prevp1) = nextp1;
+ }
+ }
+ if (p0 != p2) {
+ /*
+ * If we're here, it means block P0 didn't coalesce, so
+ * we need to insert it in the free list - we put it
+ * before ROVER, and make ROVER point to it. Or it
+ * means ROVER was NULL, i.e. free list is empty, which
+ * means we have to take care of the boundary linking
+ * Free list grows by one.
+ */
+ if (_malloc_rover == NULL) {
+ /*
+ * Free list was empty - so we point _malloc_rover at
+ * the block we're freeing to get a proper
+ * circular linking.
+ */
+ _malloc_rover = p0;
+ } else {
+ ASSERT(PTR_IN_HEAP(_malloc_rover),
+ "corrupt rover pointer in free()");
+ ASSERT(VALID_END_SIZE_FIELD(_malloc_rover),
+ "corrupt block in free()");
+ ASSERT(VALID_NEXT_PTR(_malloc_rover), "corrupt block in free()");
+ ASSERT(VALID_PREV_PTR(_malloc_rover), "corrupt block in free()");
+ }
+ NEXT(p0) = _malloc_rover;
+ PREV(p0) = PREV(_malloc_rover);
+ PREV(_malloc_rover) = p0;
+ NEXT(PREV(p0)) = p0;
+ SIZEFIELD(p0) &= SIZEMASK; /* sets the boundary tag to FREE */
+ SIZEFIELD(p0 - FREESIZE(p0) + 1) = SIZEFIELD(p0);
+ }
+ _malloc_rover = p0;
+
+ CHECKHEAP();
+ return;
+}
+
+
+
+/*
+ * WARNING: This realloc() IS *NOT* upwards compatible with the
+ * convention that the last freed block since the last malloc may be
+ * realloced. Allegedly, this was because the old free() didn't
+ * coalesce blocks, and reallocing a freed block would perform the
+ * compaction. Yuk!
+ */
+univptr_t
+realloc(cp, nbytes)
+univptr_t cp;
+size_t nbytes;
+{
+ REGISTER Word *p0 = (Word *) cp;
+ REGISTER Word *p1;
+ univptr_t tmp;
+ REGISTER size_t required;
+ REGISTER size_t sizep0;
+
+ if (p0 == NULL)
+ return(malloc(nbytes));
+
+ if (nbytes == 0) {
+ free(cp);
+ return(NULL);
+ }
+
+ required = ALLOC_OVERHEAD + (nbytes + sizeof(Word) - 1) /
+ sizeof(Word);
+ if (required < (size_t) _malloc_minchunk)
+ required = _malloc_minchunk;
+
+ p0 -= HEADERWORDS;
+
+ /* A little paranoia... */
+ ASSERT(PTR_IN_HEAP(p0), "bad pointer passed to realloc()");
+ ASSERT(TAG(p0) != FREE, "freed block passed to realloc()");
+ ASSERT(VALID_START_SIZE_FIELD(p0), "corrupt block passed to realloc()");
+ ASSERT(VALID_MAGIC(p0), "block with end overwritten passed to realloc()");
+ /* With debugging, the assert would have already aborted */
+ if (TAG(p0) == FREE) {
+ errno = EINVAL;
+ return(NULL);
+ }
+ sizep0 = SIZE(p0);
+ if (sizep0 >= required) {
+ /* Shrinking the block */
+ size_t after = sizep0 - required;
+
+ SET_REALSIZE(p0, nbytes);
+ if (after < _malloc_minchunk) {
+ /*
+ * Not enough to free what's left so we return the block
+ * intact - print no-op for neatness in output.
+ */
+ PRTRACE(strcpy(_malloc_statsbuf, "no-op\n"));
+ return(cp);
+ }
+ SIZEFIELD(p0) = ALLOCMASK(required);
+ SIZEFIELD(p0 + required - 1) = SIZEFIELD(p0);
+ p0 += required;
+ /*
+ * We free what's after the block - mark it alloced and
+ * throw it to free() to figure out whether to merge it
+ * with what follows...
+ */
+ SIZEFIELD(p0) = ALLOCMASK(after);
+ SIZEFIELD(p0 + after - 1) = SIZEFIELD(p0);
+ SET_REALSIZE(p0, (after - ALLOC_OVERHEAD) * sizeof(Word));
+ free((univptr_t) (p0 + HEADERWORDS));
+ return(cp);
+ }
+
+ /*
+ * If we get here, then we are growing the block to something
+ * bigger. If the following block is free and big enough to be
+ * realloced, then we grow using that block. This resembles the
+ * malloc code slightly.
+ */
+ p1 = p0 + sizep0;
+ required -= sizep0;
+ if (TAG(p1) == FREE) { /* p1 not free, may be an arena bound or hiword */
+ ASSERT(PTR_IN_HEAP(p1), "corrupt pointer in realloc()");
+ ASSERT(VALID_START_SIZE_FIELD(p1), "corrupt block in realloc()");
+ ASSERT(VALID_NEXT_PTR(p1 + FREESIZE(p1) - 1),
+ "corrupt block in realloc()");
+ ASSERT(VALID_PREV_PTR(p1 + FREESIZE(p1) - 1),
+ "corrupt block in realloc()");
+ }
+ if (TAG(p1) == FREE && FREESIZE(p1) >= required) {
+ size_t rest = FREESIZE(p1) - required;
+ REGISTER Word *p;
+
+ if (rest >= _malloc_minchunk) {
+ sizep0 += required;
+ SIZEFIELD(p0) = ALLOCMASK(sizep0);
+ p = p0 + sizep0;
+ SIZEFIELD(p-1) = SIZEFIELD(p0);;
+ SIZEFIELD(p) = FREEMASK(rest);
+ SIZEFIELD(p + rest - 1) = FREEMASK(rest);
+ _malloc_totalavail -= required;
+ } else {
+ /*
+ * alloc the entire block and merge into p0. Free list
+ * shrinks by a block
+ */
+ REGISTER Word *nextp1, *prevp1;
+
+ sizep0 += FREESIZE(p1);
+ SIZEFIELD(p0) = ALLOCMASK(sizep0);
+ SIZEFIELD(p0 + sizep0 - 1) = SIZEFIELD(p0);
+ p1 += FREESIZE(p1) - 1;
+ p = nextp1 = NEXT(p1);
+ if (p1 == nextp1) {
+ _malloc_rover = NULL;
+ } else {
+ prevp1 = PREV(p1);
+ PREV(nextp1) = prevp1;
+ NEXT(prevp1) = nextp1;
+ _malloc_rover = nextp1;
+ }
+ _malloc_totalavail -= SIZE(p1);
+ }
+ SET_REALSIZE(p0, nbytes);
+ CHECKHEAP();
+
+ PRTRACE(sprintf(_malloc_statsbuf, "++ %lu %lu 0x%lx %lu 0x%lx\n",
+ (ulong) nbytes,
+ (ulong) (SIZE(p0)-ALLOC_OVERHEAD)*sizeof(Word),
+ (ulong) cp, (ulong) SIZE(p)*sizeof(Word),
+ (ulong) p));
+ return(cp);
+ }
+ /* Have to do it the hard way */
+ tmp = malloc(nbytes);
+ if (tmp != NULL) {
+ MEMCPY(tmp, cp, ((SIZE(p0) - ALLOC_OVERHEAD)));
+ free(cp);
+ }
+ return(tmp);
+}
+
+
+
+/*
+ * !! Given what we know about alignment, we should be able to do better
+ * than memset and set words. Hopefully memset has been tuned.
+ */
+univptr_t
+calloc(nelem, elsize)
+size_t nelem, elsize;
+{
+ REGISTER size_t nbytes = nelem * elsize;
+ REGISTER univptr_t cp = malloc(nbytes);
+
+ if (cp)
+ (void) memset((univptr_t) cp, 0, (memsize_t) nbytes);
+ return(cp);
+}
+
+
+/*
+ * Why would anyone want this.... ?
+ */
+void
+cfree(cp)
+univptr_t cp;
+{
+ free(cp);
+}
diff --git a/lib/libmalloc/malloc.doc b/lib/libmalloc/malloc.doc
new file mode 100644
index 000000000000..f209baf5a7bf
--- /dev/null
+++ b/lib/libmalloc/malloc.doc
@@ -0,0 +1,653 @@
+$Header: /home/cvs/386BSD/src/lib/libmalloc/malloc.doc,v 1.1 1994/03/06 22:59:48 nate Exp $
+ Yet another malloc()
+ --------------------
+ Mark Moraes
+ <moraes@csri.toronto.edu>
+
+ Standard calls
+
+It provides the standard calls we expect from any self-respecting
+malloc, viz.
+
+ char *
+ malloc(nbytes)
+
+ unsigned int nbytes;
+
+which returns pointer to a contiguous memory block, at least nbytes
+bytes long,
+
+ char *
+ calloc(nelements, element_size)
+
+ unsigned int nelements, element_size;
+
+which returns a pointer to a contiguous memory block, at least
+nelements * element_size bytes long, with all locations set to zero,
+
+ char *
+ realloc(ptr, nbytes)
+
+ char *ptr;
+ unsigned int nbytes;
+
+attempts to change the size of the previously malloc'ed block pointed
+to by ptr to nbytes, and failing that, returns a pointer to a new block
+nbytes long, after copying the contents of the old block to it.
+Realloc returns NULL if it fails, and DOES NOTHING WITH THE OLD BLOCK.
+(This is not defined; some reallocs may free the old block they were
+passed)
+
+ void
+ free(ptr)
+
+ char *ptr;
+
+returns the previously malloc'ed block pointed to by ptr to the
+storage pool. It will do its best to keep storage as unfragmented as
+possible.
+
+ void
+ cfree(ptr)
+
+ char *ptr;
+
+The same as free(), used to free calloc()ed blocks.
+
+There are a couple of additional functions that Sun malloc provides,
+and that some programs need (notably the X Windows server on Suns)
+
+ char *
+ memalign(alignment, nbytes)
+
+ unsigned int alignment;
+ unsigned int nbytes;
+
+This returns a pointer to a memory block at least nbytes long,
+guaranteeing that the block starting address is an even multiple of
+alignment. Alignment must be a power of 2.
+
+ char *
+ valloc(nbytes)
+
+ unsigned int nbytes;
+
+This is the same as memalign(getpagesize(), nbytes).
+
+A frequently used function is to save a copy of a NULL-terminated
+character array (a C string) in storage malloc'ed exactly to fit it,
+for example when reading or parsing some input line from a large
+buffer. Newer systems provide the strdup() function to do just this.
+(This may not appear a complex funtion - using it eliminates the
+all-too-frequent error where you forget to add 1 to the length of the
+string to allow for the NULL terminator)
+
+ char *
+ strdup(s)
+
+ char *s;
+
+strdup returns NULL if the malloc fails.
+
+ Additional functions
+
+In addition to the usual functions, this malloc provides some
+debugging and profiling functions, which we discuss in more detail
+below. (NOTE: To use these special features, you have to include the
+header file "malloc.h" provided with this malloc. This header file
+also defines the C preprocessor symbol CSRIMALLOC. This allows anyone
+using any of the special features of this malloc to enclose any calls
+to the new features within #ifdef CSRIMALLOC, thus preserving code
+portability)
+
+Since this malloc library is usually installed as libmalloc.a, to use
+it instead of a regular system malloc, you need to specify something
+like -lmalloc on your link/load command line before -lc, if any.
+Make sure your program has at least one call to any one of
+malloc/free/calloc/realloc or the Unix loader may not link in this
+malloc, and will instead use the system one from libc, since it makes
+only one pass.
+
+Most of the debugging features will be available in a version of the
+malloc called malloc_d, which is what you should use for development
+and testing by specifying -lmalloc_d. For production programs, link
+with -lmalloc to get the fast version.
+
+Frequently, people forget to check the return value on a malloc()
+assuming that modern systems never run out of memory. Inevitably,
+Murphy ensures that some system will run out of memory, and a user
+will be faced with the illuminating error message "Segmentation
+violation - core dumped". Alas, when memory runs out, the core dump is
+likely to be large. This malloc provides an emalloc() function which
+exits if NULL is returned, with an out of memory message. Using this
+in place of malloc is advised if running out of memory is a fatal
+condition. (If not, either write your own emalloc() to recover
+gracefully, or check the value returned by malloc)
+
+ char *
+ emalloc(nbytes)
+
+ unsigned nbytes;
+
+Similarly, a realloc which will die instead of returning NULL is
+erealloc().
+
+ char *
+ erealloc(ptr, nbytes)
+
+ unsigned nbytes;
+
+A similar function, like strdup() but not returning NULL is strsave().
+
+ char *
+ strsave(s)
+
+ char *s;
+
+
+ Debugging support
+
+Alas, one of the more common, and unpleasant errors a C programmer can
+make is to accidentally exceed the bounds of an array, and write over
+the data that immediately follows (or less frequently, precedes) it in
+memory. Such "corruption" errors usually show up at a completely
+different place in the program from the place the actual overwriting
+occurs (A corollary to Murphy's Law suggests the error will appear in
+the last related module of the program), thus making it at least as
+hard to track down as the proverbial needle in the haystack. While
+there is little that we can do to help detect errors in static,
+automatic or global data, we can at least try to ensure the validity
+of the malloc()ed data.
+
+To get this support, the malloc() must be compiled with -DDEBUG -
+since this reduces performance somewhat, it is usually done in a
+separate object module from the one usually used in production code.
+This debugging malloc() makes sure all internal heap pointers relevant
+to an allocation (or free) are correct on every call to one of the
+allocation routines, and aborts if it detects any trouble, with a
+message starting with "assertion botched". This is
+useful because it causes the program to die nearer the trouble spot
+than would otherwise be the case, helping to pinpoint the error.
+This narrows down the location of the error to something less than the
+aforementioned haystack, but the problem is still somewhat large.
+
+ int
+ mal_verify(fullcheck)
+
+ int fullcheck;
+
+lends a helping hand in such distressing situations. It runs through
+all allocated and free blocks, checking all heap pointers for
+validity. Since the heap pointers (and block size values) are at the
+beginning and end of allocated (and free) blocks, any overwriting off
+the end of a memory block usually results in the corruption of the
+heap size values, or the pointer values of the next block. If
+'fullcheck' is non-zero, then additional checking of the contents of
+free blocks is done, to ensure that they haven't been written into
+after being freed. Calling mal_verify() with fullcheck as 1 is
+recommended. (More on this later)
+
+On detecting an error, mal_verify() aborts the program, on the not
+unreasonable grounds that such an error is A BAD THING and should be
+fixed immediately.
+
+A careful programmer will probably want to put calls to mal_verify()
+at frequent points in any code, as checkpoints to trap any stray
+overwriting or memory corruption that may take place. Since
+mal_verify() does nothing in a malloc compiled without -DDEBUG, it
+has no overhead in production code other than the procedure call.
+("But I can't be overwriting any data between X and Y in my code" are
+famous last words)
+
+Instead of putting calls to mal_verify(), the programmer can set
+the debugging level of the allocator.
+
+ void
+ mal_debug(level)
+
+ int level;
+
+Most debugging is done at level 1, which is the default. This only
+checks the internal pointers that are encountered during a malloc() or
+free(). Setting level to 2 with the mal_debug() call results in a
+complete check of the heap (i.e. a call to mal_verify(0) ) every time
+malloc(), realloc() or free() are called. (The other allocation
+routines call these three) This can be very slow if your program does
+a lot of debugging, but is worth turning on for a specific segment of
+the program where you suspect trouble. (The author uses this mode when
+writing and debugging a program initially, switches to normal
+debugging for alpha and beta test) Level 3 asks for mal_verify(1) on
+every malloc(), realloc() or free() which checks all free blocks'
+insides for any signs of someone writing to them.
+
+We recommend the use of a binary search technique for pinpointing the
+needle, er, the overwriting. This presupposes that malloc(), free(),
+or a previously (wisely) inserted mal_verify() has caused the
+program to die at some point with an "assertion botched" error. (If
+the programmer has not been using this malloc so far, or a variant
+compiled without -DDEBUG, then the only indication of a memory
+corruption error is utterly strange things happening to the program,
+possibly variable changing values when they're not supposed to, or
+mysterious deaths of the program in malloc(), free() or some such
+call)
+
+Insert a mal_verify() call (Referred to from now on as Checkpoint
+1) at some point well before the error occurs, if necessary, at the
+first executable statement in the program. Insert another
+mal_verify call on the statement just before you suspect the error
+manifesting itself. (Checkpoint 2)
+
+(Note that when we say insert a mal_verify() call at some point
+"before" an error occurs, we are referring to a temporal location,
+i.e some piece of code that is executed by the program in the time
+before the error occurs. Physically, this may be in a different
+procedure, or a different file altogether.)
+
+Run the program.
+
+If Checkpoint 1 causes the program to die, then the error is trapped
+in between it and the start of the program. (case A) If Checkpoint 2
+causes the program to die, then the error is trapped between it and
+Checkpoint 1, (case B) and if neither dies, the error is after
+Checkpoint 2, (case C) or is not an overwriting error at all, or is an
+error subtle enough to avoid the heap pointer checking. In the last
+case, we wish you luck...
+
+Case A: (The bug is before checkpoint 1)
+
+Move Checkpoint 2 to where checkpoint 1 presently is, and move
+checkpoint 1 further back. Run the program again.
+
+Case B: (The bug is between checkpoint 1 and checkpoint 2 - narrow the
+search area down further)
+
+This is the case we attempt to maintain. Having attained it, we
+promptly attempt to lose it again. (Why is this starting to sound like
+Zen...) To do so, we move either Checkpoint 1 or Checkpoint 2 closer
+to the other, and run the program again.
+
+Case C: (The bug is after checkpoint 2)
+
+Move Checkpoint 1 to where checkpoint 2 presently is, and move
+checkpoint 2 further ahead. Run the program again.
+
+The objective is to bring the two checkpoints as close to each other
+as is necessary to spot the bug. (Recognizing the bug is up to the
+programmer - loops exceeding the bound by one are a common problem
+causing this error - confusion with C's starting arrays at 0 unlike
+other languages which start them at 1 is another problem).
+
+Those familiar with numerical methods will see the similarity between
+this method and the binary search method for finding a root of an
+equation. (It also bears a resemblance to the binary search method on
+sorted data, but the resemblance is less striking)
+
+In a modular program, which has been well structured, placing such
+checkpoints is easy to do; simply start at the top level, narrow it
+down to some procedure call at that level, insert them at the entry and
+exit points of that procedure, narrow it down to some procedure call
+at this level, and recurse downward till the fault is detected.
+
+We noted earlier that some corruption bugs manifest themselves (Why is
+this starting to read like a ghostbusters' script...) as data values
+that change when they shouldn't. In this case, a simpler method to
+trace the bug is often to put a trace on that data location by setting
+a global pointer variable to point to it, and printing the value at
+the two checkpoints. The same search strategy can be employed. This
+has been found useful in at least one bug the author has encountered,
+which sneakily refused to corrupt the heap pointers, jumping over them
+straight into another block to do its dirty work.
+
+A vicious form of heap corruption is when someone frees a block of
+memory, but forgets to NULL or reset all pointers pointing to that
+block. At some point in the future, if that block is accessed, strange
+things can happen. If that block is still free, and in the heap, there
+is a chance of corrupting malloc's internal pointers and structures
+used to maintain the free list, in which case mal_verify() will detect
+the corruption and abort. Or the corruption may go into the middle of
+the block and go undetected. Even worse, the block or part of the
+block may have been allocated to the program for some other purpose,
+and the corruption may now be smashing data in another part of the
+program. This sort of corruption is insidious, and very hard to
+reproduce, let alone trace down. To help trace this down, when a block
+is freed, in debugging mode, the allocator scribbles a magic pattern
+all over it, thus making sure any data in there is likely to be wrong.
+Invoking mal_verify(1) will check every free block to make sure its
+contents are that magic pattern and abort if it detects corruption.
+Setting debug level to 3 with mal_debug() will force this sort of
+verification on every call to malloc(), realloc() or free().
+Obviously, if the block gets allocated, and then corrupted, the malloc
+verification cannot detect it, since it has no idea what goes on
+inside allocated blocks.
+
+
+ Advanced debugging tools.
+
+ void
+ mal_heapdump(fd)
+
+ FILE *fd;
+
+If all else fails, the programmer may obtain a printout of the entire
+heap by calling mal_heapdump() with a file descriptor to an already
+open file (fopen(3)). This will print the start address of
+all blocks, allocated or free, and their sizes. These can be matched
+with pointer addresses in the program and used to trace heap
+corruption. If you use this call, you probably know how to do this.
+Large doses of intuition (and strong beverages) are recommended.
+mal_heapdump() performs the same checking that mal_verify(1) does, but
+does not abort unless the error makes it impossible to dump the heap
+further. A knowledge of the malloc internals is necessary to fully
+exploit this call's output.
+
+ Profiling support
+
+This malloc() is faster than most other mallocs that I've seen - the
+search strategy is a first-free, which is not excitingly fast in
+theory, but, with small modifications turns out to be quite fast in
+practice; See Knuth for more details. (Theoretically, the time is of
+the same order as the size of the free list, so the free list is kept
+as small as possible by coalescing a block with adjacent freed blocks
+if possible, when it is freed) The free() is based on a boundary tags
+scheme, as described in Knuth. It is linear-time, for those who care
+about such things, and is a few statements of C code - 4 comparisons
+and a little pointer arithmetic. It also accesses memory locations
+next to the block only, so it has good virtual memory performance. (The
+malloc turns out to have good VM performance most of the time, but
+will occasionally scan through a few pages, and in worst case, through
+a lot of pages. If however, those pages are all being used, then the
+VM performance is likely to be influenced more by the program using
+the malloc than the malloc itself)
+
+Nonetheless, a program which calls malloc and free *very* frequently
+might be slow. In order to track down malloc usage, if compiled with
+-DPROFILEDSIZES, this malloc keeps count of the number of block sizes
+being used by the program. To print out these collected statistics,
+call
+
+ void
+ mal_statsdump(fd)
+
+ FILE *fd;
+
+where fd is an already opened file descriptor, and it will print a
+list of block sizes, and the number of times a block of that size was
+allocated. This information provides some indication of the allocation
+profile of the calling program.
+
+When mal_statsdump() is called, it zeroes all the counters, so that
+you can check the allocation profile of specific segments of a program
+by calling mal_statsdump() repeatedly.
+
+If more detailed tracing information is needed, the malloc must be
+compiled with -DTRACE. This prints out the size of every allocation
+or free. This can be turned on or off using
+
+ void
+ mal_trace(flag)
+
+ int flag;
+
+If flag is 0, tracing is turned off, (this is the default state), if
+it is non-zero, then tracing commences.
+
+The trace records are of the form:
+For a malloc,
+ + <nbytes> <realsize> <address>
+
+ where <nbytes> is the number of
+bytes requested, <realsize> is the number of bytes allocated (usually
+nbytes rounded up to a multiple of the word size, plus any slop if
+that is requested with mal_slopset), and <address> is the block
+returned.
+
+ If the malloc results in the system being asked for more memory,
+via sbrk(), it prints
+ sbrk <bytesobtained>
+where <bytesobtained> is the number of bytes the system was asked for.
+After the first such call, it will then print
+ heapstart <address>
+where <address> is the
+
+For a free,
+ - <realsize> <address>
+where <address> is the address of the block being freed
+and <realsize> is the malloc'ed size of the block. (the size requested
+by the user, rounded up to the word size with slop, if any)
+
+For a realloc, it may print out
+ the same as as a free if we're shrinking and the part of the
+block was freed
+
+ no-op
+ if we're shrinking and the remaining part of the block
+was too small to be freed, it prints
+
+ ++ <nbytes> <realsize> <address> <realsize_free> <address_free>
+where <nbytes> is the number of bytes requested, <realsize> is the actual
+number of bytes in the block returned, and <address> is the address of
+the block returned, <realsize_free> is the actual size of the free
+block after the one we're returning, which we grew into, <address_free>
+is the address of the free block after the one we're returning. The
+free block information is internal to the malloc and is of little use
+to the user.
+
+ the same as for a malloc and a free if the block ends up being
+copied to a new block.
+
+
+The trace records may be prefixed by the filename and linenumber of
+the call is the source if the file malloc.h was included and the C
+preprocessor symbol MALLOC_TRACE defined when compiling the program,
+and the malloc library was compield with the tracing option enabled.
+(Ask your system adminstrator, or whoever installed the malloc)
+(typically with the flag -DMALLOC_TRACE on the cc command line) This
+is advised - it makes debugging and leak tracing much easier.
+
+The file to which this information is printed can be set with
+
+ void
+ mal_setstatsfile(fd)
+
+ FILE *fd;
+
+The default is stderr.
+
+
+There are two variables in this malloc that can be set to tune
+performance somewhat, and keep memory fragmentation down. One is
+'slop', the other is the sbrk() size.
+
+ void
+ mal_slopset(slop)
+
+ int slop;
+
+The minimum size block allocated is slop. (The default for this is the
+minimum possible to maintain the heap pointers required for a free
+block, denoted by a slop of 0) If you notice however, that a lot of
+blocks are being used in a specific small size, or small range of
+small sizes, then you might want to increase slop so that slop is big
+enough to cover all those sizes - while this may waste some memory, it
+will speed up allocation for those sizes by guaranteeing that all
+blocks in the free list are at least that size, so the first fit
+becomes as fast as possible, and the memory fragmentation is reduced
+because of the more uniform block size.
+
+ void
+ mal_sbrkset(nbytes)
+
+ int nbytes;
+
+If there isn't a block large enough to supply a malloc request, then
+the allocator asks for the system to increase the data space of the
+process using the sbrk call. By default, sbrk() is called with 1K *
+sizeof(Word). (unless the malloc request is for a larger size) If your
+program uses less memory than this, you may want to reduce the size.
+On the other hand, in a program that allocates a lot of memory, to
+reduce the number of system calls, you may want to increase this size,
+using the mal_sbrkset() call.
+
+ Performance
+
+The 4.3 malloc, (variants of which are distributed with perl, tcsh,
+GNU and so on) is slightly faster than this malloc but it wastes more
+space because it allocates blocks in powers of 2. It does not coalesce
+free space, which can lead to it wasting lots of space. (There are some
+pathological allocation sequences where it will ask for more space
+from the system even though it has enough free space)
+
+The Sun malloc wastes somewhat less than this malloc, but is
+twice as slow, and causes more paging because it stores free blocks
+and their headers separately. It has debugging support similar to
+mal_verify() and mal_debug(), but not quite as thorough.
+
+The 4.1 malloc is much slower than this malloc, and wastes about the
+same space.
+
+ Incompatibilities
+
+There is only one serious incompatibility that I know of with some
+other malloc()s. In the old 4.1 malloc(), free was kept fast by not
+having it merge adjacent free blocks. This resulted in seriously
+fragmented arenas for programs that did a lot of allocation and
+freeing.
+
+The realloc() kludge provided a hook to force the merging of such
+blocks - the user called realloc() with a a block which had been freed.
+
+I think this practice is bad (Also, both ANSI and SVID do not support
+it) - since this malloc does a fast free that also merges the freed
+block to maintain the largest possible contiguous free blocks, there
+is no need for storage compaction. If compiled with -DDEBUG, this
+realloc() will die with an error if a freed block is passed to
+realloc() which would enable fixing programs that adhere to the old
+convention. If not compiled with -DDEBUG, it sets errno to EINVAL and
+returns NULL.
+
+ Memory leaks
+
+Some memory allocated by a program is meant for the entire lifetime of
+the program. (For many simple programs, this constitutes all the
+allocation done by the program, and this section does not apply to
+such programs) Some memory however is allocated for some time, and is
+later freed.
+
+Keeping track of memory to be freed is often a nuisance, and
+sometimes, programs may change the only pointer to an allocated block
+without freeing the block first. such unreferenced, but allocated
+memory is called "garbage" or a "memory leak", and is wasted, since
+the program has no way of finding it again. (Other languages, like
+Lisp, perform garbage collection frequently, finding all blocks that
+are unreferenced, and freeing them. In the Unix/C environment, this is
+difficult to do, even though garbage collecting mallocs exist. Even
+worse, it is often inefficient)
+
+Memory leaks are serious for programs that run for a long time -
+window managers, daemons, and suchlike, since the total memory wasted
+over time may be large. Meticulously freeing everything allocated
+by a program is the best solution - alas, for object-oriented
+programming styles, it becomes very hard to keep track of every object
+ever created so that open can free it.
+
+One method or providing temporary storage is the alloca() function.
+This is used to allocate space off the run-time stack so that it is
+automatically reclaimed upon procedure exit. It can therefore be used
+to provide temporary storage needed by a procedure and the procedures
+called by the procedure. Whether or not to use the alloca() call is a
+somewhat controversial matter. The manual page warns that
+ "alloca() is both machine- and compiler-dependent; its use is
+ discouraged."
+On the other hand, a fairly portable implementation using malloc() and
+free() does exist, and some compilers (eg) GNU cc provide a
+__builtin_alloca function, which they translate into a couple of
+machine instructions to extend the frame pointer in the appropriate
+direction. With these compilers, alloca() can be very fast - much
+faster than any other memory allocation technique short of statically
+allocated buffers.
+
+Alloca() still does not address the problem of storage which is needed
+temporarily, but which may be passed to a routine's parent.
+
+Another way for a programmer to trace what is going on is to define
+the preprocessor symbol MALLOC_TRACE (for example, with -DMALLOC_TRACE
+on the cc command line when compiling the program) and then include
+the header file "malloc.h" in the program. When MALLOC_TRACE is
+defined, this header redefines malloc() and friends to macros, which
+invoke _malloc() etc; the latter are routines which take the filename
+and linenumber at which they are called. Calling
+
+ void
+ mal_leaktrace(value)
+
+ int value;
+
+with value > 0 will start the leaktracing process, recording the
+address of each block returned by malloc, calloc, etc, along with the
+filename:linenumber at which it was called. If that block is freed, it
+deletes the record for that block. (Calling mal_leaktrace() with
+value == 0 turns off tracing)
+
+At any time, the programmer can call
+
+ void
+ mal_dumpleaktrace(fd)
+
+ FILE *fd;
+
+where fd is a file pointer onto a file openeed for writing with
+fopen() or freopen(), into which a list of unfreed blocks is dumped.
+This list is in the form
+
+ filename:linenumber: sequence-no. address-in-decimal (address-in-hex)
+
+This permits the programmer to examine the places in the program where
+blocks were allocated and not freed. These represent potential memory
+leaks. (Several text-editors will understand this sort of output as
+output from grep -n, and will be able to load and step through these
+files, eg. Jove)
+
+Typically, memory leaks take place within the main loop of a program,
+so the general structure of the program may look something like
+
+ initialization allocation
+ while (something) {
+ things to do
+ }
+
+The initial allocation is at worst a one-time memory wastage and does
+not concern us that much. Memory that is allocated inside the loop,
+and is not freed does concern us since it is a continuous loss, so
+after the initialization allocation, we insert a call to
+mal_leaktrace() to start tracing. When the second iteration starts,
+we call mal_dumpleaktrace() to dump the blocks that were presumably
+allocated during the first iteration and have not yet been freed, and
+do the same at the start of the third iteration for unfreed blocks
+from the second iteration and so on. The code now looks something like
+
+ initialization allocation
+ mal_leaktrace(1);
+ while(something) {
+ mal_dumpleaktrace(stderr);
+ things to do;
+ }
+
+The above is a simple example - more complex control-flow may require
+turning leak tracing on and off repeatedly, so as not to get deluged
+with information.
+
+If you use allocation functions within your code that layer on top of
+malloc, this leak tracing as it is will not be too useful since it
+will only report the location of your allocation functions. In that
+case, you have to define subsidiary allocation functions like
+_malloc() and #defines like those in the malloc.h file so that you can
+record the real address of the call. See the _malloc.c file and the
+malloc.h header for examples on how to do this. (You have to call the
+real allocation and then use the RECORD_FILE_AND_LINE() macro from
+trace.h to store the address of the allocated block. When you free the
+block you have to call the DELETE_RECORD() macro to remove that
+address. Do not include malloc.c in these files, and make sure you do
+call the real malloc from your allocation function - otherwise the
+allocation package will attempt to record the same address twice and
+fail) You may also want to include defs.h and then use PRTRACE() to
+print the line number and file name in the trace file.
diff --git a/lib/libmalloc/malloc.h b/lib/libmalloc/malloc.h
new file mode 100644
index 000000000000..f86ed22827ca
--- /dev/null
+++ b/lib/libmalloc/malloc.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright University of Toronto 1988, 1989, 1993.
+ * Written by Mark Moraes
+ *
+ * Permission is granted to anyone to use this software for any purpose on
+ * any computer system, and to alter it and redistribute it freely, subject
+ * to the following restrictions:
+ *
+ * 1. The author and the University of Toronto are not responsible
+ * for the consequences of use of this software, no matter how awful,
+ * even if they arise from flaws in it.
+ *
+ * 2. The origin of this software must not be misrepresented, either by
+ * explicit claim or by omission. Since few users ever read sources,
+ * credits must appear in the documentation.
+ *
+ * 3. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software. Since few users
+ * ever read sources, credits must appear in the documentation.
+ *
+ * 4. This notice may not be removed or altered.
+ *
+ * $Id: malloc.h,v 1.1 1994/03/06 22:59:49 nate Exp $
+ */
+#ifndef __XMALLOC_H__
+#define __XMALLOC_H__
+
+#if defined(ANSI_TYPES) || defined(__STDC__)
+#define univptr_t void *
+#else /* ! ANSI_TYPES */
+#define univptr_t char *
+#define size_t unsigned int
+#endif /* ANSI_TYPES */
+
+#if defined(ANSI_TYPES) && !defined(__STDC__)
+#define size_t unsigned long
+#endif
+
+#if defined(__STDC__)
+#define __proto(x) x
+#else
+#define __proto(x) ()
+#endif
+
+/*
+ * defined so users of new features of this malloc can #ifdef
+ * invocations of those features.
+ */
+#define CSRIMALLOC
+
+#ifdef MALLOC_TRACE
+/* Tracing malloc definitions - helps find leaks */
+
+extern univptr_t __malloc __proto((size_t, const char *, int));
+extern univptr_t __calloc __proto((size_t, size_t, const char *, int));
+extern univptr_t __realloc __proto((univptr_t, size_t, const char *, int));
+extern univptr_t __valloc __proto((size_t, const char *, int));
+extern univptr_t __memalign __proto((size_t, size_t, const char *, int));
+extern univptr_t __emalloc __proto((size_t, const char *, int));
+extern univptr_t __ecalloc __proto((size_t, size_t, const char *, int));
+extern univptr_t __erealloc __proto((univptr_t, size_t, const char *, int));
+extern char *__strdup __proto((const char *, const char *, int));
+extern char *__strsave __proto((const char *, const char *, int));
+extern void __free __proto((univptr_t, const char *, int));
+extern void __cfree __proto((univptr_t, const char *, int));
+
+#define malloc(x) __malloc((x), __FILE__, __LINE__)
+#define calloc(x, n) __calloc((x), (n), __FILE__, __LINE__)
+#define realloc(p, x) __realloc((p), (x), __FILE__, __LINE__)
+#define memalign(x, n) __memalign((x), (n), __FILE__, __LINE__)
+#define valloc(x) __valloc((x), __FILE__, __LINE__)
+#define emalloc(x) __emalloc((x), __FILE__, __LINE__)
+#define ecalloc(x, n) __ecalloc((x), (n), __FILE__, __LINE__)
+#define erealloc(p, x) __erealloc((p), (x), __FILE__, __LINE__)
+#define strdup(p) __strdup((p), __FILE__, __LINE__)
+#define strsave(p) __strsave((p), __FILE__, __LINE__)
+/* cfree and free are identical */
+#define cfree(p) __free((p), __FILE__, __LINE__)
+#define free(p) __free((p), __FILE__, __LINE__)
+
+#else /* MALLOC_TRACE */
+
+extern univptr_t malloc __proto((size_t));
+extern univptr_t calloc __proto((size_t, size_t));
+extern univptr_t realloc __proto((univptr_t, size_t));
+extern univptr_t valloc __proto((size_t));
+extern univptr_t memalign __proto((size_t, size_t));
+extern univptr_t emalloc __proto((size_t));
+extern univptr_t ecalloc __proto((size_t, size_t));
+extern univptr_t erealloc __proto((univptr_t, size_t));
+extern char *strdup __proto((const char *));
+extern char *strsave __proto((const char *));
+extern void free __proto((univptr_t));
+extern void cfree __proto((univptr_t));
+
+#endif /* MALLOC_TRACE */
+
+extern void mal_debug __proto((int));
+extern void mal_dumpleaktrace __proto((FILE *));
+extern void mal_heapdump __proto((FILE *));
+extern void mal_leaktrace __proto((int));
+extern void mal_sbrkset __proto((int));
+extern void mal_slopset __proto((int));
+extern void mal_statsdump __proto(());
+extern void mal_setstatsfile __proto((FILE *));
+extern void mal_trace __proto((int));
+extern int mal_verify __proto((int));
+extern void mal_mmap __proto((char *));
+
+
+/*
+ * You may or may not want this - In gcc version 1.30, on Sun3s running
+ * SunOS3.5, this works fine.
+ */
+#ifdef __GNUC__
+#define alloca(n) __builtin_alloca(n)
+#endif /* __GNUC__ */
+#ifdef sparc
+#define alloca(n) __builtin_alloca(n)
+#endif /* sparc */
+
+#ifdef ANSI_TYPES
+#undef univptr_t
+#else /* ! ANSI_TYPES */
+#undef univptr_t
+#undef size_t
+#endif /* ANSI_TYPES */
+
+/* Just in case you want an ANSI malloc without an ANSI compiler */
+#if defined(ANSI_TYPES) && !defined(__STDC__)
+#undef size_t
+#endif
+
+#undef __proto
+
+#endif /* __XMALLOC_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/memalign.c b/lib/libmalloc/memalign.c
new file mode 100644
index 000000000000..270aa4e62676
--- /dev/null
+++ b/lib/libmalloc/memalign.c
@@ -0,0 +1,160 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: memalign.c,v 1.1 1994/03/06 22:59:49 nate Exp $")
+
+/*
+ * !! memalign may leave small (< _malloc_minchunk) blocks as garbage.
+ * Not worth fixing now -- I've only seen two applications call valloc()
+ * or memalign(), and they do it only once in their life.
+ */
+/*
+ * This is needed to be compatible with Sun mallocs - Dunno how many
+ * programs need it - the X server sure does... Returns a block 'size'
+ * bytes long, such that the address is a multiple of 'alignment'.
+ * (alignment MUST be a power of 2). This routine is possibly more
+ * convoluted than free() - certainly uglier. Since it is rarely called
+ * - possibly once in a program, it should be ok. Since this is called
+ * from valloc() which is usually needed in conjunction with
+ * mmap()/munmap(), note the comment in the Sun manual page about
+ * freeing segments of size 128K and greater. Ugh.
+ */
+univptr_t
+memalign(alignment, size)
+size_t alignment, size;
+{
+ univptr_t cp;
+ univptr_t addr;
+ REGISTER Word *p0, *p1;
+ REGISTER size_t before, after;
+ size_t blksize;
+#ifdef DEBUG
+ int tmp_debugging = _malloc_debugging;
+#endif /* DEBUG */
+
+ if (alignment < sizeof(int) || !is_power_of_2(alignment) ||size == 0) {
+ errno = EINVAL;
+ return(NULL);
+ }
+ if (alignment < sizeof(Word))
+ return(malloc(size)); /* We guarantee this alignment anyway */
+ /*
+ * Life starts to get complicated - need to get a block large
+ * enough to hold a block 'size' long, starting on an 'alignment'
+ * boundary
+ */
+ if ((cp = malloc((size_t) (size + alignment - 1))) == NULL)
+ return(NULL);
+ addr = SIMPLEALIGN(cp, alignment);
+ /*
+ * This is all we really need - can go back now, except that we
+ * might be wasting 'alignment - 1' bytes, which can be large since
+ * this junk is usually called to align with things like pagesize.
+ * So we try to push any free space before 'addr' and after 'addr +
+ * size' back on the free list by making the memaligned chunk
+ * ('addr' to 'addr + size') a block, and then doing stuff with the
+ * space left over - either making them free blocks or coelescing
+ * them whichever way is simplest. This usually involves making
+ * them look like allocated blocks and calling free() which has all
+ * the code to deal with this, and should do it reasonably fast.
+ */
+ p0 = (Word *) cp;
+ p0 -= HEADERWORDS;
+ /*
+ * p0 now points to the word tag starting the block which we got
+ * from malloc. This remains invariant from now on - p1 is our
+ * temporary pointer
+ */
+ p1 = (Word *) addr;
+ p1 -= HEADERWORDS;
+ blksize = (size + sizeof(Word) - 1) / sizeof(Word);
+ before = p1 - p0;
+ after = SIZE(p0) - ALLOC_OVERHEAD - blksize - before;
+ /*
+ * p1 now points to the word before addr - this is going to be the
+ * start of the memaligned block
+ */
+ if (after < _malloc_minchunk) {
+ /*
+ * We merge the extra space after the memaligned block into it
+ * since that space isn't enough for a separate block. Note
+ * that if the block after the one malloc returned is free, we
+ * might be able to merge the space into that block even if it
+ * is too small - unfortunately, free() won't accept a block of
+ * this size, and I don't want to do that code here, so we'll
+ * just let it go to waste in the memaligned block. !! fix later, maybe
+ */
+ blksize += after;
+ after = 0;
+ }
+ /*
+ * We mark the newly carved memaligned block p1 as alloced. addr is
+ * (p1 + 1) which is the address we'll return
+ */
+ SIZEFIELD(p1) = ALLOCMASK(blksize + ALLOC_OVERHEAD);
+ SIZEFIELD(p1 + blksize + ALLOC_OVERHEAD - 1) = SIZEFIELD(p1);
+ SET_REALSIZE(p1, size);
+ if (after > 0) {
+ /* We can now free the block after the memaligned block. */
+ p1 += blksize + ALLOC_OVERHEAD; /* SIZE(p1) */
+ /*
+ * p1 now points to the space after the memaligned block. we
+ * fix the size, mark it alloced, and call free - the block
+ * after this may be free, which isn't simple to coalesce - let
+ * free() do it.
+ */
+ SIZEFIELD(p1) = ALLOCMASK(after);
+ SIZEFIELD(p1 + after - 1) = SIZEFIELD(p1);
+ SET_REALSIZE(p1, (after - ALLOC_OVERHEAD) * sizeof(Word));
+#ifdef DEBUG
+ /* Full heap checking will break till we finish memalign */
+ _malloc_debugging = 0;
+#endif /* DEBUG */
+ free((univptr_t) (p1 + HEADERWORDS));
+ }
+ if (addr != cp) {
+ /*
+ * If what's 'before' is large enough to be freed, add p0 to
+ * free list after changing its size to just consist of the
+ * space before the memaligned block, also setting the
+ * alloced flag. Then call free() -- may merge with preceding
+ * block. (block after it is the memaligned block)
+ */
+ /*
+ * Else the space before the block is too small to form a
+ * free block, and the preceding block isn't free, so we
+ * aren't touching it. Theoretically, we could put it in
+ * the preceding alloc'ed block, but there are painful
+ * complications if this is the start of the arena. We
+ * pass, but MUST mark it as allocated. This sort of garbage
+ * can split up the arena -- fix later with special case maybe?!!
+ */
+ p1 = p0;
+ SIZEFIELD(p1) = ALLOCMASK(before);
+ SIZEFIELD(p1 + before - 1) = SIZEFIELD(p1);
+ SET_REALSIZE(p1, (before - ALLOC_OVERHEAD) * sizeof(Word));
+ if (before >= _malloc_minchunk) {
+ free(cp);
+ }
+ }
+#ifdef DEBUG
+ _malloc_debugging = tmp_debugging;
+#endif /* DEBUG */
+ return(addr);
+}
+
+/* Just following the Sun manual page here */
+univptr_t
+valloc(size)
+size_t size;
+{
+ static size_t pagesz = 0;
+
+ if (pagesz == 0)
+ pagesz = (size_t) getpagesize();
+ return(memalign(pagesz, size));
+}
diff --git a/lib/libmalloc/setopts.c b/lib/libmalloc/setopts.c
new file mode 100644
index 000000000000..d3ddb70f7c63
--- /dev/null
+++ b/lib/libmalloc/setopts.c
@@ -0,0 +1,120 @@
+/* Set various malloc options */
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: setopts.c,v 1.1 1994/03/06 22:59:50 nate Exp $")
+
+/*
+ * Sets debugging level - level 0 and 1 both perform normal checking -
+ * making sure a pointer is valid before it is used for any heap data,
+ * and doing consistency checking on any block it touches while it
+ * works. Level 2 asks for a mal_verify() on every malloc(), free() or
+ * realloc(), thus checking the entire heap's pointers for consistency.
+ * Level 3 makes mal_verify() check that all free blocks contain a
+ * magic pattern that is put into a free block when it is freed.
+ */
+void
+mal_debug(level)
+int level;
+{
+#ifdef DEBUG
+ if (level < 0 || level > 3) {
+ return;
+ }
+ _malloc_debugging = level;
+#endif /* DEBUG */
+}
+
+/*
+ * Allows you to control the number of system calls made, which might
+ * be helpful in a program allocating a lot of memory - call this once
+ * to set a number big enough to contain all the allocations. Or for
+ * very little allocation, so that you don't get a huge space just
+ * because you alloc'e a couple of strings
+ */
+void
+mal_sbrkset(n)
+int n;
+{
+ if (n < _malloc_minchunk * sizeof(Word)) {
+ /* sbrk'ing anything less than a Word isn't a great idea.*/
+ return;
+ }
+
+ _malloc_sbrkunits = (n + sizeof(Word) - 1) / sizeof(Word);
+ return;
+}
+
+/*
+ * Since the minimum size block allocated is sizeof(Word)*_malloc_minchunk,
+ * adjusting _malloc_minchunk is one way to control
+ * memory fragmentation, and if you do a lot of mallocs and frees of
+ * objects that have a similar size, then a good way to speed things up
+ * is to set _malloc_minchunk such that the minimum size block covers
+ * most of the objects you allocate
+ */
+void
+mal_slopset(n)
+int n;
+{
+ if (n < 0) {
+ return;
+ }
+
+ _malloc_minchunk = (n + sizeof(Word) - 1) / sizeof(Word) + FIXEDOVERHEAD;
+ return;
+}
+
+/*
+ * Sets the file used for verbose statistics to 'fd'. Does no
+ * verification whatsoever on the file descriptor
+ */
+void
+mal_setstatsfile(fd)
+FILE * fd;
+{
+ _malloc_statsfile = fd;
+ /*
+ * This file descriptor had better not have been written to before
+ * this
+ */
+ (void) setvbuf(fd, (char *) 0, _IONBF, 0);
+}
+
+/*
+ * Turns tracing on (if value != 0) or off, (if value == 0)
+ */
+void
+mal_trace(value)
+int value;
+{
+ if (value) {
+ /* Try to unbuffer the trace file */
+ (void) setvbuf(_malloc_statsfile, (char *) 0, _IONBF, 0);
+ /*
+ * Write something to the stats file so stdio can initialize
+ * its buffers i.e. call malloc() at least once while tracing
+ * is off, if the unbuffering failed.
+ */
+ (void) fputs("Malloc tracing starting\n", _malloc_statsfile);
+ _malloc_tracing = 1;
+ if (_malloc_loword != NULL) {
+ /*
+ * malloc happened before tracing turned on, so make
+ * sure we print the heap start for xmem analysis.
+ */
+ PRTRACE(sprintf(_malloc_statsbuf, "heapstart 0x%lx\n",
+ (ulong) _malloc_loword));
+ }
+ } else {
+ /* For symmetry */
+ (void) fputs("Malloc tracing stopped\n", _malloc_statsfile);
+ _malloc_tracing = 0;
+ }
+ (void) fflush(_malloc_statsfile);
+}
+
diff --git a/lib/libmalloc/sptree.c b/lib/libmalloc/sptree.c
new file mode 100644
index 000000000000..e7d28f00ab26
--- /dev/null
+++ b/lib/libmalloc/sptree.c
@@ -0,0 +1,763 @@
+/*
+ * This file contains a few splay tree routines snarfed from David
+ * Brower's package, with globals renamed to keep them internal to the
+ * malloc, and not clash with similar routines that the application may
+ * use. The comments have been left with the original names - most of
+ * the renaming just involved prepending an __ before the name -
+ * spinstall got remapped to __spadd. Function prototypes added for
+ * external declarations. - Mark Moraes.
+ */
+/*
+ * spdaveb.c -- daveb's new splay tree functions.
+ *
+ * The functions in this file provide an interface that is nearly
+ * the same as the hash library I swiped from mkmf, allowing
+ * replacement of one by the other. Hey, it worked for me!
+ *
+ * splookup() -- given a key, find a node in a tree.
+ * spinstall() -- install an item in the tree, overwriting existing value.
+ * spfhead() -- fast (non-splay) find the first node in a tree.
+ * spscan() -- forward scan tree from the head.
+ * spfnext() -- non-splaying next.
+ * spstats() -- make char string of stats for a tree.
+ *
+ * Written by David Brower, daveb@rtech.uucp 1/88.
+ */
+/*LINTLIBRARY*/
+
+#if defined(__STDC__) && defined(ANSI_TYPES)
+#include <stddef.h>
+#endif
+#include <stdio.h>
+
+#include "defs.h"
+
+# define COMPARE(a,b) (((char *) (a)) - ((char *) (b)))
+
+# include "sptree.h"
+
+/* insert item into the tree */
+static SPBLK * spenq proto((SPBLK *, SPTREE *));
+/* return and remove lowest item in subtree */
+static SPBLK * spdeq proto((SPBLK **));
+/* reorganize tree */
+static void splay proto((SPBLK *, SPTREE *));
+/* fast non-splaying head */
+static SPBLK * spfhead proto((SPTREE *));
+/* fast non-splaying next */
+static SPBLK * spfnext proto((SPBLK *));
+
+/* USER SUPPLIED! */
+
+extern univptr_t emalloc proto((size_t));
+
+
+/*----------------
+ *
+ * splookup() -- given key, find a node in a tree.
+ *
+ * Splays the found node to the root.
+ */
+SPBLK *
+__splookup( key, q )
+REGISTER univptr_t key;
+REGISTER SPTREE *q;
+
+{
+ REGISTER SPBLK * n;
+ REGISTER int Sct;
+ REGISTER int c;
+
+ /* find node in the tree */
+ n = q->root;
+ c = ++(q->lkpcmps);
+ q->lookups++;
+ while( n && (Sct = COMPARE( key, n->key ) ) )
+ {
+ c++;
+ n = ( Sct < 0 ) ? n->leftlink : n->rightlink;
+ }
+ q->lkpcmps = c;
+
+ /* reorganize tree around this node */
+ if( n != NULL )
+ splay( n, q );
+
+ return( n );
+}
+
+
+
+/*----------------
+ *
+ * spinstall() -- install an entry in a tree, overwriting any existing node.
+ *
+ * If the node already exists, replace its contents.
+ * If it does not exist, then allocate a new node and fill it in.
+ */
+
+SPBLK *
+__spadd( key, data, datb, q )
+
+REGISTER univptr_t key;
+REGISTER univptr_t data;
+REGISTER univptr_t datb;
+REGISTER SPTREE *q;
+
+{
+ REGISTER SPBLK *n;
+
+ if( NULL == ( n = __splookup( key, q ) ) )
+ {
+ n = (SPBLK *) emalloc( sizeof( *n ) );
+ n->key = (univptr_t) key;
+ n->leftlink = NULL;
+ n->rightlink = NULL;
+ n->uplink = NULL;
+ (void) spenq( n, q );
+ }
+
+ n->data = data;
+ n->datb = datb;
+
+ return( n );
+}
+
+
+
+
+/*----------------
+ *
+ * spfhead() -- return the "lowest" element in the tree.
+ *
+ * returns a reference to the head event in the event-set q.
+ * avoids splaying but just searches for and returns a pointer to
+ * the bottom of the left branch.
+ */
+static SPBLK *
+spfhead( q )
+
+REGISTER SPTREE * q;
+
+{
+ REGISTER SPBLK * x;
+
+ if( NULL != ( x = q->root ) )
+ while( x->leftlink != NULL )
+ x = x->leftlink;
+
+ return( x );
+
+} /* spfhead */
+
+
+
+/*----------------
+ *
+ * spscan() -- apply a function to nodes in ascending order.
+ *
+ * if n is given, start at that node, otherwise start from
+ * the head.
+ */
+void
+__spscan( f, n, q )
+REGISTER void (*f)();
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+{
+ REGISTER SPBLK * x;
+
+ for( x = n != NULL ? n : spfhead( q ); x != NULL ; x = spfnext( x ) )
+ (*f)( x );
+}
+
+
+/*----------------
+ *
+ * spfnext() -- fast return next higer item in the tree, or NULL.
+ *
+ * return the successor of n in q, represented as a splay tree.
+ * This is a fast (on average) version that does not splay.
+ */
+static SPBLK *
+spfnext( n )
+
+REGISTER SPBLK * n;
+
+{
+ REGISTER SPBLK * next;
+ REGISTER SPBLK * x;
+
+ /* a long version, avoids splaying for fast average,
+ * poor amortized bound
+ */
+
+ if( n == NULL )
+ return( n );
+
+ x = n->rightlink;
+ if( x != NULL )
+ {
+ while( x->leftlink != NULL )
+ x = x->leftlink;
+ next = x;
+ }
+ else /* x == NULL */
+ {
+ x = n->uplink;
+ next = NULL;
+ while( x != NULL )
+ {
+ if( x->leftlink == n )
+ {
+ next = x;
+ x = NULL;
+ }
+ else
+ {
+ n = x;
+ x = n->uplink;
+ }
+ }
+ }
+
+ return( next );
+
+} /* spfnext */
+
+
+char *
+__spstats( q )
+SPTREE *q;
+{
+ static char buf[ 128 ];
+ float llen;
+ float elen;
+ float sloops;
+
+ if( q == NULL )
+ return("");
+
+ llen = q->lookups ? (float)q->lkpcmps / q->lookups : 0;
+ elen = q->enqs ? (float)q->enqcmps/q->enqs : 0;
+ sloops = q->splays ? (float)q->splayloops/q->splays : 0;
+
+ (void) sprintf(buf, "f(%d %4.2f) i(%d %4.2f) s(%d %4.2f)",
+ q->lookups, llen, q->enqs, elen, q->splays, sloops );
+
+ return buf;
+}
+
+/*
+ spaux.c: This code implements the following operations on an event-set
+ or priority-queue implemented using splay trees:
+
+ spdelete( n, q ) n is removed from q.
+
+ In the above, n and np are pointers to single items (type
+ SPBLK *); q is an event-set (type SPTREE *),
+ The type definitions for these are taken
+ from file sptree.h. All of these operations rest on basic
+ splay tree operations from file sptree.c.
+
+ The basic splay tree algorithms were originally presented in:
+
+ Self Adjusting Binary Trees,
+ by D. D. Sleator and R. E. Tarjan,
+ Proc. ACM SIGACT Symposium on Theory
+ of Computing (Boston, Apr 1983) 235-245.
+
+ The operations in this package supplement the operations from
+ file splay.h to provide support for operations typically needed
+ on the pending event set in discrete event simulation. See, for
+ example,
+
+ Introduction to Simula 67,
+ by Gunther Lamprecht, Vieweg & Sohn, Braucschweig, Wiesbaden, 1981.
+ (Chapter 14 contains the relevant discussion.)
+
+ Simula Begin,
+ by Graham M. Birtwistle, et al, Studentlitteratur, Lund, 1979.
+ (Chapter 9 contains the relevant discussion.)
+
+ Many of the routines in this package use the splay procedure,
+ for bottom-up splaying of the queue. Consequently, item n in
+ delete and item np in all operations listed above must be in the
+ event-set prior to the call or the results will be
+ unpredictable (eg: chaos will ensue).
+
+ Note that, in all cases, these operations can be replaced with
+ the corresponding operations formulated for a conventional
+ lexicographically ordered tree. The versions here all use the
+ splay operation to ensure the amortized bounds; this usually
+ leads to a very compact formulation of the operations
+ themselves, but it may slow the average performance.
+
+ Alternative versions based on simple binary tree operations are
+ provided (commented out) for head, next, and prev, since these
+ are frequently used to traverse the entire data structure, and
+ the cost of traversal is independent of the shape of the
+ structure, so the extra time taken by splay in this context is
+ wasted.
+
+ This code was written by:
+ Douglas W. Jones with assistance from Srinivas R. Sataluri
+
+ Translated to C by David Brower, daveb@rtech.uucp
+
+ Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
+ handling one-node trees. I botched the pascal translation of
+ a VAR parameter. Changed interface, so callers must also be
+ corrected to pass the node by address rather than value.
+ Mon Apr 3 15:18:32 PDT 1989 (daveb)
+ Apply fix supplied by Mark Moraes <moraes@csri.toronto.edu> to
+ spdelete(), which dropped core when taking out the last element
+ in a subtree -- that is, when the right subtree was empty and
+ the leftlink was also null, it tried to take out the leftlink's
+ uplink anyway.
+ */
+/*----------------
+ *
+ * spdelete() -- Delete node from a tree.
+ *
+ * n is deleted from q; the resulting splay tree has been splayed
+ * around its new root, which is the successor of n
+ *
+ */
+void
+__spdelete( n, q )
+
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+
+{
+ REGISTER SPBLK * x;
+
+ splay( n, q );
+ x = spdeq( &q->root->rightlink );
+ if( x == NULL ) /* empty right subtree */
+ {
+ q->root = q->root->leftlink;
+ if (q->root) q->root->uplink = NULL;
+ }
+ else /* non-empty right subtree */
+ {
+ x->uplink = NULL;
+ x->leftlink = q->root->leftlink;
+ x->rightlink = q->root->rightlink;
+ if( x->leftlink != NULL )
+ x->leftlink->uplink = x;
+ if( x->rightlink != NULL )
+ x->rightlink->uplink = x;
+ q->root = x;
+ }
+
+} /* spdelete */
+
+
+/*
+ *
+ * sptree.c: The following code implements the basic operations on
+ * an event-set or priority-queue implemented using splay trees:
+ *
+ * SPTREE *spinit( compare ) Make a new tree
+ * SPBLK *spenq( n, q ) Insert n in q after all equal keys.
+ * SPBLK *spdeq( np ) Return first key under *np, removing it.
+ * void splay( n, q ) n (already in q) becomes the root.
+ *
+ * In the above, n points to an SPBLK type, while q points to an
+ * SPTREE.
+ *
+ * The implementation used here is based on the implementation
+ * which was used in the tests of splay trees reported in:
+ *
+ * An Empirical Comparison of Priority-Queue and Event-Set Implementations,
+ * by Douglas W. Jones, Comm. ACM 29, 4 (Apr. 1986) 300-311.
+ *
+ * The changes made include the addition of the enqprior
+ * operation and the addition of up-links to allow for the splay
+ * operation. The basic splay tree algorithms were originally
+ * presented in:
+ *
+ * Self Adjusting Binary Trees,
+ * by D. D. Sleator and R. E. Tarjan,
+ * Proc. ACM SIGACT Symposium on Theory
+ * of Computing (Boston, Apr 1983) 235-245.
+ *
+ * The enq and enqprior routines use variations on the
+ * top-down splay operation, while the splay routine is bottom-up.
+ * All are coded for speed.
+ *
+ * Written by:
+ * Douglas W. Jones
+ *
+ * Translated to C by:
+ * David Brower, daveb@rtech.uucp
+ *
+ * Thu Oct 6 12:11:33 PDT 1988 (daveb) Fixed spdeq, which was broken
+ * handling one-node trees. I botched the pascal translation of
+ * a VAR parameter.
+ */
+/*----------------
+ *
+ * spinit() -- initialize an empty splay tree
+ *
+ */
+SPTREE *
+__spinit()
+{
+ REGISTER SPTREE * q;
+
+ q = (SPTREE *) emalloc( sizeof( *q ) );
+
+ q->lookups = 0;
+ q->lkpcmps = 0;
+ q->enqs = 0;
+ q->enqcmps = 0;
+ q->splays = 0;
+ q->splayloops = 0;
+ q->root = NULL;
+ return( q );
+}
+
+/*----------------
+ *
+ * spenq() -- insert item in a tree.
+ *
+ * put n in q after all other nodes with the same key; when this is
+ * done, n will be the root of the splay tree representing q, all nodes
+ * in q with keys less than or equal to that of n will be in the
+ * left subtree, all with greater keys will be in the right subtree;
+ * the tree is split into these subtrees from the top down, with rotations
+ * performed along the way to shorten the left branch of the right subtree
+ * and the right branch of the left subtree
+ */
+static SPBLK *
+spenq( n, q )
+REGISTER SPBLK * n;
+REGISTER SPTREE * q;
+{
+ REGISTER SPBLK * left; /* the rightmost node in the left tree */
+ REGISTER SPBLK * right; /* the leftmost node in the right tree */
+ REGISTER SPBLK * next; /* the root of the unsplit part */
+ REGISTER SPBLK * temp;
+
+ REGISTER univptr_t key;
+
+ q->enqs++;
+ n->uplink = NULL;
+ next = q->root;
+ q->root = n;
+ if( next == NULL ) /* trivial enq */
+ {
+ n->leftlink = NULL;
+ n->rightlink = NULL;
+ }
+ else /* difficult enq */
+ {
+ key = n->key;
+ left = n;
+ right = n;
+
+ /* n's left and right children will hold the right and left
+ splayed trees resulting from splitting on n->key;
+ note that the children will be reversed! */
+
+ q->enqcmps++;
+ if ( COMPARE( next->key, key ) > 0 )
+ goto two;
+
+ one: /* assert next->key <= key */
+
+ do /* walk to the right in the left tree */
+ {
+ temp = next->rightlink;
+ if( temp == NULL )
+ {
+ left->rightlink = next;
+ next->uplink = left;
+ right->leftlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+ if( COMPARE( temp->key, key ) > 0 )
+ {
+ left->rightlink = next;
+ next->uplink = left;
+ left = next;
+ next = temp;
+ goto two; /* change sides */
+ }
+
+ next->rightlink = temp->leftlink;
+ if( temp->leftlink != NULL )
+ temp->leftlink->uplink = next;
+ left->rightlink = temp;
+ temp->uplink = left;
+ temp->leftlink = next;
+ next->uplink = temp;
+ left = temp;
+ next = temp->rightlink;
+ if( next == NULL )
+ {
+ right->leftlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+
+ } while( COMPARE( next->key, key ) <= 0 ); /* change sides */
+
+ two: /* assert next->key > key */
+
+ do /* walk to the left in the right tree */
+ {
+ temp = next->leftlink;
+ if( temp == NULL )
+ {
+ right->leftlink = next;
+ next->uplink = right;
+ left->rightlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+ if( COMPARE( temp->key, key ) <= 0 )
+ {
+ right->leftlink = next;
+ next->uplink = right;
+ right = next;
+ next = temp;
+ goto one; /* change sides */
+ }
+ next->leftlink = temp->rightlink;
+ if( temp->rightlink != NULL )
+ temp->rightlink->uplink = next;
+ right->leftlink = temp;
+ temp->uplink = right;
+ temp->rightlink = next;
+ next->uplink = temp;
+ right = temp;
+ next = temp->leftlink;
+ if( next == NULL )
+ {
+ left->rightlink = NULL;
+ goto done; /* job done, entire tree split */
+ }
+
+ q->enqcmps++;
+
+ } while( COMPARE( next->key, key ) > 0 ); /* change sides */
+
+ goto one;
+
+ done: /* split is done, branches of n need reversal */
+
+ temp = n->leftlink;
+ n->leftlink = n->rightlink;
+ n->rightlink = temp;
+ }
+
+ return( n );
+
+} /* spenq */
+
+
+/*----------------
+ *
+ * spdeq() -- return and remove head node from a subtree.
+ *
+ * remove and return the head node from the node set; this deletes
+ * (and returns) the leftmost node from q, replacing it with its right
+ * subtree (if there is one); on the way to the leftmost node, rotations
+ * are performed to shorten the left branch of the tree
+ */
+static SPBLK *
+spdeq( np )
+
+SPBLK **np; /* pointer to a node pointer */
+
+{
+ REGISTER SPBLK * deq; /* one to return */
+ REGISTER SPBLK * next; /* the next thing to deal with */
+ REGISTER SPBLK * left; /* the left child of next */
+ REGISTER SPBLK * farleft; /* the left child of left */
+ REGISTER SPBLK * farfarleft; /* the left child of farleft */
+
+ if( np == NULL || *np == NULL )
+ {
+ deq = NULL;
+ }
+ else
+ {
+ next = *np;
+ left = next->leftlink;
+ if( left == NULL )
+ {
+ deq = next;
+ *np = next->rightlink;
+
+ if( *np != NULL )
+ (*np)->uplink = NULL;
+
+ }
+ else for(;;) /* left is not null */
+ {
+ /* next is not it, left is not NULL, might be it */
+ farleft = left->leftlink;
+ if( farleft == NULL )
+ {
+ deq = left;
+ next->leftlink = left->rightlink;
+ if( left->rightlink != NULL )
+ left->rightlink->uplink = next;
+ break;
+ }
+
+ /* next, left are not it, farleft is not NULL, might be it */
+ farfarleft = farleft->leftlink;
+ if( farfarleft == NULL )
+ {
+ deq = farleft;
+ left->leftlink = farleft->rightlink;
+ if( farleft->rightlink != NULL )
+ farleft->rightlink->uplink = left;
+ break;
+ }
+
+ /* next, left, farleft are not it, rotate */
+ next->leftlink = farleft;
+ farleft->uplink = next;
+ left->leftlink = farleft->rightlink;
+ if( farleft->rightlink != NULL )
+ farleft->rightlink->uplink = left;
+ farleft->rightlink = left;
+ left->uplink = farleft;
+ next = farleft;
+ left = farfarleft;
+ }
+ }
+
+ return( deq );
+
+} /* spdeq */
+
+
+/*----------------
+ *
+ * splay() -- reorganize the tree.
+ *
+ * the tree is reorganized so that n is the root of the
+ * splay tree representing q; results are unpredictable if n is not
+ * in q to start with; q is split from n up to the old root, with all
+ * nodes to the left of n ending up in the left subtree, and all nodes
+ * to the right of n ending up in the right subtree; the left branch of
+ * the right subtree and the right branch of the left subtree are
+ * shortened in the process
+ *
+ * this code assumes that n is not NULL and is in q; it can sometimes
+ * detect n not in q and complain
+ */
+
+static void
+splay( n, q )
+
+REGISTER SPBLK * n;
+SPTREE * q;
+
+{
+ REGISTER SPBLK * up; /* points to the node being dealt with */
+ REGISTER SPBLK * prev; /* a descendent of up, already dealt with */
+ REGISTER SPBLK * upup; /* the parent of up */
+ REGISTER SPBLK * upupup; /* the grandparent of up */
+ REGISTER SPBLK * left; /* the top of left subtree being built */
+ REGISTER SPBLK * right; /* the top of right subtree being built */
+
+ left = n->leftlink;
+ right = n->rightlink;
+ prev = n;
+ up = prev->uplink;
+
+ q->splays++;
+
+ while( up != NULL )
+ {
+ q->splayloops++;
+
+ /* walk up the tree towards the root, splaying all to the left of
+ n into the left subtree, all to right into the right subtree */
+
+ upup = up->uplink;
+ if( up->leftlink == prev ) /* up is to the right of n */
+ {
+ if( upup != NULL && upup->leftlink == up ) /* rotate */
+ {
+ upupup = upup->uplink;
+ upup->leftlink = up->rightlink;
+ if( upup->leftlink != NULL )
+ upup->leftlink->uplink = upup;
+ up->rightlink = upup;
+ upup->uplink = up;
+ if( upupup == NULL )
+ q->root = up;
+ else if( upupup->leftlink == upup )
+ upupup->leftlink = up;
+ else
+ upupup->rightlink = up;
+ up->uplink = upupup;
+ upup = upupup;
+ }
+ up->leftlink = right;
+ if( right != NULL )
+ right->uplink = up;
+ right = up;
+
+ }
+ else /* up is to the left of n */
+ {
+ if( upup != NULL && upup->rightlink == up ) /* rotate */
+ {
+ upupup = upup->uplink;
+ upup->rightlink = up->leftlink;
+ if( upup->rightlink != NULL )
+ upup->rightlink->uplink = upup;
+ up->leftlink = upup;
+ upup->uplink = up;
+ if( upupup == NULL )
+ q->root = up;
+ else if( upupup->rightlink == upup )
+ upupup->rightlink = up;
+ else
+ upupup->leftlink = up;
+ up->uplink = upupup;
+ upup = upupup;
+ }
+ up->rightlink = left;
+ if( left != NULL )
+ left->uplink = up;
+ left = up;
+ }
+ prev = up;
+ up = upup;
+ }
+
+# ifdef SPLAYDEBUG
+ if( q->root != prev )
+ {
+/* fprintf(stderr, " *** bug in splay: n not in q *** " ); */
+ abort();
+ }
+# endif
+
+ n->leftlink = left;
+ n->rightlink = right;
+ if( left != NULL )
+ left->uplink = n;
+ if( right != NULL )
+ right->uplink = n;
+ q->root = n;
+ n->uplink = NULL;
+
+} /* splay */
+
diff --git a/lib/libmalloc/sptree.h b/lib/libmalloc/sptree.h
new file mode 100644
index 000000000000..ea5a260d18df
--- /dev/null
+++ b/lib/libmalloc/sptree.h
@@ -0,0 +1,65 @@
+/*
+** sptree.h: The following type declarations provide the binary tree
+** representation of event-sets or priority queues needed by splay trees
+**
+** assumes that data and datb will be provided by the application
+** to hold all application specific information
+**
+** assumes that key will be provided by the application, comparable
+** with the compare function applied to the addresses of two keys.
+*/
+
+# ifndef SPTREE_H
+# define SPTREE_H
+
+typedef struct _spblk
+{
+ struct _spblk * leftlink;
+ struct _spblk * rightlink;
+ struct _spblk * uplink;
+
+ univptr_t key; /* formerly time/timetyp */
+ univptr_t data; /* formerly aux/auxtype */
+ univptr_t datb;
+} SPBLK;
+
+typedef struct
+{
+ SPBLK * root; /* root node */
+
+ /* Statistics, not strictly necessary, but handy for tuning */
+
+ int lookups; /* number of splookup()s */
+ int lkpcmps; /* number of lookup comparisons */
+
+ int enqs; /* number of spenq()s */
+ int enqcmps; /* compares in spenq */
+
+ int splays;
+ int splayloops;
+
+} SPTREE;
+
+#if defined(__STDC__)
+#define __proto(x) x
+#else
+#define __proto(x) ()
+#endif
+
+/* sptree.c */
+/* init tree */
+extern SPTREE * __spinit __proto((void));
+/* find key in a tree */
+extern SPBLK * __splookup __proto((univptr_t, SPTREE *));
+/* enter an item, allocating or replacing */
+extern SPBLK * __spadd __proto((univptr_t, univptr_t, univptr_t, SPTREE *));
+/* scan forward through tree */
+extern void __spscan __proto((void (*) __proto((SPBLK *)), SPBLK *, SPTREE *));
+/* return tree statistics */
+extern char *__spstats __proto((SPTREE *));
+/* delete node from tree */
+extern void __spdelete __proto((SPBLK *, SPTREE *));
+
+#undef __proto
+
+# endif /* SPTREE_H */
diff --git a/lib/libmalloc/stats.c b/lib/libmalloc/stats.c
new file mode 100644
index 000000000000..05ebb48ad869
--- /dev/null
+++ b/lib/libmalloc/stats.c
@@ -0,0 +1,38 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: stats.c,v 1.1 1994/03/06 22:59:53 nate Exp $")
+
+/*
+ * Dumps the distribution of allocated sizes we've gathered so far
+ */
+void
+mal_statsdump(fd)
+FILE *fd;
+{
+#ifdef PROFILESIZES
+ int i;
+ char buf[128];
+
+ for (i = 1; i < MAXPROFILESIZE; i++) {
+ if(_malloc_scount[i] > 0) {
+ (void) sprintf(buf, "%lu: %lu\n",(ulong)i*sizeof(Word),
+ (ulong) _malloc_scount[i]);
+ (void) fputs(buf, fd);
+ _malloc_scount[i] = 0;
+ }
+ }
+ if (_malloc_scount[0] > 0) {
+ (void) sprintf(buf, ">= %lu: %lu\n",
+ (ulong) MAXPROFILESIZE * sizeof(Word),
+ (ulong) _malloc_scount[0]);
+ (void) fputs(buf, fd);
+ _malloc_scount[0] = 0;
+ }
+ (void) fflush(fd);
+#endif /* PROFILESIZES */
+}
diff --git a/lib/libmalloc/strdup.c b/lib/libmalloc/strdup.c
new file mode 100644
index 000000000000..0e4a6bf24bb2
--- /dev/null
+++ b/lib/libmalloc/strdup.c
@@ -0,0 +1,26 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+
+RCSID("$Id: strdup.c,v 1.1 1994/03/06 22:59:54 nate Exp $")
+
+/*
+ * makes a copy of a null terminated string in malloc'ed storage.
+ * returns null if it fails.
+ */
+char *
+strdup(s)
+const char *s;
+{
+ char *cp;
+
+ if (s) {
+ cp = (char *) malloc((unsigned) (strlen(s)+1));
+ if (cp)
+ (void) strcpy(cp, s);
+ } else
+ cp = (char *) NULL;
+ return(cp);
+}
diff --git a/lib/libmalloc/strsave.c b/lib/libmalloc/strsave.c
new file mode 100644
index 000000000000..79fe856c4e45
--- /dev/null
+++ b/lib/libmalloc/strsave.c
@@ -0,0 +1,21 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+
+RCSID("$Id: strsave.c,v 1.1 1994/03/06 22:59:55 nate Exp $")
+
+/*
+ * makes a copy of a null terminated string in malloc'ed storage. Dies
+ * if enough memory isn't available or there is a malloc error
+ */
+char *
+strsave(s)
+const char *s;
+{
+ if (s)
+ return(strcpy(emalloc((size_t) (strlen(s)+1)),s));
+ else
+ return((char *) NULL);
+}
diff --git a/lib/libmalloc/tests/munge.sh b/lib/libmalloc/tests/munge.sh
new file mode 100755
index 000000000000..d9a23309c11c
--- /dev/null
+++ b/lib/libmalloc/tests/munge.sh
@@ -0,0 +1,40 @@
+#! /bin/sh
+# takes output of testrun and massages into columnar form for easier
+# evaluation and graphing
+cat $* | tr ',' ' ' |
+ awk 'BEGIN {
+ printf " Maxtime Maxsize Maxlife Sbrked Alloced Wastage";
+ printf " Real User Sys\n";
+ }
+ $1 == "Maxtime" {
+ if (t != 0) {
+ printf "%8d%8d%8d%8d%8d %7.2f", t, s, l, sb, ma, w;
+ printf " %7.1f %7.1f %7.1f\n", mr, mu, ms;
+ }
+ t = $3;
+ s = $6;
+ l = $9;
+ mr = 100000;
+ mu = 100000;
+ ms = 100000;
+ next;
+ }
+ $1 == "Sbrked" {
+ sb = $2;
+ ma = $4;
+ w = $6;
+ next;
+ }
+ $2 == "real" {
+ if ($1 < mr) mr = $1;
+ if ($3 < mu) mu = $3;
+ if ($5 < ms) ms = $5;
+ next;
+ }
+ END {
+ if (t != 0) {
+ printf "%8d%8d%8d%8d%8d %7.2f", t, s, l, sb, ma, w;
+ printf " %7.1f %7.1f %7.1f\n", mr, mu, ms;
+ }
+ }
+ '
diff --git a/lib/libmalloc/tests/plot.sh b/lib/libmalloc/tests/plot.sh
new file mode 100755
index 000000000000..74a8c8edd52e
--- /dev/null
+++ b/lib/libmalloc/tests/plot.sh
@@ -0,0 +1,81 @@
+#! /bin/sh
+# Things like
+# '-s 10 file...' should plot Maxlife vs Wastage, Real, user + sys for all
+# file for Maxsize == 10.
+# '-l 10 file...' should plot Maxsize vs ... for Maxlife == 10.
+usage="Usage: $0 [-s size | -l life] file..."
+case $# in
+[012])
+ echo $usage >&2
+ exit 1
+ ;;
+esac
+tmp=./tmp.$$
+case $1 in
+-s)
+ const='Maxsize'
+ indep='Maxlife'
+ units='iterations'
+ ;;
+-l)
+ const='Maxlife'
+ indep='Maxsize'
+ units='words'
+ ;;
+*)
+ echo $usage >&2
+ exit 1
+ ;;
+esac
+constval=$2
+shift
+shift
+mkdir $tmp
+for i
+do
+ base=`basename $i`
+ echo $base
+ ext=`expr "$base" : "res\.\(.*\)"`
+ awk '$1 == "Maxtime" {
+ for(i = 1; i <= NF; i++) {
+ field[$i] = i;
+ }
+ f1="'$tmp/W.$base'";
+ f2="'$tmp/R.$base'";
+ f3="'$tmp/US.$base'";
+ print "\"" "'$ext'" > f1
+ print "\"" "'$ext'" > f2
+ print "\"" "'$ext'" > f3
+ cfld=field["'$const'"];
+ cval='$constval';
+ xfld=field["'$indep'"];
+ y1=field["Wastage"];
+ y2=field["Real"];
+ y3=field["User"];
+ y4=field["Sys"];
+ }
+ $cfld == cval {
+ print $xfld, $y1 * 100 >> f1;
+ print $xfld, $y2 >> f2;
+ print $xfld, $y3 + $y4 >> f3;
+ }
+ END {
+ print "" >> f1;
+ print "" >> f2;
+ print "" >> f3;
+ }' $i
+done
+cat $tmp/W.* > $tmp/W
+rm -f $tmp/W.*
+cat $tmp/R.* > $tmp/R
+rm -f $tmp/R.*
+cat $tmp/US.* > $tmp/US
+rm -f $tmp/US.*
+cd $tmp
+xgraph -tk -bb -t "$const = $constval" -x "$indep ($units)" \
+ -y 'User + System time (seconds)' US &
+xgraph -tk -bb -t "$const = $constval" -x "$indep ($units)" \
+ -y 'Elapsed time (seconds)' R &
+xgraph -tk -bb -t "$const = $constval" -x "$indep ($units)" \
+ -y 'Wastage (percent of data segment)' W &
+
diff --git a/lib/libmalloc/tests/regress b/lib/libmalloc/tests/regress
new file mode 100755
index 000000000000..322aa608c196
--- /dev/null
+++ b/lib/libmalloc/tests/regress
@@ -0,0 +1,11 @@
+#! /bin/sh -x
+# testmalloc tests some unusual cases -- will test all branches in free,
+# which is important.
+./testmalloc $@
+# simumalloc makes a good thorough exercise for malloc and free.
+# need something for realloc, though.
+./simumalloc -t 15000 -s 1024 -l 2000 $@
+./simumalloc -t 5000 -s 512 -l 20 $@
+./simumalloc -d -t 500 -s 512 -l 20 $@
+./simumalloc -d -t 500 -s 512 -l 500 $@
+./simumalloc -d -t 500 -s 512 -a $@
diff --git a/lib/libmalloc/tests/simumalloc.c b/lib/libmalloc/tests/simumalloc.c
new file mode 100644
index 000000000000..f4607db3e453
--- /dev/null
+++ b/lib/libmalloc/tests/simumalloc.c
@@ -0,0 +1,239 @@
+/*
+ * To measure the speed of malloc - based on the algorithm described in
+ * "In Search of a Better Malloc" by David G. Korn and Kiem-Phong Vo,
+ * Usenix 1985. This is a vicious test of memory allocation, but does
+ * suffer from the problem that it asks for a uniform distribution of
+ * sizes - a more accurate distribution is a multi-normal distribution
+ * for all applications I've seen.
+ */
+/* Mark Moraes, CSRI, University of Toronto */
+#ifndef lint
+static char rcsid[] = "$Id: simumalloc.c,v 1.1 1994/03/06 23:01:46 nate Exp $";
+#endif /*lint*/
+
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * ANSI systems had better have this. Non-ANSI systems had better not
+ * complain about things that are implicitly declared int or void.
+ */
+#if defined(STDHEADERS)
+# include <stdlib.h>
+# include <unistd.h>
+#endif
+
+#include "malloc.h"
+
+char *progname;
+/* For getopt() */
+extern int getopt();
+extern int optind;
+extern char *optarg;
+
+
+int MaxTime, MaxLife, MaxSize, NumAllocs;
+
+typedef union u {
+ union u *ptr;
+ int size;
+} word;
+
+#define MAXTIME 100000
+static word *bufs[MAXTIME];
+
+unsigned long alloced = 0;
+static unsigned long maxalloced = 0;
+
+#ifdef HAVE_RANDOM
+extern long random();
+#define rnd(x) (random() % (long) (x))
+#define seedrnd(x) (srandom(x))
+#else /* ! HAVE_RANDOM */
+extern int rand();
+#define rnd(x) (rand() % (x))
+#define seedrnd(x) (srand(x))
+#endif /* HAVE_RANDOM */
+
+#ifdef MYMALLOC
+extern char * (* _malloc_memfunc)();
+#endif
+
+/*
+ * generally sprintf() to errstring and then call complain rather than
+ * use a varargs routine
+ */
+char errstring[128];
+
+/*
+ * Should probably have a more fancy version that does perror as well
+ * in a library someplace - like error()
+ */
+void
+complain(s)
+char *s;
+{
+ (void) fprintf(stderr, "%s: %s\n", progname, s);
+ exit(-1);
+}
+
+void
+usage()
+{
+ (void) fprintf(stderr, "\
+Usage: %s [-t MaxTime] [-s MaxSize] [-l MaxLife] [-m Mmapfile] [-a] [-d]\n", progname);
+ exit(-1);
+}
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int c;
+ register int t;
+ char *before, *after;
+ extern char *sbrk();
+ extern int atoi();
+ extern void freeall(), reserve();
+ unsigned long grew;
+ int alloconly = 0, use_mmap = 0, verbose = 0;
+
+ progname = argv[0] ? argv[0] : "(no-argv[0])";
+ NumAllocs = 1;
+ MaxTime = 15000;
+ MaxSize = 500;
+ MaxLife = 1000;
+ while((c = getopt(argc, argv, "n:t:s:l:dm:av")) != EOF) {
+ /* optarg has the current argument if the option was followed by ':'*/
+ switch (c) {
+ case 't':
+ MaxTime = atoi(optarg);
+ if (MaxTime < 0 || MaxTime > MAXTIME) {
+ (void) fprintf(stderr,
+ "%s: MaxTime must be > 0 and < %d\n", progname, MAXTIME);
+ exit(-1);
+ }
+ break;
+ case 's':
+ MaxSize = atoi(optarg);
+ if (MaxSize < 1)
+ complain("MaxSize must be > 0");
+ break;
+ case 'l':
+ MaxLife = atoi(optarg);
+ if (MaxLife < 0)
+ complain("MaxLife must be > 0");
+ break;
+ case 'n':
+ NumAllocs = atoi(optarg);
+ if (NumAllocs <= 0)
+ complain("NumAllocs must be > 0");
+ break;
+ case 'd':
+ /* Full heap debugging - S-L-O-W */
+#ifdef MYMALLOC
+ mal_debug(3);
+#endif
+ break;
+ case 'm':
+ use_mmap = 1;
+#ifdef MYMALLOC
+ mal_mmap(optarg);
+#else
+ complain("-m option needs CSRI malloc");
+#endif
+ break;
+ case 'a':
+ /* Only allocate -- no free */
+ alloconly = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case '?':
+ usage();
+ break;
+ }
+ }
+ /* Any filenames etc. after all the options */
+ if (optind < argc) {
+ usage();
+ }
+
+ for(t = 0; t < MaxTime; t++)
+ bufs[t] = 0;
+
+#ifdef MYMALLOC
+ before = (* _malloc_memfunc)(0);
+#else
+ before = sbrk(0);
+#endif
+ for(t = 0; t < MaxTime; t++) {
+ register int n;
+
+ for(n = rnd(NumAllocs) + 1; n > 0; n--) {
+ int s, l;
+
+ s = rnd(MaxSize) + 2;
+ l = rnd(MaxLife) + 1;
+ reserve(s, t + l);
+ }
+ if (! alloconly)
+ freeall(t);
+ }
+#ifdef MYMALLOC
+ after = (* _malloc_memfunc)(0);
+#else
+ after = sbrk(0);
+#endif
+ grew = after - before;
+ (void) sprintf(errstring, "Sbrked %ld, MaxAlloced %ld, Wastage %.2f\n",
+ grew, maxalloced * sizeof(word),
+ grew == 0 ? 0.0 :
+ (1.0 - ((double) maxalloced * sizeof(word)) / grew));
+ (void) write(1, errstring, strlen(errstring));
+#ifdef MYMALLOC
+ if (verbose)
+ (void) mal_statsdump(stderr);
+#endif
+ return 0;
+}
+
+/*
+ * Mallocs a block s words long, and adds it to the list of blocks to
+ * be freed at time tfree
+ */
+void
+reserve(s, tfree)
+int s;
+int tfree;
+{
+ word *wp;
+
+ wp = (word *) malloc(s * sizeof(word));
+ if (wp == NULL)
+ complain("Out of memory");
+ wp[0].ptr = bufs[tfree];
+ wp[1].size = s;
+ bufs[tfree] = wp;
+ alloced += s;
+ if (alloced > maxalloced)
+ maxalloced = alloced;
+}
+
+/* free all blocks whose lifetime expires at time t */
+void
+freeall(t)
+int t;
+{
+ word *wp;
+
+ wp = bufs[t];
+ while(wp != NULL) {
+ word *tmp = wp[0].ptr;
+ alloced -= wp[1].size;
+ free((char *) wp);
+ wp = tmp;
+ }
+}
diff --git a/lib/libmalloc/tests/t1.c b/lib/libmalloc/tests/t1.c
new file mode 100644
index 000000000000..7cdde93e4946
--- /dev/null
+++ b/lib/libmalloc/tests/t1.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+
+#define MAXALLOCS 1000
+#define SIZE 50
+
+extern char *sbrk();
+extern char *malloc();
+
+main()
+{
+ char *ptr[MAXALLOCS];
+ char *obrk, *nbrk;
+ int i;
+
+ obrk = sbrk(0);
+ printf("break is initially 0x%x\n", obrk);
+
+ for(i = 0; i < MAXALLOCS; i++) {
+ ptr[i] = malloc(SIZE);
+ }
+ nbrk = sbrk(0);
+ printf("break is 0x%x (%d bytes sbrked) after %d allocations of %d\n",
+ nbrk, nbrk - obrk, MAXALLOCS, SIZE);
+ for(i = 0; i < MAXALLOCS; i++) {
+ free(ptr[i]);
+ }
+ nbrk = sbrk(0);
+ printf("break is 0x%x (%d bytes sbrked) after freeing all allocations\n",
+ nbrk, nbrk - obrk);
+ fflush(stdout);
+
+ /* Should be enough memory for this without needing to sbrk */
+ (void) malloc(SIZE * (MAXALLOCS / 2));
+ nbrk = sbrk(0);
+
+ printf("break is 0x%x (%d bytes sbrked) after allocating %d\n",
+ nbrk, nbrk - obrk, SIZE * (MAXALLOCS/2));
+
+ exit(0);
+}
diff --git a/lib/libmalloc/tests/t2.c b/lib/libmalloc/tests/t2.c
new file mode 100644
index 000000000000..125c251e42b1
--- /dev/null
+++ b/lib/libmalloc/tests/t2.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+
+#define MAXALLOCS 100
+#define INC 50
+
+extern char *sbrk();
+extern char *malloc();
+
+main()
+{
+ char *ptr1, *ptr2;
+ char *obrk, *nbrk;
+ int i;
+ int small = 10;
+ int large = 128;
+
+ obrk = sbrk(0);
+ printf("break is initially 0x%x\n", obrk);
+
+ ptr1 = malloc(small);
+ ptr2 = malloc(small);
+ for(i = 0; i < MAXALLOCS; i++) {
+ (void) malloc(small);
+ free(ptr1);
+ ptr1 = malloc(large);
+ large += INC;
+ (void) malloc(small);
+ free(ptr2);
+ ptr2 = malloc(large);
+ large += INC;
+ mal_heapdump(stdout);
+ }
+ nbrk = sbrk(0);
+ printf("break is 0x%x (%d bytes sbrked)\n",
+ nbrk, nbrk - obrk);
+ exit(0);
+}
diff --git a/lib/libmalloc/tests/t3.c b/lib/libmalloc/tests/t3.c
new file mode 100644
index 000000000000..fdbc181e54f7
--- /dev/null
+++ b/lib/libmalloc/tests/t3.c
@@ -0,0 +1,110 @@
+/*
+Path: utstat!helios.physics.utoronto.ca!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!cs.utexas.edu!rice!sun-spots-request
+From: munsell!jwf@uunet.uu.net (Jim Franklin)
+Newsgroups: comp.sys.sun
+Subject: bug in SUN malloc()
+Keywords: Miscellaneous
+Message-ID: <4193@brazos.Rice.edu>
+Date: 4 Jan 90 13:05:06 GMT
+Sender: root@rice.edu
+Organization: Sun-Spots
+Lines: 95
+Approved: Sun-Spots@rice.edu
+X-Sun-Spots-Digest: Volume 9, Issue 4, message 10 of 12
+
+There is a bug in SUN's malloc() that causes it to sometimes attempt an
+sbrk() to grow the current process, even if there is a free block of the
+exact size available. The bug exists in OS 3.5 and 4.0.3, probably
+others.
+
+SUN's malloc() maintains the free list in a cartesian tree. The malloc()
+bug occurs when the root block is exactly equal in size to the requested
+allocation + alignment + overhead.
+
+malloc.c (416-427):
+> /-*
+> * ensure that at least one block is big enough to satisfy
+> * the request.
+> *-/
+>
+> if (weight(_root) <= nbytes) {
+> /-*
+> * the largest block is not enough.
+> *-/
+> if(!morecore(nbytes))
+> return 0;
+> }
+
+The '<=' should be '<'.
+
+The following 'malloc_bug' program illustrates the bug. Do a 'pstat -s'
+to see how much swap space you have, then run malloc_bug, requesting a
+chunk of memory at least 1/2 that size. E.g.,
+
+jwf@fechner #36 pstat -s
+8856k used (2120k text), 648872k free, 2776k wasted, 0k missing
+max process allocable = 229360k
+avail: 77*8192k 2*4096k 2*2048k 3*1024k 2*512k 3*256k 4*128k 3*64k 2*32k 4*16k 104*1k
+
+jwf@fechner #37 malloc_bug 200000000
+malloc_bug: requesting 200000000 bytes
+malloc_bug: got 200000000 bytes at 00022fd8
+malloc_bug: freeing 200000000 bytes
+malloc_bug: requesting 200000000 bytes
+malloc_bug: Not enough memory
+
+
+Jim Franklin, EPPS Inc., uunet!atexnet ---\
+32 Wiggins Ave., harvard!adelie ---+-- munsell!jwf
+Bedford, MA 01730 decvax!encore ---/
+(617) 276-7827
+
+
+*/
+#include <stdio.h>
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+ char *p;
+ unsigned int size;
+ int i;
+ extern char *malloc ();
+
+ if ( argc != 2 ) {
+ fprintf (stderr, "usage: malloc_bug <chunk_size>\n");
+ exit (-1);
+ }
+ size = atoi (argv[1]);
+ /* malloc our large chunk */
+
+ fprintf (stderr, "malloc_bug: requesting %d bytes\n", size);
+ p = malloc (size);
+ if ( p == NULL ) {
+ perror ("malloc_bug");
+ exit (-1);
+ }
+ fprintf (stderr, "malloc_bug: got %d bytes at %08x\n", size, p);
+
+ /* malloc a bunch of small trash to
+ try to use up any free fragments
+ near the large chunk */
+ for ( i = 0; i < 2000; i++ )
+ (void) malloc (8);
+ /* repeatedly free and malloc the
+ large chunk -- if this fails then
+ malloc is broken ... */
+ for (;;) {
+ fprintf (stderr, "malloc_bug: freeing %d bytes\n", size);
+ free (p);
+ fprintf (stderr, "malloc_bug: requesting %d bytes\n", size);
+ p = malloc (size);
+ if ( p == NULL ) {
+ perror ("malloc_bug");
+ exit (-1);
+ }
+ fprintf (stderr, "malloc_bug: got %d bytes at %08x\n", size, p);
+ }
+
+} /* main */
diff --git a/lib/libmalloc/tests/t4.c b/lib/libmalloc/tests/t4.c
new file mode 100644
index 000000000000..45161ad0cd49
--- /dev/null
+++ b/lib/libmalloc/tests/t4.c
@@ -0,0 +1,20 @@
+int
+main()
+{
+ char *cp;
+ int i;
+ int n = getpagesize();
+ extern char *malloc();
+
+ printf("pagesize = %d\n", n);
+
+ for(i = 0; i < 5; i++) {
+ cp = malloc(n);
+ printf("malloc(%d) returned 0x%x\n", n, cp);
+ cp = malloc(2*n);
+ printf("malloc(%d) returned 0x%x\n", 2*n, cp);
+ cp = malloc(4*n);
+ printf("malloc(%d) returned 0x%x\n", 4*n, cp);
+ }
+ return 0;
+}
diff --git a/lib/libmalloc/tests/t5.c b/lib/libmalloc/tests/t5.c
new file mode 100644
index 000000000000..f25df6045594
--- /dev/null
+++ b/lib/libmalloc/tests/t5.c
@@ -0,0 +1,31 @@
+/*
+ * posted to the net by someone who asked "Why is this causing malloc to
+ * dump core! Modified slightly to free the pointers, which causes my
+ * debugging malloc to find the bug. Turning on malloc_debug(2) also
+ * spots the problem.
+ */
+#include <stdio.h>
+
+int
+main()
+{
+ char *p[3], wd[128];
+ int len, i;
+ char *malloc();
+ int strlen();
+
+ strcpy(wd,"test");
+
+ for (i=0; i<3; i++) {
+ len = strlen(wd);
+ if ((p[i] = malloc(len)) == NULL) {
+ printf("ERROR: malloc failed\n");
+ exit(-1);
+ }
+ else
+ strcpy(p[i],wd);
+ }
+ for(i=0; i < 3; i++)
+ free(p[i]);
+ return 0;
+}
diff --git a/lib/libmalloc/tests/test.out b/lib/libmalloc/tests/test.out
new file mode 100644
index 000000000000..49d51d139cf6
--- /dev/null
+++ b/lib/libmalloc/tests/test.out
@@ -0,0 +1,415 @@
+Malloc tracing starting
+Test starting
+testmalloc.c:48:sbrk 4096
+heapstart 0x23108
+heapend 0x24100
++ 100 100 0x23114
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x240fc, 993 (0x3e1) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:51:+ 150 152 0x23184
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Free blk: 0x23220 to 0x240fc, 952 (0x3b8) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:54:+ 191 192 0x23228
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Free blk: 0x232ec to 0x240fc, 901 (0x385) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:57:+ 2 4 0x232f4
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Free blk: 0x232fc to 0x240fc, 897 (0x381) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:60:+ 21 24 0x23304
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:63:+ 3540 3540 0x23328
+Heap printout:
+Rover pointer is 0x0
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Allocated blk: 0x23320 to 0x240fc, 888 (0x378) words really 3540 bytes
+==============
+testmalloc.c:67:- 3540 0x23328
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Allocated blk: 0x23220 to 0x232e8, 51 (0x33) words really 191 bytes
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:69:- 192 0x23228
+Heap printout:
+Rover pointer is 0x232e8
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Free blk: 0x23220 to 0x232e8, 51 (0x33) words next=0x240fc, prev=0x240fc
+ Allocated blk: 0x232ec to 0x232f8, 4 (0x4) words really 2 bytes
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x232e8, prev=0x232e8
+==============
+testmalloc.c:71:- 4 0x232f4
+Heap printout:
+Rover pointer is 0x232f8
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x2321c, 41 (0x29) words really 150 bytes
+ Free blk: 0x23220 to 0x232f8, 55 (0x37) words next=0x240fc, prev=0x240fc
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x232f8, prev=0x232f8
+==============
+testmalloc.c:73:- 152 0x23184
+Heap printout:
+Rover pointer is 0x232f8
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x232f8, 96 (0x60) words next=0x240fc, prev=0x240fc
+ Allocated blk: 0x232fc to 0x2331c, 9 (0x9) words really 21 bytes
+ Free blk: 0x23320 to 0x240fc, 888 (0x378) words next=0x232f8, prev=0x232f8
+==============
+testmalloc.c:75:- 24 0x23304
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x240fc, 993 (0x3e1) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:77:- 100 0x23114
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x240fc, 1021 (0x3fd) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:79:+ 100 100 0x23114
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x240fc, 993 (0x3e1) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:82:+ 155 156 0x23184
+Heap printout:
+Rover pointer is 0x240fc
+Arena from 0x23104 to 0x24100, 1024 (0x400) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Free blk: 0x23224 to 0x240fc, 951 (0x3b7) words next=0x240fc, prev=0x240fc
+==============
+testmalloc.c:85:sbrk 12288
+- 12276 0x24108
++ 8192 8192 0x2322c
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Allocated blk: 0x23224 to 0x2522c, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25230 to 0x270fc, 1972 (0x7b4) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:88:+ 100 100 0x25238
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Allocated blk: 0x23224 to 0x2522c, 2051 (0x803) words really 8192 bytes
+ Allocated blk: 0x25230 to 0x2529c, 28 (0x1c) words really 100 bytes
+ Free blk: 0x252a0 to 0x270fc, 1944 (0x798) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:91:+ 29 32 0x252a8
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Allocated blk: 0x23224 to 0x2522c, 2051 (0x803) words really 8192 bytes
+ Allocated blk: 0x25230 to 0x2529c, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:94:- 8192 0x2322c
+Heap printout:
+Rover pointer is 0x2522c
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Free blk: 0x23224 to 0x2522c, 2051 (0x803) words next=0x270fc, prev=0x270fc
+ Allocated blk: 0x25230 to 0x2529c, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x2522c, prev=0x2522c
+==============
+testmalloc.c:96:- 100 0x25238
+Heap printout:
+Rover pointer is 0x2529c
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Allocated blk: 0x2317c to 0x23220, 42 (0x2a) words really 155 bytes
+ Free blk: 0x23224 to 0x2529c, 2079 (0x81f) words next=0x270fc, prev=0x270fc
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x2529c, prev=0x2529c
+==============
+testmalloc.c:98:- 156 0x23184
+Heap printout:
+Rover pointer is 0x2529c
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x2529c, 2121 (0x849) words next=0x270fc, prev=0x270fc
+ Allocated blk: 0x252a0 to 0x252c8, 11 (0xb) words really 29 bytes
+ Free blk: 0x252cc to 0x270fc, 1933 (0x78d) words next=0x2529c, prev=0x2529c
+==============
+testmalloc.c:100:- 32 0x252a8
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23178, 28 (0x1c) words really 100 bytes
+ Free blk: 0x2317c to 0x270fc, 4065 (0xfe1) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:102:- 100 0x23114
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:105:+ 1005 1008 0x23114
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Free blk: 0x23508 to 0x270fc, 3838 (0xefe) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:108:+ 8192 8192 0x23510
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x270fc, prev=0x270fc
+==============
+testmalloc.c:111:sbrk 16384
+heapend 0x2b164
++ 16000 16000 0x27178
+Heap printout:
+Rover pointer is 0x2b160
+Arena from 0x27168 to 0x2b164, 4096 (0x1000) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Free blk: 0x2affc to 0x2b160, 90 (0x5a) words next=0x270fc, prev=0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2b160, prev=0x2b160
+==============
+testmalloc.c:114:+ 29 32 0x2b004
+Heap printout:
+Rover pointer is 0x2b160
+Arena from 0x27168 to 0x2b164, 4096 (0x1000) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2b160, 79 (0x4f) words next=0x270fc, prev=0x270fc
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2b160, prev=0x2b160
+==============
+testmalloc.c:118:sbrk 77824
+- 77812 0x2b16c
++ 73727 73728 0x2b030
+- 4132 0x3c00c
+- 4036 0x2b030
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x3c000, 16387 (0x4003) words really 65536 bytes
+ Free blk: 0x3c004 to 0x3e160, 2136 (0x858) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:121:- 57524 0x2df4c
+Heap printout:
+Rover pointer is 0x3e160
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 8000 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:124:no-op
+Heap printout:
+Rover pointer is 0x3e160
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Allocated blk: 0x2310c to 0x23504, 255 (0xff) words really 1005 bytes
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:127:- 1008 0x23114
+Heap printout:
+Rover pointer is 0x23504
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x23504, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x23504
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x23504, 255 (0xff) words next=0x3e160, prev=0x2bff4
+ Allocated blk: 0x23508 to 0x25510, 2051 (0x803) words really 8192 bytes
+ Free blk: 0x25514 to 0x270fc, 1787 (0x6fb) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:129:- 8192 0x23510
+Heap printout:
+Rover pointer is 0x270fc
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Allocated blk: 0x2affc to 0x2b024, 11 (0xb) words really 29 bytes
+ Free blk: 0x2b028 to 0x2bff4, 1012 (0x3f4) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:131:- 32 0x2b004
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Allocated blk: 0x27170 to 0x2aff8, 4003 (0xfa3) words really 16000 bytes
+ Free blk: 0x2affc to 0x2bff4, 1023 (0x3ff) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:133:- 16000 0x27178
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Free blk: 0x27170 to 0x2bff4, 5026 (0x13a2) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2df40, 2003 (0x7d3) words really 7998 bytes
+ Free blk: 0x2df44 to 0x3e160, 16520 (0x4088) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:135:++ 16000 16000 0x2c000 58080 0x2fe84
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Free blk: 0x27170 to 0x2bff4, 5026 (0x13a2) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x2fe80, 4003 (0xfa3) words really 16000 bytes
+ Free blk: 0x2fe84 to 0x3e160, 14520 (0x38b8) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+testmalloc.c:138:++ 32000 32000 0x2c000 42080 0x33d04
+Heap printout:
+Rover pointer is 0x2bff4
+Arena from 0x27168 to 0x3e164, 23552 (0x5c00) words
+Next arena is 0x23104
+ Free blk: 0x27170 to 0x2bff4, 5026 (0x13a2) words next=0x3e160, prev=0x270fc
+ Allocated blk: 0x2bff8 to 0x33d00, 8003 (0x1f43) words really 32000 bytes
+ Free blk: 0x33d04 to 0x3e160, 10520 (0x2918) words next=0x270fc, prev=0x2bff4
+Arena from 0x23104 to 0x27100, 4096 (0x1000) words
+Next arena is 0x0
+ Free blk: 0x2310c to 0x270fc, 4093 (0xffd) words next=0x2bff4, prev=0x3e160
+==============
+16: 1
+36: 1
+44: 2
+112: 3
+164: 1
+168: 1
+204: 1
+1020: 1
+3552: 1
+>= 8192: 4
+Test done
diff --git a/lib/libmalloc/tests/testmalloc.c b/lib/libmalloc/tests/testmalloc.c
new file mode 100644
index 000000000000..d037b5e1bf00
--- /dev/null
+++ b/lib/libmalloc/tests/testmalloc.c
@@ -0,0 +1,182 @@
+#if defined(STDHEADERS)
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+# include <unistd.h>
+#else
+# define u_int unsigned int
+extern char *memset();
+/* ignore some complaints about declarations. get ANSI headers */
+#endif
+
+#include <stdio.h>
+#include "malloc.h"
+
+/*
+ * Things to test. 1. first malloc. 2. couple of ordinary mallocs 3.
+ * ordinary frees 4. want check a free with prev. merge, next merge,
+ * both, and no merge, and one with empty free list. 5. malloc that
+ * requires sbrk. 6. malloc that requires an sbrk, after test
+ * program does non-contiguous sbrk to check if non-contigous arenas
+ * work. 7. valloc (this should test memalign as well) We should work
+ * out tests to check boundary conditions, when blocks at the start
+ * of the arena are allocated/freed, last free block is allocated...
+ */
+
+
+char *progname;
+/* For getopt() */
+extern int getopt();
+extern int optind;
+extern char *optarg;
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ char *cp1;
+ char *cp2;
+ char *cp3;
+ char *cp4;
+ char *cp5;
+ char *cp6;
+ extern char *sbrk();
+ FILE *dumpfp = stdout;
+ int errs = 0, c;
+
+ progname = argv[0] ? argv[0] : "(no-argv[0])";
+ mal_debug(3);
+ mal_setstatsfile(stdout);
+ mal_trace(1);
+ while((c = getopt(argc, argv, "m:")) != EOF) {
+ /* optarg has the current argument if the option was followed by ':'*/
+ switch (c) {
+ case 'm':
+ mal_mmap(optarg);
+ break;
+ case '?':
+ errs++;
+ break;
+ }
+ }
+ if (optind < argc || errs > 0) {
+ fprintf(stderr, "Usage: %s [-m Mmapfile]\n", progname);
+ exit(1);
+ }
+ write(1, "Test starting\n", 14);
+ cp1 = (char *)malloc((u_int) 100);
+ (void) memset(cp1, 'A', 100);
+ mal_heapdump(dumpfp);
+ cp2 = (char *)calloc((u_int) 15, (u_int) 10);
+ (void) memset(cp2, 'B', 150);
+ mal_heapdump(dumpfp);
+ cp3 = (char *)malloc((u_int) 191);
+ (void) memset(cp3, 'C', 191);
+ mal_heapdump(dumpfp);
+ cp4 = (char *)malloc((u_int) 2);
+ (void) memset(cp4, 'D', 2);
+ mal_heapdump(dumpfp);
+ cp5 = (char *)malloc((u_int) 21);
+ (void) memset(cp5, 'E', 21);
+ mal_heapdump(dumpfp);
+ cp6 = (char *)malloc((u_int) 3540);
+ (void) memset(cp6, 'P', 3540);
+ mal_heapdump(dumpfp);
+ /* On a machine where sizeof(Word) == 4, rover should be NULL here */
+ free(cp6);
+ mal_heapdump(dumpfp);
+ free(cp3);
+ mal_heapdump(dumpfp);
+ free(cp4);
+ mal_heapdump(dumpfp);
+ free(cp2);
+ mal_heapdump(dumpfp);
+ free(cp5);
+ mal_heapdump(dumpfp);
+ free(cp1);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)malloc((u_int) 100);
+ (void) memset(cp1, 'Q', 100);
+ mal_heapdump(dumpfp);
+ cp2 = (char *)malloc((u_int) 155);
+ (void) memset(cp2, 'F', 155);
+ mal_heapdump(dumpfp);
+ cp3 = (char *)malloc((u_int) 8192);
+ (void) memset(cp3, 'G', 8192);
+ mal_heapdump(dumpfp);
+ cp4 = (char *)malloc((u_int) 100);
+ (void) memset(cp4, 'H', 100);
+ mal_heapdump(dumpfp);
+ cp5 = (char *)malloc((u_int) 29);
+ (void) memset(cp5, 'I', 29);
+ mal_heapdump(dumpfp);
+ free(cp3);
+ mal_heapdump(dumpfp);
+ free(cp4);
+ mal_heapdump(dumpfp);
+ free(cp2);
+ mal_heapdump(dumpfp);
+ free(cp5);
+ mal_heapdump(dumpfp);
+ free(cp1);
+ mal_heapdump(dumpfp);
+ cp1 = sbrk(100);
+ cp2 = (char *)malloc((u_int) 1005);
+ (void) memset(cp2, 'J', 1005);
+ mal_heapdump(dumpfp);
+ cp3 = (char *)calloc((u_int) 1024, (u_int) 8);
+ (void) memset(cp3, 'K', 8192);
+ mal_heapdump(dumpfp);
+ cp4 = (char *)malloc((u_int) 16000);
+ (void) memset(cp4, 'L', 16000);
+ mal_heapdump(dumpfp);
+ cp5 = (char *)malloc((u_int) 29);
+ (void) memset(cp5, 'M', 29);
+ mal_heapdump(dumpfp);
+ /* !! Should really test memalign with various cases */
+ cp1 = (char *)valloc((u_int) 65536);
+ (void) memset(cp1, 'N', 65536);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 8000);
+ (void) memset(cp1, 'O', 8000);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 7998);
+ (void) memset(cp1, 'T', 7998);
+ mal_heapdump(dumpfp);
+ free(cp2);
+ mal_heapdump(dumpfp);
+ free(cp3);
+ mal_heapdump(dumpfp);
+ free(cp5);
+ mal_heapdump(dumpfp);
+ free(cp4);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 16000);
+ (void) memset(cp1, 'R', 16000);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 32000);
+ (void) memset(cp1, 'S', 32000);
+ mal_heapdump(dumpfp);
+ cp1 = (char *)realloc(cp1, (u_int) 1);
+ (void) memset(cp1, 'U', 1);
+ cp2 = (char *)malloc(60000);
+ (void) memset(cp2, 'V', 60000);
+ cp3 = (char *)malloc(18000);
+ (void) memset(cp3, 'W', 18000);
+ cp4 = (char *)malloc(18000);
+ (void) memset(cp4, 'W', 18000);
+ mal_heapdump(dumpfp);
+ free(cp1);
+ mal_heapdump(dumpfp);
+ mal_statsdump(dumpfp);
+ (void) write(1, "Test done\n", 10);
+ return 0;
+}
+
+#ifdef atarist
+getpagesize()
+{
+ return 8 * 1024;
+}
+#endif
diff --git a/lib/libmalloc/tests/testmemalign.c b/lib/libmalloc/tests/testmemalign.c
new file mode 100644
index 000000000000..2a5a729a9675
--- /dev/null
+++ b/lib/libmalloc/tests/testmemalign.c
@@ -0,0 +1,16 @@
+int
+main()
+{
+ extern char *memalign();
+ char *cp;
+
+ if ((cp = memalign(2, 1024)) == 0)
+ perror("memalign 2");
+ if ((cp = memalign(3, 1024)) == 0)
+ perror("memalign 3");
+ if ((cp = memalign(4, 1024)) == 0)
+ perror("memalign 4");
+
+ return 0;
+}
+
diff --git a/lib/libmalloc/tests/testrun.sh b/lib/libmalloc/tests/testrun.sh
new file mode 100755
index 000000000000..9da9568d2cdf
--- /dev/null
+++ b/lib/libmalloc/tests/testrun.sh
@@ -0,0 +1,28 @@
+#! /bin/sh
+time=time
+awk 'BEGIN {
+ maxtime = 15000;
+ maxsize = 610; isize = 50;
+ maxlife = 8010; ilife = 100;
+ hdrfmt = "echo \"Maxtime = %d, Maxsize = %d, Maxlife = %d\"\n";
+ fmt = "$time $cmd -t %d -s %d -l %d\n";
+ }
+ END {
+ for (i = 10; i < maxsize; i += isize) {
+ for (j = 10; j < maxlife; j += ilife) {
+ printf hdrfmt, maxtime, i, j;
+ printf fmt, maxtime, i, j;
+ printf fmt, maxtime, i, j;
+ printf fmt, maxtime, i, j;
+ }
+ }
+ }' /dev/null > /tmp/runs.$$
+for i
+do
+ ext=`expr "$i" : "simumalloc.exe\(.*\)"`
+ date
+ echo $i
+ cmd="./$i"
+ . /tmp/runs.$$ > times$ext 2>&1
+ date
+done
diff --git a/lib/libmalloc/tests/testsbrk.c b/lib/libmalloc/tests/testsbrk.c
new file mode 100644
index 000000000000..ff6c68d1bb45
--- /dev/null
+++ b/lib/libmalloc/tests/testsbrk.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+int incr = 201;
+char *cp;
+int i;
+
+main()
+{
+ extern char *sbrk();
+ int sz;
+
+ sz = getpagesize();
+ printf("pagesize is 0x%08x (%d)\n", sz, sz);
+ for(i = 0; i < 1000; i++) {
+ if ((cp = sbrk(incr)) == (char *) -1) {
+ fprintf(stderr, "Cannot sbrk further\n");
+ exit(-1);
+ }
+ printf("segment starts at 0x%08x, ends at 0x%08x\n", (int) cp,
+ (int) (cp + incr - 1));
+ }
+}
diff --git a/lib/libmalloc/tests/teststomp.c b/lib/libmalloc/tests/teststomp.c
new file mode 100644
index 000000000000..c591921144a9
--- /dev/null
+++ b/lib/libmalloc/tests/teststomp.c
@@ -0,0 +1,34 @@
+#if defined(STDHEADERS)
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+# include <unistd.h>
+#else
+# define u_int unsigned int
+extern char *memset();
+/* ignore some complaints about declarations. get ANSI headers */
+#endif
+
+#include <stdio.h>
+#include "malloc.h"
+
+int
+main(argc, argv)
+char **argv;
+int argc;
+{
+ char *cp;
+ int nbytes;
+
+ if (argc != 2) {
+ (void) fprintf(stderr, "Usage: %s nbytes\n", argv[0]);
+ exit(1);
+ }
+
+ nbytes = atoi(argv[1]);
+ cp = (char *) malloc(nbytes);
+ cp[nbytes] = 'a';
+ mal_verify(1);
+ /* We aren't going to get here, y'know... */
+ return 0;
+}
diff --git a/lib/libmalloc/trace.h b/lib/libmalloc/trace.h
new file mode 100644
index 000000000000..c3826dceca4b
--- /dev/null
+++ b/lib/libmalloc/trace.h
@@ -0,0 +1,19 @@
+#ifndef __TRACE_H__
+#define __TRACE_H__
+extern void __m_install_record proto((univptr_t, const char *));
+extern void __m_delete_record proto((univptr_t));
+
+#define RECORD_FILE_AND_LINE(addr, fname, linenum) \
+ if (_malloc_leaktrace) { \
+ (void) sprintf(_malloc_statsbuf, "%s:%d:", fname, linenum); \
+ __m_install_record(addr, _malloc_statsbuf); \
+ } else \
+ _malloc_leaktrace += 0
+
+#define DELETE_RECORD(addr) \
+ if (_malloc_leaktrace) \
+ __m_delete_record(addr); \
+ else \
+ _malloc_leaktrace += 0
+
+#endif /* __TRACE_H__ */ /* Do not add anything after this line */
diff --git a/lib/libmalloc/verify.c b/lib/libmalloc/verify.c
new file mode 100644
index 000000000000..9fbad097b986
--- /dev/null
+++ b/lib/libmalloc/verify.c
@@ -0,0 +1,81 @@
+/* Author: Mark Moraes <moraes@csri.toronto.edu> */
+
+/*LINTLIBRARY*/
+
+#include "defs.h"
+#include "globals.h"
+
+RCSID("$Id: verify.c,v 1.1 1994/03/06 22:59:57 nate Exp $")
+
+/*
+ * Goes through the entire heap checking all pointers, tags for
+ * consistency. Should catch most casual heap corruption (overwriting
+ * the end of a malloc'ed chunk, etc..) Nonetheless, heap corrupters
+ * tend to be devious and ingenious in ways they corrupt heaps (Believe
+ * me, I know:-). We should probably do the same thing if DEBUG is not
+ * defined, but return 0 instead of aborting. If fullcheck is non-zero,
+ * it also checks that free blocks contain the magic pattern written
+ * into them when they were freed to make sure the program is not still
+ * trying to access those blocks.
+ */
+int
+mal_verify(fullcheck)
+int fullcheck;
+{
+#ifdef DEBUG
+ REGISTER Word *ptr;
+ REGISTER Word *blk;
+ REGISTER Word *blkend;
+
+ if (_malloc_loword == NULL) /* Nothing malloc'ed yet */
+ return(0);
+
+ if (_malloc_rover != NULL) {
+ ASSERT(PTR_IN_HEAP(_malloc_rover),
+ "corrupt ROVER pointer found by mal_verify()");
+ ASSERT(VALID_END_SIZE_FIELD(_malloc_rover),
+ "corrupt ROVER SIZE field found by mal_verify()");
+ ASSERT(VALID_NEXT_PTR(_malloc_rover),
+ "corrupt ROVER NEXT pointer found by mal_verify()");
+ ASSERT(VALID_PREV_PTR(_malloc_rover),
+ "corrupt ROVER PREV pointer found by mal_verify()");
+ }
+ for(ptr = _malloc_mem; ptr != NULL; ptr = ptr->next) {
+ /*
+ * Check arena bounds - not same as checking block tags,
+ * despite similar appearance of the test
+ */
+ ASSERT(SIZEFIELD(ptr+1) == SIZEFIELD(ptr + SIZE(ptr+1)),
+ "corrupt malloc arena found by mal_verify");
+ blkend = ptr + SIZE(ptr + 1);
+ for(blk = ptr + ARENASTART; blk < blkend; blk += SIZE(blk)) {
+ ASSERT(PTR_IN_HEAP(blk), "corrupt pointer found by mal_verify()");
+ ASSERT(VALID_START_SIZE_FIELD(blk),
+ "corrupt SIZE field found by mal_verify()");
+ if (TAG(blk) == FREE) {
+ ASSERT(VALID_NEXT_PTR(blk + FREESIZE(blk) - 1),
+ "corrupt NEXT pointer found by mal_verify()");
+ ASSERT(VALID_PREV_PTR(blk + FREESIZE(blk) - 1),
+ "corrupt PREV pointer found by mal_verify()");
+ if (fullcheck) {
+ /* Make sure all free blocks are filled with FREEMAGIC */
+ int i, n;
+ char *cp;
+
+ n = (SIZE(blk) - FREE_OVERHEAD) *
+ sizeof(Word);
+ cp = (char *) (blk + FREEHEADERWORDS);
+ for (i = 0; i < n; i++, cp++) {
+ ASSERT(*cp == FREEMAGIC,
+ "corrupt free block found by mal_verify()");
+ }
+ }
+ } else {
+ ASSERT(VALID_MAGIC(blk),
+ "overwritten end of block found by mal_verify()");
+ }
+ }
+ }
+#endif /* DEBUG */
+ return(0);
+}
diff --git a/lib/libmalloc/version.c b/lib/libmalloc/version.c
new file mode 100644
index 000000000000..5752fb2c4220
--- /dev/null
+++ b/lib/libmalloc/version.c
@@ -0,0 +1 @@
+char *_malloc_version = "CSRI, University of Toronto Malloc Version 1.13beta";
diff --git a/lib/libpthread/include/stdio.h b/lib/libpthread/include/stdio.h
index 70a4265ae2ab..7e58f48875b5 100644
--- a/lib/libpthread/include/stdio.h
+++ b/lib/libpthread/include/stdio.h
@@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* from: @(#)stdio.h 5.17 (Berkeley) 6/3/91
- * $Id: stdio.h,v 1.1 1994/01/30 04:22:49 proven Exp $
+ * $Id: stdio.h,v 1.2 1994/04/09 15:34:53 ats Exp $
*/
#ifndef _STDIO_H_
@@ -296,6 +296,8 @@ __BEGIN_DECLS
int __srget __P((FILE *));
int __svfscanf __P((FILE *, const char *, va_list));
int __swbuf __P((int, FILE *));
+void flockfile(FILE *);
+void funlockfile(FILE *);
__END_DECLS
/*
diff --git a/lib/libpthread/stdio/fflush.c b/lib/libpthread/stdio/fflush.c
index b7f66c3b4a13..127040f0298e 100644
--- a/lib/libpthread/stdio/fflush.c
+++ b/lib/libpthread/stdio/fflush.c
@@ -36,7 +36,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)fflush.c 5.1 (Berkeley) 1/20/91";*/
-static char *rcsid = "$Id: fflush.c,v 1.1 1994/01/30 04:24:37 proven Exp $";
+static char *rcsid = "$Id: fflush.c,v 1.2 1994/04/09 15:37:44 ats Exp $";
#endif /* LIBC_SCCS and not lint */
#include <pthread.h>
@@ -51,7 +51,7 @@ fflush(fp)
int retval;
if (fp == NULL)
- return (__swalk_sflush);
+ return (__swalk_sflush());
flockfile(fp);
if ((fp->_flags & (__SWR | __SRW)) == 0) {
diff --git a/lib/libpthread/stdio/ftell.c b/lib/libpthread/stdio/ftell.c
index d19e5825ad50..bf0eb4aa1769 100644
--- a/lib/libpthread/stdio/ftell.c
+++ b/lib/libpthread/stdio/ftell.c
@@ -36,7 +36,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)ftell.c 5.4 (Berkeley) 2/5/91";*/
-static char *rcsid = "$Id: ftell.c,v 1.1 1994/01/30 04:25:01 proven Exp $";
+static char *rcsid = "$Id: ftell.c,v 1.2 1994/06/06 08:35:25 ats Exp $";
#endif /* LIBC_SCCS and not lint */
#include <pthread.h>
@@ -62,7 +62,7 @@ ftell(fp)
if (fp->_flags & __SOFF)
pos = fp->_offset;
else {
- pos = lseek(fp, (fpos_t)0, SEEK_CUR);
+ pos = lseek(fp->_file, (fpos_t)0, SEEK_CUR);
}
if (pos != -1L) {
diff --git a/lib/libpthread/stdio/vfprintf.c b/lib/libpthread/stdio/vfprintf.c
index 8b3d29e74e30..70bab40d6518 100644
--- a/lib/libpthread/stdio/vfprintf.c
+++ b/lib/libpthread/stdio/vfprintf.c
@@ -36,7 +36,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
/*static char *sccsid = "from: @(#)vfprintf.c 5.50 (Berkeley) 12/16/92";*/
-static char *rcsid = "$Id: vfprintf.c,v 1.1 1994/01/30 04:25:51 proven Exp $";
+static char *rcsid = "$Id: vfprintf.c,v 1.2 1994/05/27 07:41:16 pst Exp $";
#endif /* LIBC_SCCS and not lint */
/*
@@ -473,7 +473,11 @@ reswitch: switch (ch) {
* -- ANSI X3J11
*/
/* NOSTRICT */
+#ifdef __i386
+ _uquad = (u_quad_t)(u_long)va_arg(ap, void *);
+#else
_uquad = (u_quad_t)va_arg(ap, void *);
+#endif
base = HEX;
xdigs = "0123456789abcdef";
flags |= HEXPREFIX;
diff --git a/lib/libskey/Makefile b/lib/libskey/Makefile
new file mode 100644
index 000000000000..ecf483333ce8
--- /dev/null
+++ b/lib/libskey/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 5.4 (Berkeley) 5/7/91
+
+LIB= skey
+SRCS= authfile.c md4.c put.c skey_crypt.c skeylogin.c skeysubr.c
+CFLAGS+=-DMPU8086
+.include <bsd.lib.mk>
+
diff --git a/lib/libskey/authfile.c b/lib/libskey/authfile.c
new file mode 100644
index 000000000000..ae7b0ace633d
--- /dev/null
+++ b/lib/libskey/authfile.c
@@ -0,0 +1,177 @@
+ /* Portions taken from the skey distribution on Oct 21 1993 */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <skey.h>
+
+#if (MAXHOSTNAMELEN < 64) /* AIX weirdness */
+#undef MAXHOSTNAMELEN
+#endif
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 255
+#endif
+
+#include "pathnames.h"
+
+static int isaddr();
+static int rdnets();
+
+#define MAXADDR 16 /* how many addresses can a machine
+ * have? */
+
+ /*
+ * Turn host into an IP address and then look it up in the authorization
+ * database to determine if ordinary password logins are OK
+ */
+int authfile(host)
+char *host;
+{
+ char *addr[MAXADDR];
+ char **ap;
+ long n;
+ struct hostent *hp;
+ char **lp;
+ struct hostent *xp;
+ int addr_length;
+
+ if (strlen(host) == 0) {
+ /* Local login, okay */
+ return 1;
+ }
+ if (isaddr(host)) {
+ return rdnets(inet_addr(host));
+ } else {
+
+ /*
+ * Stash away a copy of the host address list because it will be
+ * clobbered by other gethostbyXXX() calls.
+ */
+
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ syslog(LOG_ERR, "unknown host: %s", host);
+ return 0;
+ }
+ if (hp->h_addrtype != AF_INET) {
+ syslog(LOG_ERR, "unknown network family: %d", hp->h_addrtype);
+ return 0;
+ }
+ for (lp = hp->h_addr_list, ap = addr; ap < addr + MAXADDR; lp++, ap++) {
+ if (*lp == NULL) {
+ *ap = 0;
+ break;
+ } else {
+ if ((*ap = malloc(hp->h_length)) == 0) {
+ syslog(LOG_ERR, "out of memory");
+ return 0;
+ }
+ memcpy(*ap, *lp, hp->h_length);
+ }
+ }
+ addr_length = hp->h_length;
+
+ /*
+ * See if any of the addresses matches a pattern in the control file.
+ * Report and skip the address if it does not belong to the remote
+ * host. Assume localhost == localhost.domain.
+ */
+
+#define NEQ(x,y) (strcasecmp((x),(y)) != 0)
+
+ while (ap-- > addr) {
+ memcpy((char *) &n, *ap, addr_length);
+ if (rdnets(n)) {
+ if ((hp = gethostbyaddr(*ap, addr_length, AF_INET)) == 0
+ || (NEQ(host, hp->h_name) && NEQ(host, "localhost"))) {
+ syslog(LOG_ERR, "IP address %s not registered for host %s",
+ inet_ntoa(*(struct in_addr *) * ap), host);
+ continue;
+ }
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+static int rdnets(host)
+unsigned long host;
+{
+ FILE *fp;
+ char buf[128],
+ *cp;
+ long pattern,
+ mask;
+ char *strtok();
+ int permit_it = 0;
+
+ /*
+ * If auth file not found, be backwards compatible with standard login
+ * and allow hard coded passwords in from anywhere. Some may consider
+ * this a security hole, but backwards compatibility is more desirable
+ * than others. If you don't like it, change the return value to be zero.
+ */
+ if ((fp = fopen(_PATH_SKEYACCESS, "r")) == NULL)
+ return 1;
+
+ while (fgets(buf, sizeof(buf), fp), !feof(fp)) {
+ if (buf[0] == '#')
+ continue; /* Comment */
+ cp = strtok(buf, " \t");
+ if (cp == NULL)
+ continue;
+ /* two choices permit or deny */
+ if (strncasecmp(cp, "permit", 4) == 0) {
+ permit_it = 1;
+ } else {
+ if (strncasecmp(cp, "deny", 4) == 0) {
+ permit_it = 0;
+ } else {
+ continue; /* ignore this it is not
+ * permit/deny */
+ }
+ }
+ cp = strtok(NULL, " \t");
+ if (cp == NULL)
+ continue; /* Invalid line */
+ pattern = inet_addr(cp);
+ cp = strtok(NULL, " \t");
+ if (cp == NULL)
+ continue; /* Invalid line */
+ mask = inet_addr(cp);
+ if ((host & mask) == pattern) {
+ fclose(fp);
+ return permit_it;
+ }
+ }
+ fclose(fp);
+ return 0;
+}
+
+ /*
+ * Return TRUE if string appears to be an IP address in dotted decimal;
+ * return FALSE otherwise (i.e., if string is a domain name)
+ */
+static int isaddr(s)
+register char *s;
+{
+ char c;
+
+ if (s == NULL)
+ return 1; /* Can't happen */
+
+ while ((c = *s++) != '\0') {
+ if (c != '[' && c != ']' && !isdigit(c) && c != '.')
+ return 0;
+ }
+ return 1;
+}
diff --git a/lib/libskey/md4.c b/lib/libskey/md4.c
new file mode 100644
index 000000000000..495f4444e555
--- /dev/null
+++ b/lib/libskey/md4.c
@@ -0,0 +1,336 @@
+/*
+ * md4.c -- Implementation of MD4 Message Digest Algorithm
+ * Updated: 2/16/90 by Ronald L. Rivest
+ *
+ * Portability nits fixed and reformatted - 2/12/91 Phil Karn
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+/*
+ * To use MD4:
+ * -- Include md4.h in your program
+ * -- Declare an MDstruct MD to hold the state of the digest computation.
+ * -- Initialize MD using MDbegin(&MD)
+ * -- For each full block (64 bytes) X you wish to process, call
+ * MDupdate(&MD,X,512)
+ * (512 is the number of bits in a full block.)
+ * -- For the last block (less than 64 bytes) you wish to process,
+ * MDupdate(&MD,X,n)
+ * where n is the number of bits in the partial block. A partial
+ * block terminates the computation, so every MD computation should
+ * terminate by processing a partial block, even if it has n = 0.
+ * -- The message digest is available in MD.buffer[0] ... MD.buffer[3].
+ * (Least-significant byte of each word should be output first.)
+ * -- You can print out the digest using MDprint(&MD)
+ */
+
+/* Implementation notes:
+ * This implementation assumes that longs are 32-bit quantities.
+ * If the machine stores the least-significant byte of an long in the
+ * least-addressed byte (eg., VAX and 8086), then LOWBYTEFIRST should be
+ * set to TRUE. Otherwise (eg., SUNS), LOWBYTEFIRST should be set to
+ * FALSE. Note that on machines with LOWBYTEFIRST FALSE the routine
+ * MDupdate modifies has a side-effect on its input array (the order of bytes
+ * in each word are reversed). If this is undesired a call to MDreverse(X) can
+ * reverse the bytes of X back into order after each call to MDupdate.
+ */
+#define TRUE 1
+#define FALSE 0
+
+#if (defined(__MSDOS__) || defined(MPU8086) || defined(MPU8080) \
+ || defined(vax) || defined (MIPSEL))
+#define LOWBYTEFIRST TRUE /* Low order bytes are first in memory */
+#else /* Almost all other machines are big-endian */
+#define LOWBYTEFIRST FALSE
+#endif
+
+
+/* Compile-time includes */
+#include <stdio.h>
+#include "md4.h"
+
+/* Compile-time declarations of MD4 ``magic constants'' */
+#define I0 0x67452301 /* Initial values for MD buffer */
+#define I1 0xefcdab89
+#define I2 0x98badcfe
+#define I3 0x10325476
+#define C2 013240474631 /* round 2 constant = sqrt(2) in octal */
+#define C3 015666365641 /* round 3 constant = sqrt(3) in octal */
+/* C2 and C3 are from Knuth, The Art of Programming, Volume 2
+ * (Seminumerical Algorithms), Second Edition (1981), Addison-Wesley.
+ * Table 2, page 660.
+ */
+#define fs1 3 /* round 1 shift amounts */
+#define fs2 7
+#define fs3 11
+#define fs4 19
+#define gs1 3 /* round 2 shift amounts */
+#define gs2 5
+#define gs3 9
+#define gs4 13
+#define hs1 3 /* round 3 shift amounts */
+#define hs2 9
+#define hs3 11
+#define hs4 15
+
+
+/* Compile-time macro declarations for MD4.
+ * Note: The ``rot'' operator uses the variable ``tmp''.
+ * It assumes tmp is declared as unsigned long, so that the >>
+ * operator will shift in zeros rather than extending the sign bit.
+ */
+#define f(X,Y,Z) ((X&Y) | ((~X)&Z))
+#define g(X,Y,Z) ((X&Y) | (X&Z) | (Y&Z))
+#define h(X,Y,Z) (X^Y^Z)
+#define rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S)))
+#define ff(A,B,C,D,i,s) A = rot((A + f(B,C,D) + X[i]),s)
+#define gg(A,B,C,D,i,s) A = rot((A + g(B,C,D) + X[i] + C2),s)
+#define hh(A,B,C,D,i,s) A = rot((A + h(B,C,D) + X[i] + C3),s)
+
+void MDreverse __P((unsigned long *X));
+
+/* MDprint(MDp)
+ * Print message digest buffer MDp as 32 hexadecimal digits.
+ * Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
+ * Each byte is printed with high-order hexadecimal digit first.
+ * This is a user-callable routine.
+ */
+void
+MDprint(MDp)
+MDptr MDp;
+{
+ int i,j;
+
+ for(i=0;i<4;i++)
+ for(j=0;j<32;j=j+8)
+ printf("%02lx",(MDp->buffer[i]>>j) & 0xFF);
+}
+
+/* MDbegin(MDp)
+ * Initialize message digest buffer MDp.
+ * This is a user-callable routine.
+ */
+void
+MDbegin(MDp)
+MDptr MDp;
+{
+ int i;
+
+ MDp->buffer[0] = I0;
+ MDp->buffer[1] = I1;
+ MDp->buffer[2] = I2;
+ MDp->buffer[3] = I3;
+ for(i=0;i<8;i++)
+ MDp->count[i] = 0;
+ MDp->done = 0;
+}
+
+/* MDreverse(X)
+ * Reverse the byte-ordering of every long in X.
+ * Assumes X is an array of 16 longs.
+ * The macro revx reverses the byte-ordering of the next word of X.
+ */
+#define revx { t = (*X << 16) | (*X >> 16); \
+ *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); }
+void
+MDreverse(X)
+unsigned long *X;
+{
+ register unsigned long t;
+
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+ revx;
+}
+
+/* MDblock(MDp,X)
+ * Update message digest buffer MDp->buffer using 16-word data block X.
+ * Assumes all 16 words of X are full of data.
+ * Does not update MDp->count.
+ * This routine is not user-callable.
+ */
+static void
+MDblock(MDp,X)
+MDptr MDp;
+unsigned long *X;
+{
+ register unsigned long tmp, A, B, C, D;
+
+#if LOWBYTEFIRST == FALSE
+ MDreverse(X);
+#endif
+ A = MDp->buffer[0];
+ B = MDp->buffer[1];
+ C = MDp->buffer[2];
+ D = MDp->buffer[3];
+ /* Update the message digest buffer */
+ ff(A,B,C,D,0,fs1); /* Round 1 */
+ ff(D,A,B,C,1,fs2);
+ ff(C,D,A,B,2,fs3);
+ ff(B,C,D,A,3,fs4);
+ ff(A,B,C,D,4,fs1);
+ ff(D,A,B,C,5,fs2);
+ ff(C,D,A,B,6,fs3);
+ ff(B,C,D,A,7,fs4);
+ ff(A,B,C,D,8,fs1);
+ ff(D,A,B,C,9,fs2);
+ ff(C,D,A,B,10,fs3);
+ ff(B,C,D,A,11,fs4);
+ ff(A,B,C,D,12,fs1);
+ ff(D,A,B,C,13,fs2);
+ ff(C,D,A,B,14,fs3);
+ ff(B,C,D,A,15,fs4);
+ gg(A,B,C,D,0,gs1); /* Round 2 */
+ gg(D,A,B,C,4,gs2);
+ gg(C,D,A,B,8,gs3);
+ gg(B,C,D,A,12,gs4);
+ gg(A,B,C,D,1,gs1);
+ gg(D,A,B,C,5,gs2);
+ gg(C,D,A,B,9,gs3);
+ gg(B,C,D,A,13,gs4);
+ gg(A,B,C,D,2,gs1);
+ gg(D,A,B,C,6,gs2);
+ gg(C,D,A,B,10,gs3);
+ gg(B,C,D,A,14,gs4);
+ gg(A,B,C,D,3,gs1);
+ gg(D,A,B,C,7,gs2);
+ gg(C,D,A,B,11,gs3);
+ gg(B,C,D,A,15,gs4);
+ hh(A,B,C,D,0,hs1); /* Round 3 */
+ hh(D,A,B,C,8,hs2);
+ hh(C,D,A,B,4,hs3);
+ hh(B,C,D,A,12,hs4);
+ hh(A,B,C,D,2,hs1);
+ hh(D,A,B,C,10,hs2);
+ hh(C,D,A,B,6,hs3);
+ hh(B,C,D,A,14,hs4);
+ hh(A,B,C,D,1,hs1);
+ hh(D,A,B,C,9,hs2);
+ hh(C,D,A,B,5,hs3);
+ hh(B,C,D,A,13,hs4);
+ hh(A,B,C,D,3,hs1);
+ hh(D,A,B,C,11,hs2);
+ hh(C,D,A,B,7,hs3);
+ hh(B,C,D,A,15,hs4);
+ MDp->buffer[0] += A;
+ MDp->buffer[1] += B;
+ MDp->buffer[2] += C;
+ MDp->buffer[3] += D;
+}
+
+/* MDupdate(MDp,X,count)
+ * Input: MDp -- an MDptr
+ * X -- a pointer to an array of unsigned characters.
+ * count -- the number of bits of X to use.
+ * (if not a multiple of 8, uses high bits of last byte.)
+ * Update MDp using the number of bits of X given by count.
+ * This is the basic input routine for an MD4 user.
+ * The routine completes the MD computation when count < 512, so
+ * every MD computation should end with one call to MDupdate with a
+ * count less than 512. A call with count 0 will be ignored if the
+ * MD has already been terminated (done != 0), so an extra call with count
+ * 0 can be given as a ``courtesy close'' to force termination if desired.
+ */
+void
+MDupdate(MDp,X,count)
+MDptr MDp;
+unsigned char *X;
+unsigned int count;
+{
+ int i,bit,byte,mask;
+ unsigned long tmp;
+ unsigned char XX[64];
+ unsigned char *p;
+
+ /* return with no error if this is a courtesy close with count
+ * zero and MDp->done is true.
+ */
+ if(count == 0 && MDp->done)
+ return;
+ /* check to see if MD is already done and report error */
+ if(MDp->done){
+ printf("\nError: MDupdate MD already done.");
+ return;
+ }
+ /* Add count to MDp->count */
+ tmp = count;
+ p = MDp->count;
+ while(tmp){
+ tmp += *p;
+ *p++ = tmp;
+ tmp = tmp >> 8;
+ }
+ /* Process data */
+ if(count == 512){
+ /* Full block of data to handle */
+ MDblock(MDp,(unsigned long *)X);
+ } else if(count > 512){
+ /* Check for count too large */
+ printf("\nError: MDupdate called with illegal count value %ld.",count);
+ return;
+ } else {
+ /* partial block -- must be last block so finish up
+ * Find out how many bytes and residual bits there are
+ */
+ byte = count >> 3;
+ bit = count & 7;
+ /* Copy X into XX since we need to modify it */
+ for(i=0;i<=byte;i++)
+ XX[i] = X[i];
+ for(i=byte+1;i<64;i++)
+ XX[i] = 0;
+ /* Add padding '1' bit and low-order zeros in last byte */
+ mask = 1 << (7 - bit);
+ XX[byte] = (XX[byte] | mask) & ~( mask - 1);
+ /* If room for bit count, finish up with this block */
+ if(byte <= 55){
+ for(i=0;i<8;i++)
+ XX[56+i] = MDp->count[i];
+ MDblock(MDp,(unsigned long *)XX);
+ } else {
+ /* need to do two blocks to finish up */
+ MDblock(MDp,(unsigned long *)XX);
+ for(i=0;i<56;i++)
+ XX[i] = 0;
+ for(i=0;i<8;i++)
+ XX[56+i] = MDp->count[i];
+ MDblock(MDp,(unsigned long *)XX);
+ }
+ /* Set flag saying we're done with MD computation */
+ MDp->done = 1;
+ }
+}
+/* End of md4.c */
diff --git a/lib/libskey/md4.h b/lib/libskey/md4.h
new file mode 100644
index 000000000000..c0d341980a2c
--- /dev/null
+++ b/lib/libskey/md4.h
@@ -0,0 +1,47 @@
+
+#include <sys/cdefs.h>
+
+/*
+ *
+ * md4.h -- Header file for implementation of MD4 Message Digest Algorithm
+ * Updated: 2/13/90 by Ronald L. Rivest
+ * (C) 1990 RSA Data Security, Inc.
+ * Reformatted and de-linted - 2/12/91 Phil Karn
+ */
+
+/* MDstruct is the data structure for a message digest computation. */
+typedef struct {
+ unsigned long buffer[4];/* Holds 4-word result of MD computation */
+ unsigned char count[8]; /* Number of bits processed so far */
+ unsigned int done; /* Nonzero means MD computation finished */
+} MDstruct, *MDptr;
+
+/* MDbegin(MD)
+ * Input: MD -- an MDptr
+ * Initialize the MDstruct prepatory to doing a message digest computation.
+ */
+extern void MDbegin __P((MDptr MDp));
+
+/* MDupdate(MD,X,count)
+ * Input: MD -- an MDptr
+ * X -- a pointer to an array of unsigned characters.
+ * count -- the number of bits of X to use (an unsigned int).
+ * Updates MD using the first ``count'' bits of X.
+ * The array pointed to by X is not modified.
+ * If count is not a multiple of 8, MDupdate uses high bits of last byte.
+ * This is the basic input routine for a user.
+ * The routine terminates the MD computation when count < 512, so
+ * every MD computation should end with one call to MDupdate with a
+ * count less than 512. Zero is OK for a count.
+ */
+extern void MDupdate __P((MDptr MDp,unsigned char *X,unsigned int count));
+
+/* MDprint(MD)
+ * Input: MD -- an MDptr
+ * Prints message digest buffer MD as 32 hexadecimal digits.
+ * Order is from low-order byte of buffer[0] to high-order byte of buffer[3].
+ * Each byte is printed with high-order hexadecimal digit first.
+ */
+extern void MDprint __P((MDptr MDp));
+
+/* End of md4.h */
diff --git a/lib/libskey/pathnames.h b/lib/libskey/pathnames.h
new file mode 100644
index 000000000000..763451901531
--- /dev/null
+++ b/lib/libskey/pathnames.h
@@ -0,0 +1,5 @@
+/* $Id: pathnames.h,v 1.1 1994/05/27 07:50:08 pst Exp $ (FreeBSD) */
+
+#include <paths.h>
+
+#define _PATH_SKEYACCESS "/etc/skey.access"
diff --git a/lib/libskey/put.c b/lib/libskey/put.c
new file mode 100644
index 000000000000..0f62d22499c1
--- /dev/null
+++ b/lib/libskey/put.c
@@ -0,0 +1,2289 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <skey.h>
+
+static unsigned long extract __P((char *s,int start,int length));
+static void standard __P((char *word));
+static void insert __P((char *s, int x, int start, int length));
+static int wsrch __P((char *w,int low,int high));
+
+/* Dictionary for integer-word translations */
+char Wp[2048][4] = {
+"A",
+"ABE",
+"ACE",
+"ACT",
+"AD",
+"ADA",
+"ADD",
+"AGO",
+"AID",
+"AIM",
+"AIR",
+"ALL",
+"ALP",
+"AM",
+"AMY",
+"AN",
+"ANA",
+"AND",
+"ANN",
+"ANT",
+"ANY",
+"APE",
+"APS",
+"APT",
+"ARC",
+"ARE",
+"ARK",
+"ARM",
+"ART",
+"AS",
+"ASH",
+"ASK",
+"AT",
+"ATE",
+"AUG",
+"AUK",
+"AVE",
+"AWE",
+"AWK",
+"AWL",
+"AWN",
+"AX",
+"AYE",
+"BAD",
+"BAG",
+"BAH",
+"BAM",
+"BAN",
+"BAR",
+"BAT",
+"BAY",
+"BE",
+"BED",
+"BEE",
+"BEG",
+"BEN",
+"BET",
+"BEY",
+"BIB",
+"BID",
+"BIG",
+"BIN",
+"BIT",
+"BOB",
+"BOG",
+"BON",
+"BOO",
+"BOP",
+"BOW",
+"BOY",
+"BUB",
+"BUD",
+"BUG",
+"BUM",
+"BUN",
+"BUS",
+"BUT",
+"BUY",
+"BY",
+"BYE",
+"CAB",
+"CAL",
+"CAM",
+"CAN",
+"CAP",
+"CAR",
+"CAT",
+"CAW",
+"COD",
+"COG",
+"COL",
+"CON",
+"COO",
+"COP",
+"COT",
+"COW",
+"COY",
+"CRY",
+"CUB",
+"CUE",
+"CUP",
+"CUR",
+"CUT",
+"DAB",
+"DAD",
+"DAM",
+"DAN",
+"DAR",
+"DAY",
+"DEE",
+"DEL",
+"DEN",
+"DES",
+"DEW",
+"DID",
+"DIE",
+"DIG",
+"DIN",
+"DIP",
+"DO",
+"DOE",
+"DOG",
+"DON",
+"DOT",
+"DOW",
+"DRY",
+"DUB",
+"DUD",
+"DUE",
+"DUG",
+"DUN",
+"EAR",
+"EAT",
+"ED",
+"EEL",
+"EGG",
+"EGO",
+"ELI",
+"ELK",
+"ELM",
+"ELY",
+"EM",
+"END",
+"EST",
+"ETC",
+"EVA",
+"EVE",
+"EWE",
+"EYE",
+"FAD",
+"FAN",
+"FAR",
+"FAT",
+"FAY",
+"FED",
+"FEE",
+"FEW",
+"FIB",
+"FIG",
+"FIN",
+"FIR",
+"FIT",
+"FLO",
+"FLY",
+"FOE",
+"FOG",
+"FOR",
+"FRY",
+"FUM",
+"FUN",
+"FUR",
+"GAB",
+"GAD",
+"GAG",
+"GAL",
+"GAM",
+"GAP",
+"GAS",
+"GAY",
+"GEE",
+"GEL",
+"GEM",
+"GET",
+"GIG",
+"GIL",
+"GIN",
+"GO",
+"GOT",
+"GUM",
+"GUN",
+"GUS",
+"GUT",
+"GUY",
+"GYM",
+"GYP",
+"HA",
+"HAD",
+"HAL",
+"HAM",
+"HAN",
+"HAP",
+"HAS",
+"HAT",
+"HAW",
+"HAY",
+"HE",
+"HEM",
+"HEN",
+"HER",
+"HEW",
+"HEY",
+"HI",
+"HID",
+"HIM",
+"HIP",
+"HIS",
+"HIT",
+"HO",
+"HOB",
+"HOC",
+"HOE",
+"HOG",
+"HOP",
+"HOT",
+"HOW",
+"HUB",
+"HUE",
+"HUG",
+"HUH",
+"HUM",
+"HUT",
+"I",
+"ICY",
+"IDA",
+"IF",
+"IKE",
+"ILL",
+"INK",
+"INN",
+"IO",
+"ION",
+"IQ",
+"IRA",
+"IRE",
+"IRK",
+"IS",
+"IT",
+"ITS",
+"IVY",
+"JAB",
+"JAG",
+"JAM",
+"JAN",
+"JAR",
+"JAW",
+"JAY",
+"JET",
+"JIG",
+"JIM",
+"JO",
+"JOB",
+"JOE",
+"JOG",
+"JOT",
+"JOY",
+"JUG",
+"JUT",
+"KAY",
+"KEG",
+"KEN",
+"KEY",
+"KID",
+"KIM",
+"KIN",
+"KIT",
+"LA",
+"LAB",
+"LAC",
+"LAD",
+"LAG",
+"LAM",
+"LAP",
+"LAW",
+"LAY",
+"LEA",
+"LED",
+"LEE",
+"LEG",
+"LEN",
+"LEO",
+"LET",
+"LEW",
+"LID",
+"LIE",
+"LIN",
+"LIP",
+"LIT",
+"LO",
+"LOB",
+"LOG",
+"LOP",
+"LOS",
+"LOT",
+"LOU",
+"LOW",
+"LOY",
+"LUG",
+"LYE",
+"MA",
+"MAC",
+"MAD",
+"MAE",
+"MAN",
+"MAO",
+"MAP",
+"MAT",
+"MAW",
+"MAY",
+"ME",
+"MEG",
+"MEL",
+"MEN",
+"MET",
+"MEW",
+"MID",
+"MIN",
+"MIT",
+"MOB",
+"MOD",
+"MOE",
+"MOO",
+"MOP",
+"MOS",
+"MOT",
+"MOW",
+"MUD",
+"MUG",
+"MUM",
+"MY",
+"NAB",
+"NAG",
+"NAN",
+"NAP",
+"NAT",
+"NAY",
+"NE",
+"NED",
+"NEE",
+"NET",
+"NEW",
+"NIB",
+"NIL",
+"NIP",
+"NIT",
+"NO",
+"NOB",
+"NOD",
+"NON",
+"NOR",
+"NOT",
+"NOV",
+"NOW",
+"NU",
+"NUN",
+"NUT",
+"O",
+"OAF",
+"OAK",
+"OAR",
+"OAT",
+"ODD",
+"ODE",
+"OF",
+"OFF",
+"OFT",
+"OH",
+"OIL",
+"OK",
+"OLD",
+"ON",
+"ONE",
+"OR",
+"ORB",
+"ORE",
+"ORR",
+"OS",
+"OTT",
+"OUR",
+"OUT",
+"OVA",
+"OW",
+"OWE",
+"OWL",
+"OWN",
+"OX",
+"PA",
+"PAD",
+"PAL",
+"PAM",
+"PAN",
+"PAP",
+"PAR",
+"PAT",
+"PAW",
+"PAY",
+"PEA",
+"PEG",
+"PEN",
+"PEP",
+"PER",
+"PET",
+"PEW",
+"PHI",
+"PI",
+"PIE",
+"PIN",
+"PIT",
+"PLY",
+"PO",
+"POD",
+"POE",
+"POP",
+"POT",
+"POW",
+"PRO",
+"PRY",
+"PUB",
+"PUG",
+"PUN",
+"PUP",
+"PUT",
+"QUO",
+"RAG",
+"RAM",
+"RAN",
+"RAP",
+"RAT",
+"RAW",
+"RAY",
+"REB",
+"RED",
+"REP",
+"RET",
+"RIB",
+"RID",
+"RIG",
+"RIM",
+"RIO",
+"RIP",
+"ROB",
+"ROD",
+"ROE",
+"RON",
+"ROT",
+"ROW",
+"ROY",
+"RUB",
+"RUE",
+"RUG",
+"RUM",
+"RUN",
+"RYE",
+"SAC",
+"SAD",
+"SAG",
+"SAL",
+"SAM",
+"SAN",
+"SAP",
+"SAT",
+"SAW",
+"SAY",
+"SEA",
+"SEC",
+"SEE",
+"SEN",
+"SET",
+"SEW",
+"SHE",
+"SHY",
+"SIN",
+"SIP",
+"SIR",
+"SIS",
+"SIT",
+"SKI",
+"SKY",
+"SLY",
+"SO",
+"SOB",
+"SOD",
+"SON",
+"SOP",
+"SOW",
+"SOY",
+"SPA",
+"SPY",
+"SUB",
+"SUD",
+"SUE",
+"SUM",
+"SUN",
+"SUP",
+"TAB",
+"TAD",
+"TAG",
+"TAN",
+"TAP",
+"TAR",
+"TEA",
+"TED",
+"TEE",
+"TEN",
+"THE",
+"THY",
+"TIC",
+"TIE",
+"TIM",
+"TIN",
+"TIP",
+"TO",
+"TOE",
+"TOG",
+"TOM",
+"TON",
+"TOO",
+"TOP",
+"TOW",
+"TOY",
+"TRY",
+"TUB",
+"TUG",
+"TUM",
+"TUN",
+"TWO",
+"UN",
+"UP",
+"US",
+"USE",
+"VAN",
+"VAT",
+"VET",
+"VIE",
+"WAD",
+"WAG",
+"WAR",
+"WAS",
+"WAY",
+"WE",
+"WEB",
+"WED",
+"WEE",
+"WET",
+"WHO",
+"WHY",
+"WIN",
+"WIT",
+"WOK",
+"WON",
+"WOO",
+"WOW",
+"WRY",
+"WU",
+"YAM",
+"YAP",
+"YAW",
+"YE",
+"YEA",
+"YES",
+"YET",
+"YOU",
+"ABED",
+"ABEL",
+"ABET",
+"ABLE",
+"ABUT",
+"ACHE",
+"ACID",
+"ACME",
+"ACRE",
+"ACTA",
+"ACTS",
+"ADAM",
+"ADDS",
+"ADEN",
+"AFAR",
+"AFRO",
+"AGEE",
+"AHEM",
+"AHOY",
+"AIDA",
+"AIDE",
+"AIDS",
+"AIRY",
+"AJAR",
+"AKIN",
+"ALAN",
+"ALEC",
+"ALGA",
+"ALIA",
+"ALLY",
+"ALMA",
+"ALOE",
+"ALSO",
+"ALTO",
+"ALUM",
+"ALVA",
+"AMEN",
+"AMES",
+"AMID",
+"AMMO",
+"AMOK",
+"AMOS",
+"AMRA",
+"ANDY",
+"ANEW",
+"ANNA",
+"ANNE",
+"ANTE",
+"ANTI",
+"AQUA",
+"ARAB",
+"ARCH",
+"AREA",
+"ARGO",
+"ARID",
+"ARMY",
+"ARTS",
+"ARTY",
+"ASIA",
+"ASKS",
+"ATOM",
+"AUNT",
+"AURA",
+"AUTO",
+"AVER",
+"AVID",
+"AVIS",
+"AVON",
+"AVOW",
+"AWAY",
+"AWRY",
+"BABE",
+"BABY",
+"BACH",
+"BACK",
+"BADE",
+"BAIL",
+"BAIT",
+"BAKE",
+"BALD",
+"BALE",
+"BALI",
+"BALK",
+"BALL",
+"BALM",
+"BAND",
+"BANE",
+"BANG",
+"BANK",
+"BARB",
+"BARD",
+"BARE",
+"BARK",
+"BARN",
+"BARR",
+"BASE",
+"BASH",
+"BASK",
+"BASS",
+"BATE",
+"BATH",
+"BAWD",
+"BAWL",
+"BEAD",
+"BEAK",
+"BEAM",
+"BEAN",
+"BEAR",
+"BEAT",
+"BEAU",
+"BECK",
+"BEEF",
+"BEEN",
+"BEER",
+"BEET",
+"BELA",
+"BELL",
+"BELT",
+"BEND",
+"BENT",
+"BERG",
+"BERN",
+"BERT",
+"BESS",
+"BEST",
+"BETA",
+"BETH",
+"BHOY",
+"BIAS",
+"BIDE",
+"BIEN",
+"BILE",
+"BILK",
+"BILL",
+"BIND",
+"BING",
+"BIRD",
+"BITE",
+"BITS",
+"BLAB",
+"BLAT",
+"BLED",
+"BLEW",
+"BLOB",
+"BLOC",
+"BLOT",
+"BLOW",
+"BLUE",
+"BLUM",
+"BLUR",
+"BOAR",
+"BOAT",
+"BOCA",
+"BOCK",
+"BODE",
+"BODY",
+"BOGY",
+"BOHR",
+"BOIL",
+"BOLD",
+"BOLO",
+"BOLT",
+"BOMB",
+"BONA",
+"BOND",
+"BONE",
+"BONG",
+"BONN",
+"BONY",
+"BOOK",
+"BOOM",
+"BOON",
+"BOOT",
+"BORE",
+"BORG",
+"BORN",
+"BOSE",
+"BOSS",
+"BOTH",
+"BOUT",
+"BOWL",
+"BOYD",
+"BRAD",
+"BRAE",
+"BRAG",
+"BRAN",
+"BRAY",
+"BRED",
+"BREW",
+"BRIG",
+"BRIM",
+"BROW",
+"BUCK",
+"BUDD",
+"BUFF",
+"BULB",
+"BULK",
+"BULL",
+"BUNK",
+"BUNT",
+"BUOY",
+"BURG",
+"BURL",
+"BURN",
+"BURR",
+"BURT",
+"BURY",
+"BUSH",
+"BUSS",
+"BUST",
+"BUSY",
+"BYTE",
+"CADY",
+"CAFE",
+"CAGE",
+"CAIN",
+"CAKE",
+"CALF",
+"CALL",
+"CALM",
+"CAME",
+"CANE",
+"CANT",
+"CARD",
+"CARE",
+"CARL",
+"CARR",
+"CART",
+"CASE",
+"CASH",
+"CASK",
+"CAST",
+"CAVE",
+"CEIL",
+"CELL",
+"CENT",
+"CERN",
+"CHAD",
+"CHAR",
+"CHAT",
+"CHAW",
+"CHEF",
+"CHEN",
+"CHEW",
+"CHIC",
+"CHIN",
+"CHOU",
+"CHOW",
+"CHUB",
+"CHUG",
+"CHUM",
+"CITE",
+"CITY",
+"CLAD",
+"CLAM",
+"CLAN",
+"CLAW",
+"CLAY",
+"CLOD",
+"CLOG",
+"CLOT",
+"CLUB",
+"CLUE",
+"COAL",
+"COAT",
+"COCA",
+"COCK",
+"COCO",
+"CODA",
+"CODE",
+"CODY",
+"COED",
+"COIL",
+"COIN",
+"COKE",
+"COLA",
+"COLD",
+"COLT",
+"COMA",
+"COMB",
+"COME",
+"COOK",
+"COOL",
+"COON",
+"COOT",
+"CORD",
+"CORE",
+"CORK",
+"CORN",
+"COST",
+"COVE",
+"COWL",
+"CRAB",
+"CRAG",
+"CRAM",
+"CRAY",
+"CREW",
+"CRIB",
+"CROW",
+"CRUD",
+"CUBA",
+"CUBE",
+"CUFF",
+"CULL",
+"CULT",
+"CUNY",
+"CURB",
+"CURD",
+"CURE",
+"CURL",
+"CURT",
+"CUTS",
+"DADE",
+"DALE",
+"DAME",
+"DANA",
+"DANE",
+"DANG",
+"DANK",
+"DARE",
+"DARK",
+"DARN",
+"DART",
+"DASH",
+"DATA",
+"DATE",
+"DAVE",
+"DAVY",
+"DAWN",
+"DAYS",
+"DEAD",
+"DEAF",
+"DEAL",
+"DEAN",
+"DEAR",
+"DEBT",
+"DECK",
+"DEED",
+"DEEM",
+"DEER",
+"DEFT",
+"DEFY",
+"DELL",
+"DENT",
+"DENY",
+"DESK",
+"DIAL",
+"DICE",
+"DIED",
+"DIET",
+"DIME",
+"DINE",
+"DING",
+"DINT",
+"DIRE",
+"DIRT",
+"DISC",
+"DISH",
+"DISK",
+"DIVE",
+"DOCK",
+"DOES",
+"DOLE",
+"DOLL",
+"DOLT",
+"DOME",
+"DONE",
+"DOOM",
+"DOOR",
+"DORA",
+"DOSE",
+"DOTE",
+"DOUG",
+"DOUR",
+"DOVE",
+"DOWN",
+"DRAB",
+"DRAG",
+"DRAM",
+"DRAW",
+"DREW",
+"DRUB",
+"DRUG",
+"DRUM",
+"DUAL",
+"DUCK",
+"DUCT",
+"DUEL",
+"DUET",
+"DUKE",
+"DULL",
+"DUMB",
+"DUNE",
+"DUNK",
+"DUSK",
+"DUST",
+"DUTY",
+"EACH",
+"EARL",
+"EARN",
+"EASE",
+"EAST",
+"EASY",
+"EBEN",
+"ECHO",
+"EDDY",
+"EDEN",
+"EDGE",
+"EDGY",
+"EDIT",
+"EDNA",
+"EGAN",
+"ELAN",
+"ELBA",
+"ELLA",
+"ELSE",
+"EMIL",
+"EMIT",
+"EMMA",
+"ENDS",
+"ERIC",
+"EROS",
+"EVEN",
+"EVER",
+"EVIL",
+"EYED",
+"FACE",
+"FACT",
+"FADE",
+"FAIL",
+"FAIN",
+"FAIR",
+"FAKE",
+"FALL",
+"FAME",
+"FANG",
+"FARM",
+"FAST",
+"FATE",
+"FAWN",
+"FEAR",
+"FEAT",
+"FEED",
+"FEEL",
+"FEET",
+"FELL",
+"FELT",
+"FEND",
+"FERN",
+"FEST",
+"FEUD",
+"FIEF",
+"FIGS",
+"FILE",
+"FILL",
+"FILM",
+"FIND",
+"FINE",
+"FINK",
+"FIRE",
+"FIRM",
+"FISH",
+"FISK",
+"FIST",
+"FITS",
+"FIVE",
+"FLAG",
+"FLAK",
+"FLAM",
+"FLAT",
+"FLAW",
+"FLEA",
+"FLED",
+"FLEW",
+"FLIT",
+"FLOC",
+"FLOG",
+"FLOW",
+"FLUB",
+"FLUE",
+"FOAL",
+"FOAM",
+"FOGY",
+"FOIL",
+"FOLD",
+"FOLK",
+"FOND",
+"FONT",
+"FOOD",
+"FOOL",
+"FOOT",
+"FORD",
+"FORE",
+"FORK",
+"FORM",
+"FORT",
+"FOSS",
+"FOUL",
+"FOUR",
+"FOWL",
+"FRAU",
+"FRAY",
+"FRED",
+"FREE",
+"FRET",
+"FREY",
+"FROG",
+"FROM",
+"FUEL",
+"FULL",
+"FUME",
+"FUND",
+"FUNK",
+"FURY",
+"FUSE",
+"FUSS",
+"GAFF",
+"GAGE",
+"GAIL",
+"GAIN",
+"GAIT",
+"GALA",
+"GALE",
+"GALL",
+"GALT",
+"GAME",
+"GANG",
+"GARB",
+"GARY",
+"GASH",
+"GATE",
+"GAUL",
+"GAUR",
+"GAVE",
+"GAWK",
+"GEAR",
+"GELD",
+"GENE",
+"GENT",
+"GERM",
+"GETS",
+"GIBE",
+"GIFT",
+"GILD",
+"GILL",
+"GILT",
+"GINA",
+"GIRD",
+"GIRL",
+"GIST",
+"GIVE",
+"GLAD",
+"GLEE",
+"GLEN",
+"GLIB",
+"GLOB",
+"GLOM",
+"GLOW",
+"GLUE",
+"GLUM",
+"GLUT",
+"GOAD",
+"GOAL",
+"GOAT",
+"GOER",
+"GOES",
+"GOLD",
+"GOLF",
+"GONE",
+"GONG",
+"GOOD",
+"GOOF",
+"GORE",
+"GORY",
+"GOSH",
+"GOUT",
+"GOWN",
+"GRAB",
+"GRAD",
+"GRAY",
+"GREG",
+"GREW",
+"GREY",
+"GRID",
+"GRIM",
+"GRIN",
+"GRIT",
+"GROW",
+"GRUB",
+"GULF",
+"GULL",
+"GUNK",
+"GURU",
+"GUSH",
+"GUST",
+"GWEN",
+"GWYN",
+"HAAG",
+"HAAS",
+"HACK",
+"HAIL",
+"HAIR",
+"HALE",
+"HALF",
+"HALL",
+"HALO",
+"HALT",
+"HAND",
+"HANG",
+"HANK",
+"HANS",
+"HARD",
+"HARK",
+"HARM",
+"HART",
+"HASH",
+"HAST",
+"HATE",
+"HATH",
+"HAUL",
+"HAVE",
+"HAWK",
+"HAYS",
+"HEAD",
+"HEAL",
+"HEAR",
+"HEAT",
+"HEBE",
+"HECK",
+"HEED",
+"HEEL",
+"HEFT",
+"HELD",
+"HELL",
+"HELM",
+"HERB",
+"HERD",
+"HERE",
+"HERO",
+"HERS",
+"HESS",
+"HEWN",
+"HICK",
+"HIDE",
+"HIGH",
+"HIKE",
+"HILL",
+"HILT",
+"HIND",
+"HINT",
+"HIRE",
+"HISS",
+"HIVE",
+"HOBO",
+"HOCK",
+"HOFF",
+"HOLD",
+"HOLE",
+"HOLM",
+"HOLT",
+"HOME",
+"HONE",
+"HONK",
+"HOOD",
+"HOOF",
+"HOOK",
+"HOOT",
+"HORN",
+"HOSE",
+"HOST",
+"HOUR",
+"HOVE",
+"HOWE",
+"HOWL",
+"HOYT",
+"HUCK",
+"HUED",
+"HUFF",
+"HUGE",
+"HUGH",
+"HUGO",
+"HULK",
+"HULL",
+"HUNK",
+"HUNT",
+"HURD",
+"HURL",
+"HURT",
+"HUSH",
+"HYDE",
+"HYMN",
+"IBIS",
+"ICON",
+"IDEA",
+"IDLE",
+"IFFY",
+"INCA",
+"INCH",
+"INTO",
+"IONS",
+"IOTA",
+"IOWA",
+"IRIS",
+"IRMA",
+"IRON",
+"ISLE",
+"ITCH",
+"ITEM",
+"IVAN",
+"JACK",
+"JADE",
+"JAIL",
+"JAKE",
+"JANE",
+"JAVA",
+"JEAN",
+"JEFF",
+"JERK",
+"JESS",
+"JEST",
+"JIBE",
+"JILL",
+"JILT",
+"JIVE",
+"JOAN",
+"JOBS",
+"JOCK",
+"JOEL",
+"JOEY",
+"JOHN",
+"JOIN",
+"JOKE",
+"JOLT",
+"JOVE",
+"JUDD",
+"JUDE",
+"JUDO",
+"JUDY",
+"JUJU",
+"JUKE",
+"JULY",
+"JUNE",
+"JUNK",
+"JUNO",
+"JURY",
+"JUST",
+"JUTE",
+"KAHN",
+"KALE",
+"KANE",
+"KANT",
+"KARL",
+"KATE",
+"KEEL",
+"KEEN",
+"KENO",
+"KENT",
+"KERN",
+"KERR",
+"KEYS",
+"KICK",
+"KILL",
+"KIND",
+"KING",
+"KIRK",
+"KISS",
+"KITE",
+"KLAN",
+"KNEE",
+"KNEW",
+"KNIT",
+"KNOB",
+"KNOT",
+"KNOW",
+"KOCH",
+"KONG",
+"KUDO",
+"KURD",
+"KURT",
+"KYLE",
+"LACE",
+"LACK",
+"LACY",
+"LADY",
+"LAID",
+"LAIN",
+"LAIR",
+"LAKE",
+"LAMB",
+"LAME",
+"LAND",
+"LANE",
+"LANG",
+"LARD",
+"LARK",
+"LASS",
+"LAST",
+"LATE",
+"LAUD",
+"LAVA",
+"LAWN",
+"LAWS",
+"LAYS",
+"LEAD",
+"LEAF",
+"LEAK",
+"LEAN",
+"LEAR",
+"LEEK",
+"LEER",
+"LEFT",
+"LEND",
+"LENS",
+"LENT",
+"LEON",
+"LESK",
+"LESS",
+"LEST",
+"LETS",
+"LIAR",
+"LICE",
+"LICK",
+"LIED",
+"LIEN",
+"LIES",
+"LIEU",
+"LIFE",
+"LIFT",
+"LIKE",
+"LILA",
+"LILT",
+"LILY",
+"LIMA",
+"LIMB",
+"LIME",
+"LIND",
+"LINE",
+"LINK",
+"LINT",
+"LION",
+"LISA",
+"LIST",
+"LIVE",
+"LOAD",
+"LOAF",
+"LOAM",
+"LOAN",
+"LOCK",
+"LOFT",
+"LOGE",
+"LOIS",
+"LOLA",
+"LONE",
+"LONG",
+"LOOK",
+"LOON",
+"LOOT",
+"LORD",
+"LORE",
+"LOSE",
+"LOSS",
+"LOST",
+"LOUD",
+"LOVE",
+"LOWE",
+"LUCK",
+"LUCY",
+"LUGE",
+"LUKE",
+"LULU",
+"LUND",
+"LUNG",
+"LURA",
+"LURE",
+"LURK",
+"LUSH",
+"LUST",
+"LYLE",
+"LYNN",
+"LYON",
+"LYRA",
+"MACE",
+"MADE",
+"MAGI",
+"MAID",
+"MAIL",
+"MAIN",
+"MAKE",
+"MALE",
+"MALI",
+"MALL",
+"MALT",
+"MANA",
+"MANN",
+"MANY",
+"MARC",
+"MARE",
+"MARK",
+"MARS",
+"MART",
+"MARY",
+"MASH",
+"MASK",
+"MASS",
+"MAST",
+"MATE",
+"MATH",
+"MAUL",
+"MAYO",
+"MEAD",
+"MEAL",
+"MEAN",
+"MEAT",
+"MEEK",
+"MEET",
+"MELD",
+"MELT",
+"MEMO",
+"MEND",
+"MENU",
+"MERT",
+"MESH",
+"MESS",
+"MICE",
+"MIKE",
+"MILD",
+"MILE",
+"MILK",
+"MILL",
+"MILT",
+"MIMI",
+"MIND",
+"MINE",
+"MINI",
+"MINK",
+"MINT",
+"MIRE",
+"MISS",
+"MIST",
+"MITE",
+"MITT",
+"MOAN",
+"MOAT",
+"MOCK",
+"MODE",
+"MOLD",
+"MOLE",
+"MOLL",
+"MOLT",
+"MONA",
+"MONK",
+"MONT",
+"MOOD",
+"MOON",
+"MOOR",
+"MOOT",
+"MORE",
+"MORN",
+"MORT",
+"MOSS",
+"MOST",
+"MOTH",
+"MOVE",
+"MUCH",
+"MUCK",
+"MUDD",
+"MUFF",
+"MULE",
+"MULL",
+"MURK",
+"MUSH",
+"MUST",
+"MUTE",
+"MUTT",
+"MYRA",
+"MYTH",
+"NAGY",
+"NAIL",
+"NAIR",
+"NAME",
+"NARY",
+"NASH",
+"NAVE",
+"NAVY",
+"NEAL",
+"NEAR",
+"NEAT",
+"NECK",
+"NEED",
+"NEIL",
+"NELL",
+"NEON",
+"NERO",
+"NESS",
+"NEST",
+"NEWS",
+"NEWT",
+"NIBS",
+"NICE",
+"NICK",
+"NILE",
+"NINA",
+"NINE",
+"NOAH",
+"NODE",
+"NOEL",
+"NOLL",
+"NONE",
+"NOOK",
+"NOON",
+"NORM",
+"NOSE",
+"NOTE",
+"NOUN",
+"NOVA",
+"NUDE",
+"NULL",
+"NUMB",
+"OATH",
+"OBEY",
+"OBOE",
+"ODIN",
+"OHIO",
+"OILY",
+"OINT",
+"OKAY",
+"OLAF",
+"OLDY",
+"OLGA",
+"OLIN",
+"OMAN",
+"OMEN",
+"OMIT",
+"ONCE",
+"ONES",
+"ONLY",
+"ONTO",
+"ONUS",
+"ORAL",
+"ORGY",
+"OSLO",
+"OTIS",
+"OTTO",
+"OUCH",
+"OUST",
+"OUTS",
+"OVAL",
+"OVEN",
+"OVER",
+"OWLY",
+"OWNS",
+"QUAD",
+"QUIT",
+"QUOD",
+"RACE",
+"RACK",
+"RACY",
+"RAFT",
+"RAGE",
+"RAID",
+"RAIL",
+"RAIN",
+"RAKE",
+"RANK",
+"RANT",
+"RARE",
+"RASH",
+"RATE",
+"RAVE",
+"RAYS",
+"READ",
+"REAL",
+"REAM",
+"REAR",
+"RECK",
+"REED",
+"REEF",
+"REEK",
+"REEL",
+"REID",
+"REIN",
+"RENA",
+"REND",
+"RENT",
+"REST",
+"RICE",
+"RICH",
+"RICK",
+"RIDE",
+"RIFT",
+"RILL",
+"RIME",
+"RING",
+"RINK",
+"RISE",
+"RISK",
+"RITE",
+"ROAD",
+"ROAM",
+"ROAR",
+"ROBE",
+"ROCK",
+"RODE",
+"ROIL",
+"ROLL",
+"ROME",
+"ROOD",
+"ROOF",
+"ROOK",
+"ROOM",
+"ROOT",
+"ROSA",
+"ROSE",
+"ROSS",
+"ROSY",
+"ROTH",
+"ROUT",
+"ROVE",
+"ROWE",
+"ROWS",
+"RUBE",
+"RUBY",
+"RUDE",
+"RUDY",
+"RUIN",
+"RULE",
+"RUNG",
+"RUNS",
+"RUNT",
+"RUSE",
+"RUSH",
+"RUSK",
+"RUSS",
+"RUST",
+"RUTH",
+"SACK",
+"SAFE",
+"SAGE",
+"SAID",
+"SAIL",
+"SALE",
+"SALK",
+"SALT",
+"SAME",
+"SAND",
+"SANE",
+"SANG",
+"SANK",
+"SARA",
+"SAUL",
+"SAVE",
+"SAYS",
+"SCAN",
+"SCAR",
+"SCAT",
+"SCOT",
+"SEAL",
+"SEAM",
+"SEAR",
+"SEAT",
+"SEED",
+"SEEK",
+"SEEM",
+"SEEN",
+"SEES",
+"SELF",
+"SELL",
+"SEND",
+"SENT",
+"SETS",
+"SEWN",
+"SHAG",
+"SHAM",
+"SHAW",
+"SHAY",
+"SHED",
+"SHIM",
+"SHIN",
+"SHOD",
+"SHOE",
+"SHOT",
+"SHOW",
+"SHUN",
+"SHUT",
+"SICK",
+"SIDE",
+"SIFT",
+"SIGH",
+"SIGN",
+"SILK",
+"SILL",
+"SILO",
+"SILT",
+"SINE",
+"SING",
+"SINK",
+"SIRE",
+"SITE",
+"SITS",
+"SITU",
+"SKAT",
+"SKEW",
+"SKID",
+"SKIM",
+"SKIN",
+"SKIT",
+"SLAB",
+"SLAM",
+"SLAT",
+"SLAY",
+"SLED",
+"SLEW",
+"SLID",
+"SLIM",
+"SLIT",
+"SLOB",
+"SLOG",
+"SLOT",
+"SLOW",
+"SLUG",
+"SLUM",
+"SLUR",
+"SMOG",
+"SMUG",
+"SNAG",
+"SNOB",
+"SNOW",
+"SNUB",
+"SNUG",
+"SOAK",
+"SOAR",
+"SOCK",
+"SODA",
+"SOFA",
+"SOFT",
+"SOIL",
+"SOLD",
+"SOME",
+"SONG",
+"SOON",
+"SOOT",
+"SORE",
+"SORT",
+"SOUL",
+"SOUR",
+"SOWN",
+"STAB",
+"STAG",
+"STAN",
+"STAR",
+"STAY",
+"STEM",
+"STEW",
+"STIR",
+"STOW",
+"STUB",
+"STUN",
+"SUCH",
+"SUDS",
+"SUIT",
+"SULK",
+"SUMS",
+"SUNG",
+"SUNK",
+"SURE",
+"SURF",
+"SWAB",
+"SWAG",
+"SWAM",
+"SWAN",
+"SWAT",
+"SWAY",
+"SWIM",
+"SWUM",
+"TACK",
+"TACT",
+"TAIL",
+"TAKE",
+"TALE",
+"TALK",
+"TALL",
+"TANK",
+"TASK",
+"TATE",
+"TAUT",
+"TEAL",
+"TEAM",
+"TEAR",
+"TECH",
+"TEEM",
+"TEEN",
+"TEET",
+"TELL",
+"TEND",
+"TENT",
+"TERM",
+"TERN",
+"TESS",
+"TEST",
+"THAN",
+"THAT",
+"THEE",
+"THEM",
+"THEN",
+"THEY",
+"THIN",
+"THIS",
+"THUD",
+"THUG",
+"TICK",
+"TIDE",
+"TIDY",
+"TIED",
+"TIER",
+"TILE",
+"TILL",
+"TILT",
+"TIME",
+"TINA",
+"TINE",
+"TINT",
+"TINY",
+"TIRE",
+"TOAD",
+"TOGO",
+"TOIL",
+"TOLD",
+"TOLL",
+"TONE",
+"TONG",
+"TONY",
+"TOOK",
+"TOOL",
+"TOOT",
+"TORE",
+"TORN",
+"TOTE",
+"TOUR",
+"TOUT",
+"TOWN",
+"TRAG",
+"TRAM",
+"TRAY",
+"TREE",
+"TREK",
+"TRIG",
+"TRIM",
+"TRIO",
+"TROD",
+"TROT",
+"TROY",
+"TRUE",
+"TUBA",
+"TUBE",
+"TUCK",
+"TUFT",
+"TUNA",
+"TUNE",
+"TUNG",
+"TURF",
+"TURN",
+"TUSK",
+"TWIG",
+"TWIN",
+"TWIT",
+"ULAN",
+"UNIT",
+"URGE",
+"USED",
+"USER",
+"USES",
+"UTAH",
+"VAIL",
+"VAIN",
+"VALE",
+"VARY",
+"VASE",
+"VAST",
+"VEAL",
+"VEDA",
+"VEIL",
+"VEIN",
+"VEND",
+"VENT",
+"VERB",
+"VERY",
+"VETO",
+"VICE",
+"VIEW",
+"VINE",
+"VISE",
+"VOID",
+"VOLT",
+"VOTE",
+"WACK",
+"WADE",
+"WAGE",
+"WAIL",
+"WAIT",
+"WAKE",
+"WALE",
+"WALK",
+"WALL",
+"WALT",
+"WAND",
+"WANE",
+"WANG",
+"WANT",
+"WARD",
+"WARM",
+"WARN",
+"WART",
+"WASH",
+"WAST",
+"WATS",
+"WATT",
+"WAVE",
+"WAVY",
+"WAYS",
+"WEAK",
+"WEAL",
+"WEAN",
+"WEAR",
+"WEED",
+"WEEK",
+"WEIR",
+"WELD",
+"WELL",
+"WELT",
+"WENT",
+"WERE",
+"WERT",
+"WEST",
+"WHAM",
+"WHAT",
+"WHEE",
+"WHEN",
+"WHET",
+"WHOA",
+"WHOM",
+"WICK",
+"WIFE",
+"WILD",
+"WILL",
+"WIND",
+"WINE",
+"WING",
+"WINK",
+"WINO",
+"WIRE",
+"WISE",
+"WISH",
+"WITH",
+"WOLF",
+"WONT",
+"WOOD",
+"WOOL",
+"WORD",
+"WORE",
+"WORK",
+"WORM",
+"WORN",
+"WOVE",
+"WRIT",
+"WYNN",
+"YALE",
+"YANG",
+"YANK",
+"YARD",
+"YARN",
+"YAWL",
+"YAWN",
+"YEAH",
+"YEAR",
+"YELL",
+"YOGA",
+"YOKE"
+};
+
+/* Encode 8 bytes in 'c' as a string of English words.
+ * Returns a pointer to a static buffer
+ */
+char *
+btoe(engout,c)
+char *c, *engout;
+{
+ char cp[9]; /* add in room for the parity 2 bits*/
+ int p,i ;
+
+ engout[0] = '\0';
+ memcpy(cp, c,8);
+ /* compute parity */
+ for(p = 0,i = 0; i < 64;i += 2)
+ p += extract(cp,i,2);
+
+ cp[8] = (char)p << 6;
+ strncat(engout,&Wp[extract(cp, 0,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,11,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,22,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,33,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,44,11)][0],4);
+ strcat(engout," ");
+ strncat(engout,&Wp[extract(cp,55,11)][0],4);
+#ifdef notdef
+ printf("engout is %s\n\r",engout);
+#endif
+ return(engout);
+}
+
+/* convert English to binary
+ * returns 1 OK - all good words and parity is OK
+ * 0 word not in data base
+ * -1 badly formed in put ie > 4 char word
+ * -2 words OK but parity is wrong
+ */
+int
+etob(out, e)
+char *out;
+char *e;
+{
+ char *word;
+ int i, p, v,l, low,high;
+ char b[9];
+ char input[36];
+
+ if(e == NULL)
+ return -1;
+
+ strncpy(input,e,sizeof(input));
+ memset(b, 0, sizeof(b));
+ memset(out, 0, 8);
+ for(i=0,p=0;i<6;i++,p+=11){
+ if((word = strtok(i == 0 ? input : NULL," ")) == NULL)
+ return -1;
+ l = strlen(word);
+ if(l > 4 || l < 1){
+ return -1;
+ } else if(l < 4){
+ low = 0;
+ high = 570;
+ } else {
+ low = 571;
+ high = 2047;
+ }
+ standard(word);
+ if( (v = wsrch(word,low,high)) < 0 )
+ return 0;
+ insert(b,v,p,11);
+ }
+
+ /* now check the parity of what we got */
+ for(p = 0, i = 0; i < 64; i +=2)
+ p += extract(b, i, 2);
+
+ if( (p & 3) != extract(b, 64,2) )
+ return -2;
+
+ memcpy(out,b,8);
+
+ return 1;
+}
+/* Display 8 bytes as a series of 16-bit hex digits */
+char *
+put8(out,s)
+char *out;
+char *s;
+{
+ sprintf(out,"%02X%02X %02X%02X %02X%02X %02X%02X",
+ s[0] & 0xff,s[1] & 0xff,s[2] & 0xff,
+ s[3] & 0xff,s[4] & 0xff,s[5] & 0xff,
+ s[6] & 0xff,s[7] & 0xff);
+ return out;
+}
+#ifdef notdef
+/* Encode 8 bytes in 'cp' as stream of ascii letters.
+ * Provided as a possible alternative to btoe()
+ */
+char *
+btoc(cp)
+char *cp;
+{
+ int i;
+ static char out[31];
+
+ /* code out put by characters 6 bits each added to 0x21 (!)*/
+ for(i=0;i <= 10;i++){
+ /* last one is only 4 bits not 6*/
+ out[i] = '!'+ extract(cp,6*i,i >= 10 ? 4:6);
+ }
+ out[i] = '\0';
+ return(out);
+}
+#endif
+
+/* Internal subroutines for word encoding/decoding */
+
+/* Dictionary binary search */
+static int
+wsrch(w,low,high)
+char *w;
+int low, high;
+{
+ int i,j;
+
+ for(;;){
+ i = (low + high)/2;
+ if((j = strncmp(w,Wp[i],4)) == 0)
+ return i; /* Found it */
+ if(high == low+1){
+ /* Avoid effects of integer truncation in /2 */
+ if(strncmp(w,Wp[high],4) == 0)
+ return high;
+ else
+ return -1;
+ }
+ if(low >= high)
+ return -1; /* I don't *think* this can happen...*/
+ if(j < 0)
+ high = i; /* Search lower half */
+ else
+ low = i; /* Search upper half */
+ }
+}
+static void
+insert(s, x, start, length)
+char *s;
+int x;
+int start, length;
+{
+ unsigned char cl;
+ unsigned char cc;
+ unsigned char cr;
+ unsigned long y;
+ int shift;
+
+ assert(length <= 11);
+ assert(start >= 0);
+ assert(length >= 0);
+ assert(start +length <= 66);
+
+ shift = ((8 -(( start + length) % 8))%8);
+ y = (long) x << shift;
+ cl = (y >> 16) & 0xff;
+ cc = (y >> 8) & 0xff;
+ cr = y & 0xff;
+ if(shift + length > 16){
+ s[start /8] |= cl;
+ s[start/8 +1] |= cc;
+ s[start/8 +2] |= cr;
+ } else if(shift +length > 8){
+ s[start/8] |= cc;
+ s[start/8 + 1] |= cr;
+ } else {
+ s[start/8] |= cr;
+ }
+}
+
+static void
+standard(word)
+register char *word;
+{
+ while(*word){
+ if(!isascii(*word))
+ break;
+ if(islower(*word))
+ *word = toupper(*word);
+ if(*word == '1')
+ *word = 'L';
+ if(*word == '0')
+ *word = 'O';
+ if(*word == '5')
+ *word = 'S';
+ word++;
+ }
+}
+
+/* Extract 'length' bits from the char array 's' starting with bit 'start' */
+static unsigned long
+extract(s, start, length)
+char *s;
+int start, length;
+{
+ unsigned char cl;
+ unsigned char cc;
+ unsigned char cr;
+ unsigned long x;
+
+ assert(length <= 11);
+ assert(start >= 0);
+ assert(length >= 0);
+ assert(start +length <= 66);
+
+ cl = s[start/8];
+ cc = s[start/8 +1];
+ cr = s[start/8 +2];
+ x = ((long)(cl<<8 | cc) <<8 | cr) ;
+ x = x >> (24 - (length + (start %8)));
+ x =( x & (0xffff >> (16-length) ) );
+ return(x);
+}
+
diff --git a/lib/libskey/skey_crypt.c b/lib/libskey/skey_crypt.c
new file mode 100644
index 000000000000..b61bef08c90b
--- /dev/null
+++ b/lib/libskey/skey_crypt.c
@@ -0,0 +1,37 @@
+/* Author: Wietse Venema, Eindhoven University of Technology. */
+
+#include <string.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <skey.h>
+
+/* skey_crypt - return encrypted UNIX passwd if s/key or regular password ok */
+
+char *skey_crypt(pp, salt, pwd, pwok)
+char *pp;
+char *salt;
+struct passwd *pwd;
+int pwok;
+{
+ struct skey skey;
+ char *p;
+ char *crypt();
+
+ /* Try s/key authentication even when the UNIX password is permitted. */
+
+ if (pwd != 0 && skeylookup(&skey, pwd->pw_name) == 0
+ && skeyverify(&skey, pp) == 0) {
+ /* s/key authentication succeeded */
+ return (pwd->pw_passwd);
+ }
+
+ /* When s/key authentication does not work, always invoke crypt(). */
+
+ p = crypt(pp, salt);
+ if (pwok && pwd != 0 && strcmp(p, pwd->pw_passwd) == 0)
+ return (pwd->pw_passwd);
+
+ /* The user does not exist or entered bad input. */
+
+ return (":");
+}
diff --git a/lib/libskey/skeylogin.c b/lib/libskey/skeylogin.c
new file mode 100644
index 000000000000..f2d41049e1d8
--- /dev/null
+++ b/lib/libskey/skeylogin.c
@@ -0,0 +1,328 @@
+/* Login code for S/KEY Authentication. S/KEY is a trademark
+ * of Bellcore.
+ *
+ * Mink is the former name of the S/KEY authentication system.
+ * Many references for mink may still be found in this program. */
+
+#include <sys/param.h>
+#ifdef QUOTA
+#include <sys/quota.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <skey.h>
+
+#define KEYFILE "/etc/skeykeys"
+
+char *skipspace();
+int skeylookup __P((struct skey *mp,char *name));
+
+#define setpriority(x,y,z) /* nothing */
+
+/* Issue a skey challenge for user 'name'. If successful,
+ * fill in the caller's skey structure and return 0. If unsuccessful
+ * (e.g., if name is unknown) return -1.
+ *
+ * The file read/write pointer is left at the start of the
+ * record.
+ */
+int
+getskeyprompt(mp,name,prompt)
+struct skey *mp;
+char *name;
+char *prompt;
+{
+ int rval;
+
+ sevenbit(name);
+ rval = skeylookup(mp,name);
+ strcpy(prompt,"s/key 55 latour1\n");
+ switch(rval){
+ case -1: /* File error */
+ return -1;
+ case 0: /* Lookup succeeded, return challenge */
+ sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed);
+ return 0;
+ case 1: /* User not found */
+ fclose(mp->keyfile);
+ return -1;
+ }
+ return -1; /* Can't happen */
+}
+/* Return a skey challenge string for user 'name'. If successful,
+ * fill in the caller's skey structure and return 0. If unsuccessful
+ * (e.g., if name is unknown) return -1.
+ *
+ * The file read/write pointer is left at the start of the
+ * record.
+ */
+int
+skeychallenge(mp,name, ss)
+struct skey *mp;
+char *name;
+char *ss;
+{
+ int rval;
+
+ rval = skeylookup(mp,name);
+ switch(rval){
+ case -1: /* File error */
+ return -1;