summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
Diffstat (limited to 'libc')
-rw-r--r--libc/COPYING481
-rw-r--r--libc/Config_sh145
-rw-r--r--libc/KERNEL37
-rw-r--r--libc/Make.defs80
-rw-r--r--libc/Makefile101
-rwxr-xr-xlibc/New_subdir62
-rw-r--r--libc/Pre_main66
-rw-r--r--libc/README59
-rw-r--r--libc/bcc/Config2
-rw-r--r--libc/bcc/Makefile87
-rw-r--r--libc/bcc/__ldivmod.c195
-rw-r--r--libc/bcc/alloca.c50
-rw-r--r--libc/bcc/bcc_bsw.c487
-rw-r--r--libc/bcc/bcc_i386.c149
-rw-r--r--libc/bcc/bcc_int.c162
-rw-r--r--libc/bcc/bcc_io.c189
-rw-r--r--libc/bcc/bcc_long.c479
-rw-r--r--libc/bcc/heap.c184
-rw-r--r--libc/bcc/ldiv.c30
-rw-r--r--libc/bios/Config1
-rw-r--r--libc/bios/Makefile35
-rw-r--r--libc/bios/README10
-rw-r--r--libc/bios/bios.c230
-rw-r--r--libc/bios/bios_vid.c489
-rw-r--r--libc/crt0.c62
-rw-r--r--libc/error/Config2
-rw-r--r--libc/error/Makefile18
-rw-r--r--libc/error/README10
-rw-r--r--libc/error/__assert.c28
-rw-r--r--libc/error/error.c57
-rw-r--r--libc/error/liberror.txt121
-rw-r--r--libc/error/perror.c19
-rw-r--r--libc/error/sys_errlist.c74
-rw-r--r--libc/error/sys_siglist.c38
-rw-r--r--libc/getent/Config1
-rw-r--r--libc/getent/Makefile36
-rw-r--r--libc/getent/__getgrent.c168
-rw-r--r--libc/getent/__getpwent.c99
-rw-r--r--libc/getent/config-grp.h65
-rw-r--r--libc/getent/config.h65
-rw-r--r--libc/getent/fgetgrent.c35
-rw-r--r--libc/getent/fgetpwent.c35
-rw-r--r--libc/getent/getgrgid.c48
-rw-r--r--libc/getent/getgrnam.c51
-rw-r--r--libc/getent/getpw.c51
-rw-r--r--libc/getent/getpwnam.c52
-rw-r--r--libc/getent/getpwuid.c44
-rw-r--r--libc/getent/grent.c57
-rw-r--r--libc/getent/initgroups.c80
-rw-r--r--libc/getent/putpwent.c39
-rw-r--r--libc/getent/pwent.c62
-rw-r--r--libc/getent/test_grp.c107
-rw-r--r--libc/getent/test_pwd.c91
-rw-r--r--libc/getent/utent.c152
-rw-r--r--libc/gtermcap/COPYING339
-rw-r--r--libc/gtermcap/ChangeLog52
-rw-r--r--libc/gtermcap/Makefile19
-rw-r--r--libc/gtermcap/Makefile.old25
-rw-r--r--libc/gtermcap/NEWS12
-rw-r--r--libc/gtermcap/README14
-rw-r--r--libc/gtermcap/termcap.c827
-rw-r--r--libc/gtermcap/tparam.c330
-rw-r--r--libc/gtermcap/version.c2
-rw-r--r--libc/i386fp/Config1
-rw-r--r--libc/i386fp/Makefile38
-rw-r--r--libc/i386fp/bccfp.tex0
-rw-r--r--libc/i386fp/changes30
-rw-r--r--libc/i386fp/fabs.x17
-rw-r--r--libc/i386fp/fadd.x485
-rw-r--r--libc/i386fp/fcomp.x89
-rw-r--r--libc/i386fp/fdiv.x312
-rw-r--r--libc/i386fp/fmul.x150
-rw-r--r--libc/i386fp/fpbsr.x25
-rw-r--r--libc/i386fp/fperr.c44
-rw-r--r--libc/i386fp/fperr.h8
-rw-r--r--libc/i386fp/fperror.x126
-rw-r--r--libc/i386fp/fplib.h43
-rw-r--r--libc/i386fp/fptoi.x117
-rw-r--r--libc/i386fp/fpulld.x20
-rw-r--r--libc/i386fp/fpullf.x101
-rw-r--r--libc/i386fp/fpushd.x60
-rw-r--r--libc/i386fp/fpushf.x74
-rw-r--r--libc/i386fp/fpushi.x126
-rw-r--r--libc/i386fp/frexp.x66
-rw-r--r--libc/i386fp/ftst.x28
-rw-r--r--libc/i386fp/ldexp.x74
-rw-r--r--libc/i386fp/modf.c14
-rw-r--r--libc/i386fp/test.c118
-rw-r--r--libc/i386sys/Config1
-rw-r--r--libc/i386sys/Makefile52
-rw-r--r--libc/i386sys/dirent.c106
-rw-r--r--libc/i386sys/exec.c292
-rw-r--r--libc/i386sys/mksyscall143
-rw-r--r--libc/i386sys/signal.c99
-rw-r--r--libc/i386sys/syscall.dat155
-rw-r--r--libc/i386sys/syslibc.c255
-rw-r--r--libc/include/a.out.h115
-rw-r--r--libc/include/ar.h18
-rw-r--r--libc/include/assert.h23
-rw-r--r--libc/include/bsd/bsd.h49
-rw-r--r--libc/include/bsd/errno.h9
-rw-r--r--libc/include/bsd/sgtty.h113
-rw-r--r--libc/include/bsd/signal.h25
-rw-r--r--libc/include/bsd/stdlib.h12
-rw-r--r--libc/include/bsd/sys/ttychars.h3
-rw-r--r--libc/include/bsd/tzfile.h10
-rw-r--r--libc/include/bsd/unistd.h4
-rw-r--r--libc/include/ctype.h38
-rw-r--r--libc/include/dirent.h52
-rw-r--r--libc/include/dos.h36
-rw-r--r--libc/include/errno.h25
-rw-r--r--libc/include/fcntl.h20
-rw-r--r--libc/include/features.h36
-rw-r--r--libc/include/getopt.h17
-rw-r--r--libc/include/grp.h37
-rw-r--r--libc/include/limits.h57
-rw-r--r--libc/include/malloc.h30
-rw-r--r--libc/include/math.h0
-rw-r--r--libc/include/memory.h1
-rw-r--r--libc/include/paths.h21
-rw-r--r--libc/include/pwd.h40
-rw-r--r--libc/include/regexp.h21
-rw-r--r--libc/include/regmagic.h5
-rw-r--r--libc/include/search.h94
-rw-r--r--libc/include/setjmp.h30
-rw-r--r--libc/include/signal.h85
-rw-r--r--libc/include/stdarg.h47
-rw-r--r--libc/include/stddef.h28
-rw-r--r--libc/include/stdio.h129
-rw-r--r--libc/include/stdlib.h46
-rw-r--r--libc/include/string.h53
-rw-r--r--libc/include/strings.h1
-rw-r--r--libc/include/sys/cdefs.h36
-rw-r--r--libc/include/sys/errno.h1
-rw-r--r--libc/include/sys/fcntl.h1
-rw-r--r--libc/include/sys/file.h35
-rw-r--r--libc/include/sys/ioctl.h9
-rw-r--r--libc/include/sys/mman.h0
-rw-r--r--libc/include/sys/param.h18
-rw-r--r--libc/include/sys/resource.h73
-rw-r--r--libc/include/sys/signal.h1
-rw-r--r--libc/include/sys/stat.h64
-rw-r--r--libc/include/sys/time.h1
-rw-r--r--libc/include/sys/times.h21
-rw-r--r--libc/include/sys/types.h2
-rw-r--r--libc/include/sys/utsname.h18
-rw-r--r--libc/include/sys/vm86.h125
-rw-r--r--libc/include/sys/wait.h77
-rw-r--r--libc/include/termcap.h21
-rw-r--r--libc/include/termio.h1
-rw-r--r--libc/include/termios.h24
-rw-r--r--libc/include/time.h68
-rw-r--r--libc/include/unistd.h37
-rw-r--r--libc/include/utime.h15
-rw-r--r--libc/include/utmp.h52
-rw-r--r--libc/include/varargs.h12
-rw-r--r--libc/kinclude/Config1
-rw-r--r--libc/kinclude/Makefile21
-rw-r--r--libc/kinclude/arch/errno.h127
-rw-r--r--libc/kinclude/arch/ioctl.h9
-rw-r--r--libc/kinclude/arch/types.h48
-rw-r--r--libc/kinclude/linuxmt/errno.h1
-rw-r--r--libc/kinclude/linuxmt/fcntl.h70
-rw-r--r--libc/kinclude/linuxmt/ioctl.h1
-rw-r--r--libc/kinclude/linuxmt/stat.h57
-rw-r--r--libc/kinclude/linuxmt/termios.h260
-rw-r--r--libc/kinclude/linuxmt/types.h34
-rw-r--r--libc/malloc1/Config1
-rw-r--r--libc/malloc1/Makefile23
-rw-r--r--libc/malloc1/README9
-rw-r--r--libc/malloc1/malloc.c546
-rw-r--r--libc/malloc1/malloc.h30
-rw-r--r--libc/malloc2/Config1
-rw-r--r--libc/malloc2/Makefile13
-rw-r--r--libc/malloc2/README19
-rw-r--r--libc/malloc2/malloc.c126
-rw-r--r--libc/malloc2/malloc.h21
-rw-r--r--libc/malloc2/stack.c10
-rw-r--r--libc/misc/Config1
-rw-r--r--libc/misc/Makefile62
-rw-r--r--libc/misc/aliases.c110
-rw-r--r--libc/misc/atexit.c102
-rw-r--r--libc/misc/atoi.c24
-rw-r--r--libc/misc/atol.c24
-rw-r--r--libc/misc/bsearch.c46
-rw-r--r--libc/misc/cputype.c357
-rw-r--r--libc/misc/crypt.c50
-rw-r--r--libc/misc/ctype.c68
-rw-r--r--libc/misc/getcwd.c109
-rw-r--r--libc/misc/getenv.c26
-rw-r--r--libc/misc/getopt.c122
-rw-r--r--libc/misc/itoa.c24
-rw-r--r--libc/misc/lsearch.c47
-rw-r--r--libc/misc/ltoa.c37
-rw-r--r--libc/misc/ltostr.c43
-rw-r--r--libc/misc/popen.c42
-rw-r--r--libc/misc/putenv.c56
-rw-r--r--libc/misc/qsort.c166
-rw-r--r--libc/misc/rand.c61
-rw-r--r--libc/misc/setenv.c97
-rw-r--r--libc/misc/strtod.c100
-rw-r--r--libc/misc/strtol.c106
-rw-r--r--libc/misc/system.c49
-rw-r--r--libc/msdos/Config1
-rw-r--r--libc/msdos/Makefile45
-rw-r--r--libc/msdos/Notes8
-rw-r--r--libc/msdos/i86.c193
-rw-r--r--libc/msdos/msdos.c646
-rw-r--r--libc/msdos/time.c63
-rw-r--r--libc/regexp/Config1
-rw-r--r--libc/regexp/Makefile27
-rw-r--r--libc/regexp/Makefile.org63
-rw-r--r--libc/regexp/README84
-rw-r--r--libc/regexp/README.rdb6
-rw-r--r--libc/regexp/patch.132
-rw-r--r--libc/regexp/patch.227
-rw-r--r--libc/regexp/patch.346
-rw-r--r--libc/regexp/patch.465
-rw-r--r--libc/regexp/regerror.c14
-rw-r--r--libc/regexp/regexp.3176
-rw-r--r--libc/regexp/regexp.c1213
-rw-r--r--libc/regexp/regexp.h21
-rw-r--r--libc/regexp/regmagic.h5
-rw-r--r--libc/regexp/regsub.c82
-rw-r--r--libc/regexp/tests127
-rw-r--r--libc/regexp/timer.c182
-rw-r--r--libc/regexp/try.c238
-rw-r--r--libc/stdio2/Config4
-rw-r--r--libc/stdio2/Makefile52
-rw-r--r--libc/stdio2/printf.c376
-rw-r--r--libc/stdio2/scanf.c521
-rw-r--r--libc/stdio2/stdio.c814
-rw-r--r--libc/stdio2/stdio.h129
-rw-r--r--libc/string/Config1
-rw-r--r--libc/string/Makefile30
-rw-r--r--libc/string/strcasecmp.c26
-rw-r--r--libc/string/strcspn.c32
-rw-r--r--libc/string/string.c669
-rw-r--r--libc/string/string.h53
-rw-r--r--libc/string/strncasecmp.c28
-rw-r--r--libc/string/strpbrk.c21
-rw-r--r--libc/string/strsep.c38
-rw-r--r--libc/string/strspn.c44
-rw-r--r--libc/string/strstr.c54
-rw-r--r--libc/string/strtok.c71
-rw-r--r--libc/syscall/Config1
-rw-r--r--libc/syscall/Makefile64
-rw-r--r--libc/syscall/TODO5
-rw-r--r--libc/syscall/dirent.c106
-rw-r--r--libc/syscall/exec.c292
-rw-r--r--libc/syscall/mksyscall289
-rw-r--r--libc/syscall/setjmp.c56
-rw-r--r--libc/syscall/signal.c99
-rw-r--r--libc/syscall/syscall.dat142
-rw-r--r--libc/syscall/syscall.dat.chad55
-rw-r--r--libc/syscall/syscall.dat.code70
-rw-r--r--libc/syscall/syscall.dat.rdb142
-rw-r--r--libc/syscall/syslib0.c258
-rw-r--r--libc/syscall/syslibc.c168
-rw-r--r--libc/termios/Config1
-rw-r--r--libc/termios/Makefile30
-rw-r--r--libc/termios/README7
-rw-r--r--libc/termios/termios.c220
-rw-r--r--libc/termios/ttyname.c45
-rw-r--r--libc/time/Config1
-rw-r--r--libc/time/Makefile15
-rw-r--r--libc/time/README8
-rw-r--r--libc/time/asc_conv.c49
-rw-r--r--libc/time/asctime.c15
-rw-r--r--libc/time/ctime.c26
-rw-r--r--libc/time/gmtime.c15
-rw-r--r--libc/time/localtime.c22
-rw-r--r--libc/time/tm_conv.c138
273 files changed, 24532 insertions, 0 deletions
diff --git a/libc/COPYING b/libc/COPYING
new file mode 100644
index 0000000..eb685a5
--- /dev/null
+++ b/libc/COPYING
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/libc/Config_sh b/libc/Config_sh
new file mode 100644
index 0000000..6c93784
--- /dev/null
+++ b/libc/Config_sh
@@ -0,0 +1,145 @@
+#!/bin/sh -
+# Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+main()
+{
+ rm -f .config.tmp
+ ALLON=no
+
+ if [ -f .config.lst ]
+ then grep '^[^:]*:+:' .config.lst > .config.tmp
+ if [ ! -s .config.tmp ]
+ then ALLON=yes
+ fi
+ else ALLON=yes
+ fi
+
+ egrep -v '^#|^$' /dev/null */[Cc]onfig | \
+ sed -e 's./.:.' -e 's/[ ]*:[ ]*/:/g' >> .config.tmp 2>/dev/null
+ ls */Makefile | sed 's-/Makefile-:+:+-' >> .config.tmp
+ sort .config.tmp > .config.lst
+
+ unset_dups
+
+ if [ ! -s .config.lst ]
+ then echo 'No configuration options'
+ exit 0
+ fi
+
+ CHANGED=0
+ RUNNING=1
+ [ "$DIST" != "" ] && {
+ RUNNING=0
+ echo 'Using default configuration'
+ }
+ while [ $RUNNING = 1 ]
+ do
+ display
+ echo
+ echo -n 'Option to flip [or quit] >'
+ read n
+ v=""
+ case "$n" in
+ [qQ]* ) RUNNING=0
+ ;;
+ [0-9] ) v=$n ;;
+ [0-9][0-9] ) v=$n ;;
+ * ) echo '\007'
+ ;;
+ esac
+
+ if [ "$v" != "" ]
+ then set_option $v
+ fi
+ done
+
+ if [ "$CHANGED" = 1 -a \( -f libc.a -o -f crt0.o \) ]
+ then echo '
+ You should now run a "make clean" to clean out the libc.a
+'
+ exit 1
+ fi
+
+ exit 0
+}
+
+display()
+{
+ clear
+ echo 'Configuration options'
+ echo
+ awk -F: < .config.lst '{
+ if( $3 == "+" ) next;
+ if( $2 == "+" ) { flags[$1] = 1; next; }
+
+ printf("%2d) ", ++count);
+ if( $1 in flags ) printf("(ON) ");
+ else printf("(OFF) ");
+ if( $2 == "Config" ) printf(" "); else printf("* ");
+ printf("%s\n", $4);
+ }'
+}
+
+unset_dups()
+{
+ awk -F: < .config.lst '{
+ if( $2 == "+" && $3 == "+") { if( noco[$1] != 1 ) noco[$1] = 2; next; }
+ if( $2 == "+" ) { flags[$1] = 1; next; }
+ if( "'$ALLON'" == "yes" && $2 == "Config" ) flags[$1] = 1;
+
+ if( $1 in flags )
+ {
+ if( $3 in gottype )
+ ;
+ else
+ {
+ printf("%s:+:\n", $1);
+ gottype[$3] = 1;
+ }
+ }
+ noco[$1] = 1;
+ printf("%s\n", $0);
+ } END {
+ for(i in noco)
+ if( noco[i] == 2 )
+ printf("%s:+:+\n", i);
+ }' | sort > .config.tmp
+ ALLON=no
+ mv -f .config.tmp .config.lst
+}
+
+set_option()
+{
+ rm -f .config.tmp1
+ awk -F: < .config.lst '{
+ if( $2 == "+" && $3 == "+" ) { print $0; next; }
+ if( $2 == "+" ) { flags[$1] = 1; next; }
+
+ if( ++cnt == '$1' )
+ {
+ if( $1 in flags )
+ ;
+ else
+ printf("%s:+:\n", $1) > ".config.tmp1";
+ printf("%s\n", $0) > ".config.tmp1";
+ }
+ else
+ {
+ if( $1 in flags )
+ printf("%s:+:\n", $1);
+ printf("%s\n", $0);
+ }
+ }' > .config.tmp2
+ if [ -f .config.tmp1 ]
+ then CHANGED=1
+ else echo 'Cannot change that option!'
+ sleep 2
+ fi
+ cat .config.tmp[12] > .config.lst
+ rm .config.tmp[12]
+ unset_dups
+}
+
+main
diff --git a/libc/KERNEL b/libc/KERNEL
new file mode 100644
index 0000000..6f83f90
--- /dev/null
+++ b/libc/KERNEL
@@ -0,0 +1,37 @@
+
+KERNEL SYSTEM CALL INTERFACE:
+The kernel system calls are all done through interrupt 0x80
+All parameters are passed in the 'AX,BX,CX,DX,DI,SI' registers.
+The AX register contains the system call number.
+The BX,CX,DX,DI,SI registers contain the first 5 arguments from the stack.
+(NB If the syscall is know to have less than 5 args the rest are not loaded)
+On return from the syscall AX has the return value.
+If AX is -ve then errno= -AX and return val = -1;
+
+The system calls are named in syscall/syscall.dat.
+There is a script syscall/mksyscall which generates the assembler for the
+system calls, near the top there is a line:
+ COMPACT=1
+If this is changed to
+ COMPACT=0
+the code generated will be slightly faster and larger.
+
+-RDB
+
+KERNEL SIGNAL INTERFACE:
+ It is assumed the kernel will never pass a signal to the userspace
+ routine unless it's _explicitly_ asked for!
+
+The Kernel need only save space for _one_ function pointer
+(to system_signal) and must deal with SIG_DFL and SIG_IGN
+in kernel space.
+
+When a signal is required the kernel must set all the registers as if
+returning from a interrupt normally then push the number of the signal
+to be generated, push the current pc value, then set the pc to the
+address of the 'system_signal' function.
+
+This is in syscall/signal.c
+
+-RDB
+
diff --git a/libc/Make.defs b/libc/Make.defs
new file mode 100644
index 0000000..2b1eca6
--- /dev/null
+++ b/libc/Make.defs
@@ -0,0 +1,80 @@
+############################################################################
+# Normal standard 8086 code
+
+ifeq ($(PLATFORM),i86-ELKS)
+OBJ=crt0.o
+LIBC=$(TOP)/libc.a
+ARCH=-Mn
+LIB_CPU=i86
+LIB_OS=ELKS
+endif
+
+##############################################################################
+# 8086 elks code With "Caller saves" and "First arg in AX"
+
+ifeq ($(PLATFORM),i86-FAST)
+OBJ=crt0.o
+LIBC=$(TOP)/libc_f.a
+ARCH=-Mf
+LIB_CPU=i86
+LIB_OS=ELKS
+endif
+
+##############################################################################
+# Standalone executable
+
+ifeq ($(PLATFORM),i86-BIOS)
+OBJ=crt0.o
+LIBC=$(TOP)/libc_s.a
+ARCH=-Ms
+LIB_CPU=i86
+LIB_OS=BIOS
+endif
+
+##############################################################################
+# MSDOS COM file (msdos libs don't support "First arg in AX")
+
+ifeq ($(PLATFORM),i86-DOS)
+OBJ=crt0.o
+LIBC=$(TOP)/libdos.a
+ARCH=-Md
+LIB_CPU=i86
+LIB_OS=DOS
+endif
+
+##############################################################################
+# BCC 386.
+
+ifeq ($(PLATFORM),i386-BCC)
+OBJ=crt3.o
+LIBC=$(TOP)/libc3.a
+ARCH=-Ml
+LIB_CPU=i386
+LIB_OS=ELKS
+endif
+
+##############################################################################
+# Anonymous
+
+ifeq ($(PLATFORM),ANON)
+OBJ=crt0.o
+LIBC=$(TOP)/libc.a
+ARCH=
+LIB_CPU=Bigbad
+LIB_OS=Nice
+CC=cc
+CCFLAGS=-I$(TOP)/include
+endif
+
+##############################################################################
+# Unknown
+
+ifeq ($(LIB_CPU),)
+OBJ=crtX.o
+LIBC=$(TOP)/libc_X.a
+ARCH=
+LIB_CPU=Unknown
+LIB_OS=Unknown
+endif
+
+.PRECIOUS: $(LIBC)
diff --git a/libc/Makefile b/libc/Makefile
new file mode 100644
index 0000000..83aded9
--- /dev/null
+++ b/libc/Makefile
@@ -0,0 +1,101 @@
+# Copyright (C) 1996,1997 Robert de Bath <robert@mayday.cix.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+ifeq ($(TOPDIR),)
+# This should work, but ..
+TOP=..
+else
+TOP=$(TOPDIR)/libc
+endif
+
+VERMAJOR=0
+VERMINOR=0
+VERPATCH=11
+VER=$(VERMAJOR).$(VERMINOR).$(VERPATCH)
+
+CC=bcc
+CCFLAGS=-I -I$(TOP)/include
+DEFS=-D__LIBC__
+
+include Make.defs
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+############################################################################
+
+MAKEPASS= \
+ LIBC='$(LIBC)' CC='$(CC)' ARCH='$(ARCH)' CCFLAGS='$(CCFLAGS)' \
+ DEFS='$(DEFS)' LIB_CPU='$(LIB_CPU)' LIB_OS='$(LIB_OS)' \
+
+
+all: $(OBJ) $(LIBC)
+ @:
+
+$(LIBC): transfer .config.dir
+ @for i in `cat .config.dir` ; do \
+ $(MAKE) $(MAKEPASS) -C $$i all || exit 1 ; \
+ done
+
+crt3.o: crt0.c Makefile
+ $(CC) -c $(CFLAGS) -D__LIBC_VER__='"$(VER)"' -o $@ crt0.c
+
+crt0.o: crt0.c Makefile
+ $(CC) -c $(CFLAGS) -D__LIBC_VER__='"$(VER)"' -o $@ crt0.c
+
+crtX.o:
+ @echo "You need to define the 'PLATFORM=...' variable"
+ @exit 1
+
+############################################################################
+
+transfer: .config.dir
+ @for i in `cat .config.dir`; do \
+ grep -s '^transfer' $$i/Makefile && $(MAKE) -s -C $$i $@ ; \
+ done ; echo -n
+ @[ -f kinclude/Used ] || \
+ { rm -f include/linuxmt ; \
+ ln -s $(ELKSSRC)/include/linuxmt include ; }
+
+############################################################################
+
+realclean: clean noconfig
+
+clean:
+ rm -f *.o *.a
+ @for i in */Makefile ; do \
+ $(MAKE) -C `dirname $$i` $@ || exit 1 ; \
+ done
+
+############################################################################
+
+install_incl:
+ rm -rf $(BCCHOME)/include
+ cp -pr include $(BCCHOME)/include
+ if [ -f kinclude/Used ] ; \
+ then cp -pr kinclude/arch $(BCCHOME)/include/arch ; \
+ else rm -rf $(BCCHOME)/include/linuxmt ; \
+ ln -s $(ELKSSRC)/include/linuxmt $(BCCHOME)/include ; \
+ fi
+ -chown -R root:root $(BCCHOME)/include 2>/dev/null
+ -chmod -R u=rwX,og=rX $(BCCHOME)/include
+
+############################################################################
+
+config:
+ sh Config_sh
+
+.config.dir: .config.lst
+ @grep '^[^:]*:+:' < .config.lst | sed 's/:.*//' > .config.tmp
+ @mv -f .config.tmp .config.dir
+
+.config.lst: Config_sh
+ sh Config_sh
+
+noconfig:
+ rm -f .config.dir .config.lst .config.tmp
+
+############################################################################
+
+Libc_version:
+ echo $(VER) > ../Libc_version
diff --git a/libc/New_subdir b/libc/New_subdir
new file mode 100755
index 0000000..e3803c7
--- /dev/null
+++ b/libc/New_subdir
@@ -0,0 +1,62 @@
+#!/bin/sh -
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+cat <<!
+This is a shell script to create the bare bones for a new part of the
+libc package. To use it you just invoke it with the directory name
+you want to create as it's argument, it'll then create that directory
+and put a few files in it.
+
+!
+if [ "$1" = "" ] ; then exit 1 ; fi
+if [ -e "$1" ]
+then echo "There is already something called '$1' in the current directory"
+ echo "You'll have to remove it or rename it first"
+ exit 1
+fi
+
+YEAR=`date +%Y`
+NAME="`finger -s $LOGNAME | head -2 | tail -1 | cut -b10-30 | sed 's/ *$//'`"
+EMAIL="$LOGNAME@`hostname -f`"
+FNAME="`echo $NAME | cut -d\ -f1`"
+
+mkdir $1
+cat <<! > $1/Makefile
+# Copyright (C) $YEAR $NAME <$EMAIL>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+OBJ=$1.o
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)($(OBJ))
+ @:
+clean:
+ rm -f *.o libc.a
+!
+cat <<! > $1/README
+Copyright (C) $YEAR $NAME <$EMAIL>
+This file is part of the Linux-8086 C library and is distributed
+under the GNU Library General Public License.
+
+There's currently nothing special about $1.
+
+-$FNAME
+!
+cat <<! > $1/$1.c
+/* Copyright (C) $YEAR $NAME <$EMAIL>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+$1()
+{
+ /* FIXME :-) */
+}
+!
+
+echo "Ok, the directory $1 has now been created ..."
+exit 0
diff --git a/libc/Pre_main b/libc/Pre_main
new file mode 100644
index 0000000..0b3bec2
--- /dev/null
+++ b/libc/Pre_main
@@ -0,0 +1,66 @@
+
+There is now support for calling functions before main and from inside the
+exit() function.
+
+The exit processing uses the standard 'atexit' and 'on_exit' functions
+see the normal man pages.
+
+Execution of code before main is Linux-8086 (actually BCC) specific; the
+method works like this:
+
+/**********************/
+long global_var_that_needs_init;
+
+#ifdef __AS386_16__
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .word _init_vars ! Pointer to the autorun function
+ .word no_op ! Space filler cause segs are padded to 4 bytes.
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+#ifdef __AS386_32__
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .long _init_vars ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+static void init_vars()
+{
+ time(&global_var_that_needs_init);
+}
+/**********************/
+
+The most important part is that the asm code _MUST_ be compiled into the
+same object file as the variable that is being initialised.
+
+If this is not so the init_vars function will not be linked in and will
+not be executed.
+
+Also do note that the init functions are called in essentially random order
+(It's actually the order that they appear in the executable) so you must be
+careful not to call any routines that have their own autostart from inside
+your autostart. Nevertheless you should try to ensure that your routines
+will fail gracefully if they are called before the initilisation routine.
+
+If you do not know if a routine has an autostart create a test program
+calling the routine and compile with:
+
+ bcc -0 [other_stuff] -M test.c | sort +2 | more
+
+Look down the list for lines like this:
+
+ crt0 ZP_safety 1 00000000 R
+ crt0 auto_start 1 00000008 R
+ objname auto_func 1 00000008 R <<****
+ crt0 data_start 2 00000010 R
+ crt0 _environ 3 00000010 R
+
+The line marked is an autostart function call.
+
+Robert.
diff --git a/libc/README b/libc/README
new file mode 100644
index 0000000..6f45f26
--- /dev/null
+++ b/libc/README
@@ -0,0 +1,59 @@
+SYSTEM CALLS
+The system call table (syscalls/syscall.dat) is constantly changing, using
+skewed versions is _very_ likely to give you segfaults and strange behaviour.
+For this lib you should use the same version of elksemu.
+The system call table will only be frozen when the linux-86 kernel is
+running and reasonably stable. The 386 version is using a distinct list
+that matches the Linux-i386 syscall list.
+
+THE COMPILER
+You should use the versions of bcc, unproto, as86, ld86 and elksemu that
+are in this version of the combined development environment. Some other
+versions will work but often they'll just appear to work or not work at
+all. The original bcc-cc1 won't pickup the right header files, the
+original ld86 won't generate COM files or 386-Linux files and looks in
+the wrong place for crt0.o and libc.a.
+
+Main Subdirectories.
+
+bcc Lots of BCC helper functions
+bios Minimal 'system' calls for standalone executables.
+error The C error functions.
+getent Routines for /etc/group, /etc/passwd and /etc/utmp
+gtermcap GNU termcap
+i386fp BCC's floating point routines for 386 code.
+include Some include files, some new others Glib or Glib hacked.
+kinclude Kernel include files, here for now.
+malloc1 Robert's malloc routines
+malloc2 Joel's malloc routines
+misc Various larger functions
+msdos This is the syscall directory for msdos.
+regexp Standard regular expression parser
+stdio2 Robert's standard I/O
+string The functions for string.h
+syscall All the system call functions, and some tied lib ones.
+termios Termimal mode control.
+time Unix time related functions.
+
+Directory structure:
+
+ The top Makefile will try to call any "Makefile" it finds in a
+ subdirectory, so to add a new chunk to "libc.a" just drop in
+ the directory a Makefile that understands "make clean" and
+ "make libc.a" (Which must also update ../libc.a)
+ There's now a tiny script (New_subdir) that'll do this.
+
+ Make config will look in all subdirectories for a file 'Config'
+ any it finds will be displayed and can be used to switch a directory
+ on or off.
+
+ The exit(rv) function is already defined. It will call the contents
+ of the function pointer (*__cleanup)() before it calls _exit();
+ This pointer should be used through the 'atexit' or 'on_exit' lib
+ functions. (See standard man pages)
+
+ If you need to call something before main see the file 'Pre_main'.
+
+-Robert
+
+-=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=-
diff --git a/libc/bcc/Config b/libc/bcc/Config
new file mode 100644
index 0000000..0bfed09
--- /dev/null
+++ b/libc/bcc/Config
@@ -0,0 +1,2 @@
+
+bcclib: Library of bcc helper functions
diff --git a/libc/bcc/Makefile b/libc/bcc/Makefile
new file mode 100644
index 0000000..f4cce3d
--- /dev/null
+++ b/libc/bcc/Makefile
@@ -0,0 +1,87 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+# Support for integer arithmetic
+ifeq ($(LIB_CPU),i86)
+IOBJ=__idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o
+ISRC=bcc_int.c
+endif
+
+# Support for integer arithmetic when compiling for the i386
+ifeq ($(LIB_CPU),i386)
+ISRC=bcc_i386.c
+IOBJ=__idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o \
+ __divsi3.o
+endif
+
+# Support for long arithmetic on little-endian (normal) longs
+LSRC=bcc_long.c
+LOBJ=__laddl.o __landl.o __lcmpl.o __lcoml.o __ldecl.o __ldivl.o __ldivul.o \
+ __leorl.o __lincl.o __lmodl.o __lmodul.o __lmull.o __lnegl.o __lorl.o \
+ __lsll.o __lsrl.o __lsrul.o __lsubl.o __ltstl.o
+
+# Memory allocation primitives
+AOBJ=errno.o __brk_addr.o sbrk.o brk.o
+ASRC=heap.c
+
+# Support for long arithmetic on big-endian (words-swapped) longs
+RSRC=bcc_bsw.c
+ROBJ=__laddb.o __landb.o __lcmpb.o __lcomb.o __ldecb.o __ldivb.o __ldivub.o \
+ __leorb.o __lincb.o __lmodb.o __lmodub.o __lmulb.o __lnegb.o __lorb.o \
+ __lslb.o __lsrb.o __lsrub.o __lsubb.o __ltstb.o
+
+# Miscellaneous I/O and far access junk
+PSRC=bcc_io.c
+POBJ=__inport.o __inportb.o __outport.o __outportb.o __peekb.o __peekw.o \
+ __pokeb.o __pokew.o
+
+ifeq ($(LIB_CPU),i86)
+OBJ=__ldivmod.o $(IOBJ) $(LOBJ) $(AOBJ)
+endif
+ifeq ($(LIB_CPU),i386)
+OBJ=$(IOBJ) $(AOBJ)
+endif
+
+OLDOBJ=$(ROBJ) $(POBJ)
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+ifneq ($(OBJ),)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(IOBJ)): $(ISRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(LOBJ)): $(LSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(ROBJ)): $(RSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(POBJ)): $(PSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/bcc/__ldivmod.c b/libc/bcc/__ldivmod.c
new file mode 100644
index 0000000..4cb6d77
--- /dev/null
+++ b/libc/bcc/__ldivmod.c
@@ -0,0 +1,195 @@
+/************************************************************************/
+/* This file contains the BCC compiler helper functions */
+/* Function ldivmod */
+
+#ifdef __AS386_16__
+#asm
+ .text
+ .even
+
+| ldivmod.s - 32 over 32 to 32 bit division and remainder for 8086
+
+| ldivmod( dividend bx:ax, divisor di:cx ) [ signed quot di:cx, rem bx:ax ]
+| ludivmod( dividend bx:ax, divisor di:cx ) [ unsigned quot di:cx, rem bx:ax ]
+
+| dx is not preserved
+
+
+| NB negatives are handled correctly, unlike by the processor
+| divison by zero does not trap
+
+
+| let dividend = a, divisor = b, quotient = q, remainder = r
+| a = b * q + r mod 2^32
+| where:
+
+| if b = 0, q = 0 and r = a
+
+| otherwise, q and r are uniquely determined by the requirements:
+| r has the same sign as b and absolute value smaller than that of b, i.e.
+| if b > 0, then 0 <= r < b
+| if b < 0, then 0 >= r > b
+| (the absoulute value and its comparison depend on signed/unsigned)
+
+| the rule for the sign of r means that the quotient is truncated towards
+| negative infinity in the usual case of a positive divisor
+
+| if the divisor is negative, the division is done by negating a and b,
+| doing the division, then negating q and r
+
+
+ .globl ldivmod
+
+ldivmod:
+ mov dx,di ! sign byte of b in dh
+ mov dl,bh ! sign byte of a in dl
+ test di,di
+ jns set_asign
+ neg di
+ neg cx
+ sbb di,*0
+set_asign:
+ test bx,bx
+ jns got_signs ! leave r = a positive
+ neg bx
+ neg ax
+ sbb bx,*0
+ j got_signs
+
+ .globl ludivmod
+ .even
+
+ludivmod:
+ xor dx,dx ! both sign bytes 0
+got_signs:
+ push bp
+ push si
+ mov bp,sp
+ push di ! remember b
+ push cx
+b0 = -4
+b16 = -2
+
+ test di,di
+ jne divlarge
+ test cx,cx
+ je divzero
+ cmp bx,cx
+ jae divlarge ! would overflow
+ xchg dx,bx ! a in dx:ax, signs in bx
+ div cx
+ xchg cx,ax ! q in di:cx, junk in ax
+ xchg ax,bx ! signs in ax, junk in bx
+ xchg ax,dx ! r in ax, signs back in dx
+ mov bx,di ! r in bx:ax
+ j zdivu1
+
+divzero: ! return q = 0 and r = a
+ test dl,dl
+ jns return
+ j negr ! a initially minus, restore it
+
+divlarge:
+ push dx ! remember sign bytes
+ mov si,di ! w in si:dx, initially b from di:cx
+ mov dx,cx
+ xor cx,cx ! q in di:cx, initially 0
+ mov di,cx
+ ! r in bx:ax, initially a
+ ! use di:cx rather than dx:cx in order to
+ ! have dx free for a byte pair later
+ cmp si,bx
+ jb loop1
+ ja zdivu ! finished if b > r
+ cmp dx,ax
+ ja zdivu
+
+| rotate w (= b) to greatest dyadic multiple of b <= r
+
+loop1:
+ shl dx,*1 ! w = 2*w
+ rcl si,*1
+ jc loop1_exit ! w was > r counting overflow (unsigned)
+ cmp si,bx ! while w <= r (unsigned)
+ jb loop1
+ ja loop1_exit
+ cmp dx,ax
+ jbe loop1 ! else exit with carry clear for rcr
+loop1_exit:
+ rcr si,*1
+ rcr dx,*1
+loop2:
+ shl cx,*1 ! q = 2*q
+ rcl di,*1
+ cmp si,bx ! if w <= r
+ jb loop2_over
+ ja loop2_test
+ cmp dx,ax
+ ja loop2_test
+loop2_over:
+ add cx,*1 ! q++
+ adc di,*0
+ sub ax,dx ! r = r-w
+ sbb bx,si
+loop2_test:
+ shr si,*1 ! w = w/2
+ rcr dx,*1
+ cmp si,b16[bp] ! while w >= b
+ ja loop2
+ jb zdivu
+ cmp dx,b0[bp]
+ jae loop2
+
+zdivu:
+ pop dx ! sign bytes
+zdivu1:
+ test dh,dh
+ js zbminus
+ test dl,dl
+ jns return ! else a initially minus, b plus
+ mov dx,ax ! -a = b * q + r ==> a = b * (-q) + (-r)
+ or dx,bx
+ je negq ! use if r = 0
+ sub ax,b0[bp] ! use a = b * (-1 - q) + (b - r)
+ sbb bx,b16[bp]
+ not cx ! q = -1 - q (same as complement)
+ not di
+negr:
+ neg bx
+ neg ax
+ sbb bx,*0
+return:
+ mov sp,bp
+ pop si
+ pop bp
+ ret
+
+ .even
+
+zbminus:
+ test dl,dl ! (-a) = (-b) * q + r ==> a = b * q + (-r)
+ js negr ! use if initial a was minus
+ mov dx,ax ! a = (-b) * q + r ==> a = b * (-q) + r
+ or dx,bx
+ je negq ! use if r = 0
+ sub ax,b0[bp] ! use a = b * (-1 - q) + (b + r) (b is now -b)
+ sbb bx,b16[bp]
+ not cx
+ not di
+ mov sp,bp
+ pop si
+ pop bp
+ ret
+
+ .even
+
+negq:
+ neg di
+ neg cx
+ sbb di,*0
+ mov sp,bp
+ pop si
+ pop bp
+ ret
+#endasm
+#endif
diff --git a/libc/bcc/alloca.c b/libc/bcc/alloca.c
new file mode 100644
index 0000000..4f85047
--- /dev/null
+++ b/libc/bcc/alloca.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* Alloca is a nice interesting function */
+/* Needs change to BCC to work, as BCC doesn't use 'mov sp,bp:pop bp' */
+/* The only other way to do it is to use malloc and the emacs alloca */
+
+#if 0
+THIS IS BROKEN!!!
+
+#asm
+export _alloca
+ .text
+_alloca:
+ pop cx ! The program counter
+ pop ax ! The argument (>1 arg == snafu)
+ inc ax
+ and al,$FE ! Round up to even
+
+ test ax,ax
+ jz too_big ! Well _I_ think it means 64k ! :-) (ANSI too IIUC)
+
+ mov bx,sp
+ sub bx,ax ! Calc new SP
+ jb too_big ! SP wrapped, snafu!
+
+ mov ax,[brk_addr]
+ add ax,#64 ! Check if brk has allocated the memory first but
+ cmp bx,ax ! leave a little bit of space before we collide!
+ jb too_big
+
+ xchg bx,sp ! Put it in place, may need the old SP for other args
+ mov ax,sp ! The bottom of the area allocated
+
+ ! This is needed if si/di popped before mov sp,bp
+ !push [bx+4] ! This copies the saved register vars and possibly a temp
+ !push [bx+2] ! value, beware snafu if called within complex expression!
+ !push [bx] !
+
+ push ax ! Anything really, it will be deallocated by the caller
+ jmp cx ! Return
+
+too_big:
+ xor ax,ax ! Sorry not enough stack
+ push ax ! More junk
+ jmp cx ! Return
+#endasm
+#endif
diff --git a/libc/bcc/bcc_bsw.c b/libc/bcc/bcc_bsw.c
new file mode 100644
index 0000000..4dd0d11
--- /dev/null
+++ b/libc/bcc/bcc_bsw.c
@@ -0,0 +1,487 @@
+/************************************************************************/
+/* This file contains the BCC compiler helper functions */
+/* Support for long arithmetic on big-endian (words-swapped) longs
+ * __laddb.o __landb.o __lcmpb.o __lcomb.o __ldecb.o __ldivb.o __ldivub.o
+ * __leorb.o __lincb.o __lmodb.o __lmodub.o __lmulb.o __lnegb.o __lorb.o
+ * __lslb.o __lsrb.o __lsrub.o __lsubb.o __ltstb.o
+ */
+#ifdef __AS386_16__
+#asm
+ .text ! This is common to all.
+ .even
+#endasm
+
+/************************************************************************/
+/* Function laddb */
+
+#ifdef L___laddb
+#asm
+
+| laddb.s
+
+ .globl laddb
+ .globl laddub
+
+laddb:
+laddub:
+ add bx,2(di)
+ adc ax,(di)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function landb */
+
+#ifdef L___landb
+#asm
+
+| landb.s
+
+ .globl landb
+ .globl landub
+
+landb:
+landub:
+ and ax,(di)
+ and bx,2(di)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lcmpb */
+
+#ifdef L___lcmpb
+#asm
+
+| lcmpb.s
+| lcmpb, lcmpub don`t preserve ax
+
+ .globl lcmpb
+ .globl lcmpub
+
+lcmpb:
+lcmpub:
+ sub ax,(di) | don`t need to preserve ax
+ je LCMP_NOT_SURE
+ ret
+
+ .even
+
+LCMP_NOT_SURE:
+ cmp bx,2(di)
+ jb LCMP_B_AND_LT | b (below) becomes lt (less than) as well
+ jge LCMP_EXIT | ge and already ae
+ | else make gt as well as a (above)
+ inc ax | clear ov and mi, set ne for greater than
+LCMP_EXIT:
+ ret
+
+ .even
+
+LCMP_B_AND_LT:
+ dec ax | clear ov, set mi and ne for less than
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lcomb */
+
+#ifdef L___lcomb
+#asm
+
+| lcomb.s
+
+ .globl lcomb
+ .globl lcomub
+
+lcomb:
+lcomub:
+ not ax
+ not bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ldecb */
+
+#ifdef L___ldecb
+#asm
+
+| ldecb.s
+
+ .globl ldecb
+ .globl ldecub
+
+ldecb:
+ldecub:
+ cmp 2(bx),*0
+ je LDEC_BOTH
+ dec 2(bx)
+ ret
+
+ .even
+
+LDEC_BOTH:
+ dec 2(bx)
+ dec (bx)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ldivb */
+
+#ifdef L___ldivb
+#asm
+
+| ldivb.s
+| ax:bx / (di):2(di), quotient ax:bx, remainder cx:di, dx not preserved
+
+ .globl ldivb
+ .extern ldivmod
+
+ldivb:
+ xchg ax,bx
+ mov cx,2(di)
+ mov di,(di)
+ call ldivmod | bx:ax / di:cx, quot di:cx, rem bx:ax
+ xchg ax,di
+ xchg bx,cx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ldivub */
+
+#ifdef L___ldivub
+#asm
+
+| ldivub.s
+| unsigned ax:bx / (di):2(di), quotient ax:bx,remainder cx:di, dx not preserved
+
+ .globl ldivub
+ .extern ludivmod
+
+ldivub:
+ xchg ax,bx
+ mov cx,2(di)
+ mov di,(di)
+ call ludivmod | unsigned bx:ax / di:cx, quot di:cx, rem bx:ax
+ xchg ax,di
+ xchg bx,cx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function leorb */
+
+#ifdef L___leorb
+#asm
+
+| leorb.s
+
+ .globl leorb
+ .globl leorub
+
+leorb:
+leorub:
+ xor ax,(di)
+ xor bx,2(di)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lincb */
+
+#ifdef L___lincb
+#asm
+
+| lincb.s
+
+ .globl lincb
+ .globl lincub
+
+lincb:
+lincub:
+ inc 2(bx)
+ je LINC_HIGH_WORD
+ ret
+
+ .even
+
+LINC_HIGH_WORD:
+ inc (bx)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lmodb */
+
+#ifdef L___lmodb
+#asm
+
+| lmodb.s
+| ax:bx % (di):2(di), remainder ax:bx, quotient cx:di, dx not preserved
+
+ .globl lmodb
+ .extern ldivmod
+
+lmodb:
+ xchg ax,bx
+ mov cx,2(di)
+ mov di,(di)
+ call ldivmod | bx:ax / di:cx, quot di:cx, rem bx:ax
+ xchg ax,bx
+ xchg cx,di
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lmodub */
+
+#ifdef L___lmodub
+#asm
+
+| lmodub.s
+| unsigned ax:bx / (di):2(di), remainder ax:bx,quotient cx:di, dx not preserved
+
+ .globl lmodub
+ .extern ludivmod
+
+lmodub:
+ xchg ax,bx
+ mov cx,2(di)
+ mov di,(di)
+ call ludivmod | unsigned bx:ax / di:cx, quot di:cx, rem bx:ax
+ xchg ax,bx
+ xchg cx,di
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lmulb */
+
+#ifdef L___lmulb
+#asm
+
+| lmulb.s
+| lmulb, lmulub don`t preserve cx, dx
+
+ .globl lmulb
+ .globl lmulub
+
+lmulb:
+lmulub:
+ mul 2(di)
+ xchg ax,bx
+ mov cx,ax
+ mul (di)
+ add bx,ax
+ mov ax,2(di)
+ mul cx
+ add bx,dx
+ xchg ax,bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lnegb */
+
+#ifdef L___lnegb
+#asm
+
+| lnegb.s
+
+ .globl lnegb
+ .globl lnegub
+
+lnegb:
+lnegub:
+ neg ax
+ neg bx
+ sbb ax,*0
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lorb */
+
+#ifdef L___lorb
+#asm
+
+| lorb.s
+
+ .globl lorb
+ .globl lorub
+
+lorb:
+lorub:
+ or ax,(di)
+ or bx,2(di)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lslb */
+
+#ifdef L___lslb
+#asm
+
+| lslb.s
+| lslb, lslub don`t preserve cx
+
+ .globl lslb
+ .globl lslub
+
+lslb:
+lslub:
+ mov cx,di
+ jcxz LSL_EXIT
+ cmp cx,*32
+ jae LSL_ZERO
+LSL_LOOP:
+ shl bx,*1
+ rcl ax,*1
+ loop LSL_LOOP
+LSL_EXIT:
+ ret
+
+ .even
+
+LSL_ZERO:
+ xor ax,ax
+ mov bx,ax
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsrb */
+
+#ifdef L___lsrb
+#asm
+
+| lsrb.s
+| lsrb doesn`t preserve cx
+
+ .globl lsrb
+
+lsrb:
+ mov cx,di
+ jcxz LSR_EXIT
+ cmp cx,*32
+ jae LSR_SIGNBIT
+LSR_LOOP:
+ sar ax,*1
+ rcr bx,*1
+ loop LSR_LOOP
+LSR_EXIT:
+ ret
+
+ .even
+
+LSR_SIGNBIT:
+ mov cx,*32 | equivalent to +infinity in this context
+ j LSR_LOOP
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsrub */
+
+#ifdef L___lsrub
+#asm
+
+| lsrub.s
+| lsrub doesn`t preserve cx
+
+ .globl lsrub
+
+lsrub:
+ mov cx,di
+ jcxz LSRU_EXIT
+ cmp cx,*32
+ jae LSRU_ZERO
+LSRU_LOOP:
+ shr ax,*1
+ rcr bx,*1
+ loop LSRU_LOOP
+LSRU_EXIT:
+ ret
+
+ .even
+
+LSRU_ZERO:
+ xor ax,ax
+ mov bx,ax
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsubb */
+
+#ifdef L___lsubb
+#asm
+
+| lsubb.s
+
+ .globl lsubb
+ .globl lsubub
+
+lsubb:
+lsubub:
+ sub bx,2(di)
+ sbb ax,(di)
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ltstb */
+
+#ifdef L___ltstb
+#asm
+
+| ltstb.s
+| ltstb, ltstub don`t preserve ax
+
+ .globl ltstb
+ .globl ltstub
+
+ltstb:
+ltstub:
+ test ax,ax
+ je LTST_NOT_SURE
+ ret
+
+ .even
+
+LTST_NOT_SURE:
+ test bx,bx
+ js LTST_FIX_SIGN
+ ret
+
+ .even
+
+LTST_FIX_SIGN:
+ inc ax | clear ov and mi, set ne for greater than
+ ret
+#endasm
+#endif
+
+#endif
+
diff --git a/libc/bcc/bcc_i386.c b/libc/bcc/bcc_i386.c
new file mode 100644
index 0000000..d994628
--- /dev/null
+++ b/libc/bcc/bcc_i386.c
@@ -0,0 +1,149 @@
+/************************************************************************/
+/* This file contains the BCC compiler helper functions */
+/* Support for 386 integer arithmetic
+ * __divsi3.o __idiv.o __idivu.o __imod.o __imodu.o __imul.o
+ * __isl.o __isr.o __isru.o
+ */
+
+#ifdef __AS386_32__
+#asm
+ .text ! This is common to all.
+ .align 4
+#endasm
+
+#ifdef L___divsi3
+#asm
+! divsi3.s
+ .globl ___divsi3
+ ___divsi3:
+ push edx
+ mov eax,[esp+4+4]
+ cdq
+ idiv [esp+4+4+4]
+ pop edx
+ ret
+
+ .globl ___udivsi3
+ .text
+ .align 4
+
+ ___udivsi3:
+ push edx
+ mov eax,[esp+4+4]
+ sub edx,edx
+ div [esp+4+4+4]
+ pop edx
+ ret
+#endasm
+#endif
+
+#ifdef L___idiv
+#asm
+! idiv.s
+! idiv_ doesn`t preserve edx (returns remainder in it)
+
+ .globl idiv_
+idiv_:
+ cdq
+ idiv ebx
+ ret
+#endasm
+#endif
+
+#ifdef L___idivu
+#asm
+! idivu.s
+! idiv_u doesn`t preserve edx (returns remainder in it)
+
+ .globl idiv_u
+idiv_u:
+ xor edx,edx
+ div ebx
+ ret
+#endasm
+#endif
+
+#ifdef L___imod
+#asm
+! imod.s
+! imod doesn`t preserve edx (returns quotient in it)
+
+ .globl imod
+imod:
+ cdq
+ idiv ebx
+ mov eax,edx ! instruction queue full so xchg slower
+ ret
+#endasm
+#endif
+
+#ifdef L___imodu
+#asm
+! imodu.s
+! imodu doesn`t preserve edx (returns quotient in it)
+
+ .globl imodu
+imodu:
+ xor edx,edx
+ div ebx
+ mov eax,edx ! instruction queue full so xchg slower
+ ret
+#endasm
+#endif
+
+#ifdef L___imul
+#asm
+! imul.s
+! imul_, imul_u don`t preserve edx
+
+ .globl imul_
+ .globl imul_u
+imul_:
+imul_u:
+ imul ebx
+ ret
+#endasm
+#endif
+
+#ifdef L___isl
+#asm
+! isl.s
+! isl, islu don`t preserve cl
+
+ .globl isl
+ .globl islu
+isl:
+islu:
+ mov cl,bl
+ shl eax,cl
+ ret
+#endasm
+#endif
+
+#ifdef L___isr
+#asm
+! isr.s
+! isr doesn`t preserve cl
+
+ .globl isr
+isr:
+ mov cl,bl
+ sar eax,cl
+ ret
+#endasm
+#endif
+
+#ifdef L___isru
+#asm
+! isru.s
+! isru doesn`t preserve cl
+
+ .globl isru
+isru:
+ mov cl,bl
+ shr eax,cl
+ ret
+#endasm
+#endif
+
+#endif
diff --git a/libc/bcc/bcc_int.c b/libc/bcc/bcc_int.c
new file mode 100644
index 0000000..abdb7b4
--- /dev/null
+++ b/libc/bcc/bcc_int.c
@@ -0,0 +1,162 @@
+/************************************************************************/
+/* This file contains the BCC compiler helper functions */
+/* Support for integer arithmetic
+ * __idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o
+ */
+
+#ifdef __AS386_16__
+#asm
+ .text ! This is common to all.
+ .even
+#endasm
+
+/************************************************************************/
+/* Function idiv */
+
+#ifdef L___idiv
+#asm
+
+| idiv.s
+| idiv_ doesn`t preserve dx (returns remainder in it)
+
+ .globl idiv_
+
+idiv_:
+ cwd
+ idiv bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function idivu */
+
+#ifdef L___idivu
+#asm
+
+| idivu.s
+| idiv_u doesn`t preserve dx (returns remainder in it)
+
+ .globl idiv_u
+
+idiv_u:
+ xor dx,dx
+ div bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function imod */
+
+#ifdef L___imod
+#asm
+
+| imod.s
+| imod doesn`t preserve dx (returns quotient in it)
+
+ .globl imod
+
+imod:
+ cwd
+ idiv bx
+ mov ax,dx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function imodu */
+
+#ifdef L___imodu
+#asm
+
+| imodu.s
+| imodu doesn`t preserve dx (returns quotient in it)
+
+ .globl imodu
+
+imodu:
+ xor dx,dx
+ div bx
+ mov ax,dx ! instruction queue full so xchg slower
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function imul */
+
+#ifdef L___imul
+#asm
+
+| imul.s
+| imul_, imul_u don`t preserve dx
+
+ .globl imul_
+ .globl imul_u
+
+imul_:
+imul_u:
+ imul bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function isl */
+
+#ifdef L___isl
+#asm
+
+| isl.s
+| isl, islu don`t preserve cl
+
+ .globl isl
+ .globl islu
+
+isl:
+islu:
+ mov cl,bl
+ shl ax,cl
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function isr */
+
+#ifdef L___isr
+#asm
+
+| isr.s
+| isr doesn`t preserve cl
+
+ .globl isr
+
+isr:
+ mov cl,bl
+ sar ax,cl
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function isru */
+
+#ifdef L___isru
+#asm
+
+| isru.s
+| isru doesn`t preserve cl
+
+ .globl isru
+
+isru:
+ mov cl,bl
+ shr ax,cl
+ ret
+#endasm
+#endif
+
+#endif
diff --git a/libc/bcc/bcc_io.c b/libc/bcc/bcc_io.c
new file mode 100644
index 0000000..af5dfd2
--- /dev/null
+++ b/libc/bcc/bcc_io.c
@@ -0,0 +1,189 @@
+/************************************************************************/
+/* This file contains the BCC compiler helper functions */
+/* Miscellaneous obsolete junk
+ * __inport.o __inportb.o __outport.o __outportb.o __peekb.o __peekw.o
+ * __pokeb.o __pokew.o
+ */
+
+#ifdef __AS368_16__
+#if !__FIRST_ARG_IN_AX__
+#asm
+ .text ! This is common to all.
+ .even
+#endasm
+
+/************************************************************************/
+/* Function inport */
+
+#ifdef L___inport
+#asm
+
+| int inport( int port );
+| reads a word from the i/o port port and returns it
+
+ .globl _inport
+_inport:
+ pop bx
+ pop dx
+ dec sp
+ dec sp
+ inw
+ jmp bx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function inportb */
+
+#ifdef L___inportb
+#asm
+
+| int inportb( int port );
+| reads a byte from the i/o port port and returns it
+
+ .globl _inportb
+_inportb:
+ pop bx
+ pop dx
+ dec sp
+ dec sp
+ in
+ sub ah,ah
+ jmp bx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function outport */
+
+#ifdef L___outport
+#asm
+
+| void outport( int port, int value );
+| writes the word value to the i/o port port
+
+ .globl _outport
+_outport:
+ pop bx
+ pop dx
+ pop ax
+ sub sp,*4
+ outw
+ jmp bx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function outportb */
+
+#ifdef L___outportb
+#asm
+
+| void oportb( int port, char value );
+| writes the byte value to the i/o port port
+| this would be outportb except for feeble linkers
+
+ .globl _oportb
+_oportb:
+ pop bx
+ pop dx
+ pop ax
+ sub sp,*4
+ out
+ jmp bx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function peekb */
+
+#ifdef L___peekb
+#asm
+
+| int peekb( unsigned segment, char *offset );
+| returns the (unsigned) byte at the far pointer segment:offset
+
+ .define _peekb
+_peekb:
+ mov cx,ds
+ pop dx
+ pop ds
+ pop bx
+ sub sp,*4
+ movb al,(bx)
+ subb ah,ah
+ mov ds,cx
+ jmp dx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function peekw */
+
+#ifdef L___peekw
+#asm
+
+| int peekw( unsigned segment, int *offset );
+| returns the word at the far pointer segment:offset
+
+ .define _peekw
+_peekw:
+ mov cx,ds
+ pop dx
+ pop ds
+ pop bx
+ sub sp,*4
+ mov ax,(bx)
+ mov ds,cx
+ jmp dx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function pokeb */
+
+#ifdef L___pokeb
+#asm
+
+| void pokeb( unsigned segment, char *offset, char value );
+| writes the byte value at the far pointer segment:offset
+
+ .define _pokeb
+_pokeb:
+ mov cx,ds
+ pop dx
+ pop ds
+ pop bx
+ pop ax
+ sub sp,*6
+ movb (bx),al
+ mov ds,cx
+ jmp dx
+#endasm
+#endif
+
+/************************************************************************/
+/* Function pokew */
+
+#ifdef L___pokew
+#asm
+
+| void pokew( unsigned segment, int *offset, int value );
+| writes the word value at the far pointer segment:offset
+
+ .define _pokew
+_pokew:
+ mov cx,ds
+ pop dx
+ pop ds
+ pop bx
+ pop ax
+ sub sp,*6
+ mov (bx),ax
+ mov ds,cx
+ jmp dx
+#endasm
+#endif
+
+#endif /* !__FIRST_ARG_IN_AX__ */
+#endif
diff --git a/libc/bcc/bcc_long.c b/libc/bcc/bcc_long.c
new file mode 100644
index 0000000..4b6ceae
--- /dev/null
+++ b/libc/bcc/bcc_long.c
@@ -0,0 +1,479 @@
+/************************************************************************/
+/* This file contains the BCC compiler helper functions */
+/* Support for long arithmetic on little-endian (normal) longs
+ * __laddl.o __landl.o __lcmpl.o __lcoml.o __ldecl.o __ldivl.o __ldivul.o
+ * __leorl.o __lincl.o __lmodl.o __lmodul.o __lmull.o __lnegl.o __lorl.o
+ * __lsll.o __lsrl.o __lsrul.o __lsubl.o __ltstl.o
+ */
+
+#ifdef __AS386_16__
+#asm
+ .text ! This is common to all.
+ .even
+#endasm
+
+/************************************************************************/
+/* Function laddl */
+
+#ifdef L___laddl
+#asm
+
+| laddl.s
+
+ .globl laddl
+ .globl laddul
+
+laddl:
+laddul:
+ add ax,[di]
+ adc bx,2[di]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function landl */
+
+#ifdef L___landl
+#asm
+
+| landl.s
+
+ .globl landl
+ .globl landul
+
+landl:
+landul:
+ and ax,[di]
+ and bx,2[di]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lcmpl */
+
+#ifdef L___lcmpl
+#asm
+
+| lcmpl.s
+| lcmpl, lcmpul don`t preserve bx
+
+ .globl lcmpl
+ .globl lcmpul
+
+lcmpl:
+lcmpul:
+ sub bx,2[di]
+ je LCMP_NOT_SURE
+ ret
+
+ .even
+
+LCMP_NOT_SURE:
+ cmp ax,[di]
+ jb LCMP_B_AND_LT
+ jge LCMP_EXIT
+
+ inc bx
+LCMP_EXIT:
+ ret
+
+ .even
+
+LCMP_B_AND_LT:
+ dec bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lcoml */
+
+#ifdef L___lcoml
+#asm
+
+| lcoml.s
+
+ .globl lcoml
+ .globl lcomul
+
+lcoml:
+lcomul:
+ not ax
+ not bx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ldecl */
+
+#ifdef L___ldecl
+#asm
+
+| ldecl.s
+
+ .globl ldecl
+ .globl ldecul
+
+ldecl:
+ldecul:
+ cmp word ptr [bx],*0
+ je LDEC_BOTH
+ dec word ptr [bx]
+ ret
+
+ .even
+
+LDEC_BOTH:
+ dec word ptr [bx]
+ dec word ptr 2[bx]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ldivl */
+
+#ifdef L___ldivl
+#asm
+
+| ldivl.s
+| bx:ax / 2(di):(di), quotient bx:ax, remainder di:cx, dx not preserved
+
+ .globl ldivl
+ .extern ldivmod
+
+ldivl:
+ mov cx,[di]
+ mov di,2[di]
+ call ldivmod
+ xchg ax,cx
+ xchg bx,di
+ ret
+
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ldivul */
+
+#ifdef L___ldivul
+#asm
+
+| ldivul.s
+| unsigned bx:ax / 2(di):(di), quotient bx:ax,remainder di:cx, dx not preserved
+
+ .globl ldivul
+ .extern ludivmod
+
+ldivul:
+ mov cx,[di]
+ mov di,2[di]
+ call ludivmod
+ xchg ax,cx
+ xchg bx,di
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function leorl */
+
+#ifdef L___leorl
+#asm
+
+| leorl.s
+
+ .globl leorl
+ .globl leorul
+
+leorl:
+leorul:
+ xor ax,[di]
+ xor bx,2[di]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lincl */
+
+#ifdef L___lincl
+#asm
+
+| lincl.s
+
+ .globl lincl
+ .globl lincul
+
+lincl:
+lincul:
+ inc word ptr [bx]
+ je LINC_HIGH_WORD
+ ret
+
+ .even
+
+LINC_HIGH_WORD:
+ inc word ptr 2[bx]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lmodl */
+
+#ifdef L___lmodl
+#asm
+
+| lmodl.s
+| bx:ax % 2(di):(di), remainder bx:ax, quotient di:cx, dx not preserved
+
+ .globl lmodl
+ .extern ldivmod
+
+lmodl:
+ mov cx,[di]
+ mov di,2[di]
+ call ldivmod
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lmodul */
+
+#ifdef L___lmodul
+#asm
+
+| lmodul.s
+| unsigned bx:ax / 2(di):(di), remainder bx:ax,quotient di:cx, dx not preserved
+
+ .globl lmodul
+ .extern ludivmod
+
+lmodul:
+ mov cx,[di]
+ mov di,2[di]
+ call ludivmod
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lmull */
+
+#ifdef L___lmull
+#asm
+
+| lmull.s
+| lmull, lmulul don`t preserve cx, dx
+
+ .globl lmull
+ .globl lmulul
+
+lmull:
+lmulul:
+ mov cx,ax
+ mul word ptr 2[di]
+ xchg ax,bx
+ mul word ptr [di]
+ add bx,ax
+ mov ax,ptr [di]
+ mul cx
+ add bx,dx
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lnegl */
+
+#ifdef L___lnegl
+#asm
+
+| lnegl.s
+
+ .globl lnegl
+ .globl lnegul
+
+lnegl:
+lnegul:
+ neg bx
+ neg ax
+ sbb bx,*0
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lorl */
+
+#ifdef L___lorl
+#asm
+
+| lorl.s
+
+ .globl lorl
+ .globl lorul
+
+lorl:
+lorul:
+ or ax,[di]
+ or bx,2[di]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsll */
+
+#ifdef L___lsll
+#asm
+
+| lsll.s
+| lsll, lslul don`t preserve cx
+
+ .globl lsll
+ .globl lslul
+
+lsll:
+lslul:
+ mov cx,di
+ jcxz LSL_EXIT
+ cmp cx,*32
+ jae LSL_ZERO
+LSL_LOOP:
+ shl ax,*1
+ rcl bx,*1
+ loop LSL_LOOP
+LSL_EXIT:
+ ret
+
+ .even
+
+LSL_ZERO:
+ xor ax,ax
+ mov bx,ax
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsrl */
+
+#ifdef L___lsrl
+#asm
+
+| lsrl.s
+| lsrl doesn`t preserve cx
+
+ .globl lsrl
+
+lsrl:
+ mov cx,di
+ jcxz LSR_EXIT
+ cmp cx,*32
+ jae LSR_SIGNBIT
+LSR_LOOP:
+ sar bx,*1
+ rcr ax,*1
+ loop LSR_LOOP
+LSR_EXIT:
+ ret
+
+ .even
+
+LSR_SIGNBIT:
+ mov cx,*32
+ j LSR_LOOP
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsrul */
+
+#ifdef L___lsrul
+#asm
+
+| lsrul.s
+| lsrul doesn`t preserve cx
+
+ .globl lsrul
+
+lsrul:
+ mov cx,di
+ jcxz LSRU_EXIT
+ cmp cx,*32
+ jae LSRU_ZERO
+LSRU_LOOP:
+ shr bx,*1
+ rcr ax,*1
+ loop LSRU_LOOP
+LSRU_EXIT:
+ ret
+
+ .even
+
+LSRU_ZERO:
+ xor ax,ax
+ mov bx,ax
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function lsubl */
+
+#ifdef L___lsubl
+#asm
+
+| lsubl.s
+
+ .globl lsubl
+ .globl lsubul
+
+lsubl:
+lsubul:
+ sub ax,[di]
+ sbb bx,2[di]
+ ret
+#endasm
+#endif
+
+/************************************************************************/
+/* Function ltstl */
+
+#ifdef L___ltstl
+#asm
+
+| ltstl.s
+| ltstl, ltstul don`t preserve bx
+
+ .globl ltstl
+ .globl ltstul
+
+ltstl:
+ltstul:
+ test bx,bx
+ je LTST_NOT_SURE
+ ret
+
+ .even
+
+LTST_NOT_SURE:
+ test ax,ax
+ js LTST_FIX_SIGN
+ ret
+
+ .even
+
+LTST_FIX_SIGN:
+ inc bx
+ ret
+#endasm
+#endif
+
+#endif
diff --git a/libc/bcc/heap.c b/libc/bcc/heap.c
new file mode 100644
index 0000000..c5b2457
--- /dev/null
+++ b/libc/bcc/heap.c
@@ -0,0 +1,184 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <errno.h>
+
+/****************************************************************************/
+
+#ifdef L_errno
+int errno = 0; /* libc error value */
+#endif
+
+/****************************************************************************/
+
+#ifdef __AS386_16__
+
+#ifdef L___brk_addr
+#asm
+.data
+export brk_addr
+brk_addr: .word __end ! This holds the current return for sbrk(0)
+.text
+#endasm
+#endif
+
+/****************************************************************************/
+
+#ifdef L_sbrk
+int sbrk(brk_off)
+int brk_off;
+{
+#asm
+ mov bx,sp
+#if !__FIRST_ARG_IN_AX__
+ mov ax,[bx+2] ! Fetch the requested value
+#endif
+ test ax,ax
+ jnz has_change
+ mov ax,[brk_addr] ! Simple one, read current - can`t fail.
+ jmp eof
+
+has_change:
+ js go_down
+ add ax,[brk_addr] ! Goin up!
+ jc Enomem
+ sub bx,#511 ! Safety space 512 bytes
+ cmp bx,ax ! Too close ?
+ jb Enomem
+
+sbrk_ok:
+#if !defined(__MSDOS__) && !defined(__STANDALONE__)
+ push ax ! MSDOS `kernel` doesn`t care
+ call ___brk ! Tell the kernel
+ test ax,ax
+ pop ax ! ASSUME ___brk doesn`t alter stack!
+ jnz Enomem ! Ugh! kernel didn`t like the idea!
+#endif
+ xchg [brk_addr],ax ! Save away new val
+ jmp eof ! Return it
+go_down:
+ add ax,[brk_addr]
+ jnc Enomem
+ cmp ax,#__end
+ jae sbrk_ok
+
+Enomem:
+ mov ax,#12 ! This should be ENOMEM not a magic.
+ mov [_errno],ax
+ mov ax,#-1
+eof:
+#endasm
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_brk
+int
+brk(new_brk)
+char * new_brk;
+{
+#asm
+ mov bx,sp
+#if !__FIRST_ARG_IN_AX__
+ mov ax,[bx+2] ! Fetch the requested value
+#endif
+ sub bx,#512 ! Safety space 512 bytes
+ cmp bx,ax ! Too close ?
+ jb Enomem
+ cmp ax,#__end
+ jae brk_ok
+Enomem:
+ mov ax,#12 ! This should be ENOMEM not a magic.
+ mov [_errno],ax
+ mov ax,#-1
+ ret
+brk_ok:
+#if !defined(__MSDOS__) && !defined(__STANDALONE__)
+ push ax
+ call ___brk ! Tell the kernel
+ test ax,ax
+ pop bx ! ASSUME ___brk doesn`t alter stack!
+ jnz Enomem ! Ugh! kernel didn`t like the idea!
+ mov [brk_addr],bx ! Save away new val
+#else
+ mov [brk_addr],ax ! MSDOS `kernel` doesn`t care
+ mov ax,#0
+#endif
+#endasm
+}
+#endif
+
+#endif
+
+/****************************************************************************/
+
+#ifdef __AS386_32__
+extern char * __brk_addr;
+extern char * __brk();
+
+#ifdef L___brk_addr
+char * __brk_addr = 0; /* This holds the current return for sbrk(0) */
+
+char *
+__brk(val)
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov ebx,eax
+#else
+ mov ebx,[esp+4]
+#endif
+ mov eax,#45
+ int $80
+#endasm
+}
+
+__brk_addr_init()
+{
+ if( __brk_addr == 0 && (__brk_addr = __brk(0)) == 0 )
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+#ifdef L_sbrk
+char *
+sbrk(brk_off)
+int brk_off;
+{
+ char * new_brk;
+ if( __brk_addr_init() ) return (char*)-1;
+ if( brk_off == 0 ) return __brk_addr;
+
+ new_brk = __brk_addr + brk_off;
+ __brk_addr = __brk(new_brk);
+ if( __brk_addr != new_brk )
+ {
+ errno = ENOMEM;
+ return (char*)-1;
+ }
+ return __brk_addr - brk_off;
+}
+#endif
+
+#ifdef L_brk
+int
+brk(new_brk)
+char * new_brk;
+{
+ if( __brk_addr_init() ) return -1;
+
+ __brk_addr = __brk(new_brk);
+ if( __brk_addr == new_brk ) return 0;
+ errno = ENOMEM;
+ return -1;
+}
+#endif
+
+#endif
diff --git a/libc/bcc/ldiv.c b/libc/bcc/ldiv.c
new file mode 100644
index 0000000..aab0701
--- /dev/null
+++ b/libc/bcc/ldiv.c
@@ -0,0 +1,30 @@
+
+#ifdef __AS386_16__
+#asm
+.text
+export _ldiv
+_ldiv:
+ push bp
+ mov bp,sp
+ push di
+ push si
+ mov ax,[bp+6]
+ mov bx,[bp+8]
+ mov cx,[bp+10]
+ mov di,[bp+12]
+ call ldivmod
+ mov si,[bp+4]
+ mov [si],cx
+ mov [si+2],di
+ mov [si+4],ax
+ mov [si+6],bx
+ mov ax,si
+ pop si
+ pop di
+ pop bp
+ ret
+.data
+.bss
+#endasm
+#endif
+
diff --git a/libc/bios/Config b/libc/bios/Config
new file mode 100644
index 0000000..e7f1971
--- /dev/null
+++ b/libc/bios/Config
@@ -0,0 +1 @@
+bios: Minimal syscalls for BIOS level
diff --git a/libc/bios/Makefile b/libc/bios/Makefile
new file mode 100644
index 0000000..5fcc964
--- /dev/null
+++ b/libc/bios/Makefile
@@ -0,0 +1,35 @@
+# Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+ifeq ($(LIB_OS),BIOS)
+ASRC=bios.c
+AOBJ=bios_start.o bios_isatty.o \
+ bios_open.o bios_read.o bios_write.o bios_lseek.o bios_close.o
+
+BSRC=bios_vid.c
+BOBJ=bios_putc.o bios_getc.o bios_khit.o bios_rdline.o
+
+OBJ=$(AOBJ) $(BOBJ)
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)($(OBJ))
+ @:
+
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(BOBJ)): $(BSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/bios/README b/libc/bios/README
new file mode 100644
index 0000000..cc883e1
--- /dev/null
+++ b/libc/bios/README
@@ -0,0 +1,10 @@
+Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+This file is part of the Linux-8086 C library and is distributed
+under the GNU Library General Public License.
+
+This is a very simple set of functions for standalone executables.
+
+There is a choice as to which console type you want to use, I think
+the VT52 clone is best.
+
+-Robert
diff --git a/libc/bios/bios.c b/libc/bios/bios.c
new file mode 100644
index 0000000..a8d2079
--- /dev/null
+++ b/libc/bios/bios.c
@@ -0,0 +1,230 @@
+/* Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#if !__FIRST_ARG_IN_AX__
+#ifdef __AS386_16__
+#ifdef __STANDALONE__
+
+#include <dos.h>
+#include <fcntl.h>
+#include <errno.h>
+int errno;
+
+#ifdef L_bios_start
+char ** environ = { 0 };
+
+void (*__cleanup)() = 0;
+
+#asm
+ .data
+export ___argr
+___argr:
+ .word 0,0,0,0,0,0,0 ! A struct REGS
+defarg:
+ .word boot_str, 0
+boot_str:
+ .asciz "boot"
+loop_save:
+ .word 0
+
+ .text
+export ___cstartup ! Crt0 startup
+___cstartup:
+ mov ___argr+0,ax
+ mov ___argr+2,bx
+ mov ___argr+4,cx
+ mov ___argr+6,dx
+ mov ___argr+8,si
+ mov ___argr+10,di
+
+zap_bss: ! Clear the BSS
+ mov ax,ds
+ mov es,ax ! ES now data seg
+ mov di,#__edata
+ mov cx,#__end
+ sub cx,di
+ xor ax,ax
+ cld
+ rep
+ stosb
+
+ push [_environ]
+ mov ax,#defarg ! Don`t define __mkargv, standalone programs don`t
+ push ax ! get any arguments.
+ mov ax,#1
+ push ax
+
+ mov bx,#auto_start ! Pointer to first autostart function
+auto_run:
+ mov [loop_save],bx
+ mov bx,[bx]
+ test bx,bx
+ jz no_entry
+ call bx ! Call the function
+no_entry:
+ mov bx,[loop_save]
+ inc bx ! next
+ inc bx
+ jmp auto_run ! And round for the next.
+
+call_exit: ! Last item called by above.
+ pop bx ! Be tidy.
+ push ax ! At the end the last called was main() push it`s
+ call _exit ! return val and call exit();
+bad_exit:
+ jmp bad_exit ! Exit returned !!
+
+ loc 2
+ .word _main ! Segment 2 is the trailing pointers, main and the
+ .word call_exit ! routine to call exit.
+data_start:
+
+ .text
+export _exit
+_exit: ! exit(rv) function
+ mov bx,sp
+ push [bx+2] ! Copy the `rv` for the exit fuctions.
+ mov bx,[___cleanup] ! Call exit, normally this is `__do_exit`
+ test bx,bx
+ je no_clean ! But it`s default is null
+ call bx
+no_clean:
+ inc sp
+ inc sp
+
+export __exit
+__exit:
+ xor ax,ax
+ mov es,ax
+ mov ax,cs
+ seg es
+ mov [$E6*4+2],ax
+ mov ax,#reti_ins
+ seg es
+ mov [$E6*4],ax
+ mov ax,#$FFFF
+ int $E6 ! Try to exit DOSEMU
+ ! If we get here we`re not in dosemu.
+ seg es
+ mov [$472],#$1234 ! Warm reboot.
+ jmpi $0000,$FFFF
+reti_ins:
+ reti
+
+#endasm
+
+#endif
+
+/****************************************************************************/
+
+#ifdef L___file_3
+
+/* If the block function does track buffering this should be ok ... */
+struct {
+ int (*block_rw)(); /* Args (rwoc, &buffer, blockno) 1k blocks */
+ /* 0 = read, 1 = write */
+ /* 2 = open, buffer is fname ptr */
+ /* 3 = close, other args ignored */
+ long offset;
+
+ int flags;
+ long block_num;
+ char buffer[1024];
+} __file_3_data;
+
+#define FILE3_OPEN 1 /* File is open */
+#define FILE3_DATA 2 /* buffer has valid contents */
+#define FILE3_DIRTY 4 /* buffer has been modified */
+
+#endif
+
+#ifdef L_bios_write
+write(fd,buf,len)
+int fd,len;
+char * buf;
+{
+ register int v, c;
+ if(fd == 1 || fd == 2)
+ {
+ for(v=len; v>0; v--)
+ {
+ c= *buf++;
+ if( c == '\n') bios_putc('\r');
+ bios_putc(c);
+ }
+ return len;
+ }
+ errno = EBADF;
+ return -1;
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_read
+read(fd,buf,len)
+int fd,len;
+char * buf;
+{
+ if(fd == 0) return bios_rdline(buf, len);
+ errno = EBADF;
+ return -1;
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_lseek
+long
+lseek(fd, offt, whence)
+int fd, whence;
+long offt;
+{
+ if( fd >= 0 && fd <= 2 ) errno = ESPIPE;
+ else errno = EBADF;
+ return -1L;
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_open
+open(name, flags, mode)
+char * name;
+int flags, mode;
+{
+ errno = ENOENT;
+ return -1;
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_close
+close(fd)
+int fd;
+{
+ if( fd >= 0 && fd <= 2 ) errno = ENOSYS;
+ else errno = EBADF;
+ return -1;
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_isatty
+isatty(fd)
+int fd;
+{
+ if( fd >= 0 && fd <= 2 ) return 1;
+ return 0;
+}
+#endif
+
+/****************************************************************************/
+
+#endif
+#endif
+#endif
diff --git a/libc/bios/bios_vid.c b/libc/bios/bios_vid.c
new file mode 100644
index 0000000..db2e91d
--- /dev/null
+++ b/libc/bios/bios_vid.c
@@ -0,0 +1,489 @@
+/* Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* Various possible console types */
+#define VT52_CON /* IMO the best, no clear to EOS/EOL yet */
+#define XANSI_CON /* Largest but still not complete */
+#define XDUMB_CON /* Can't do much */
+#define XSPEC_CON /* Incomplete, best for slow links */
+
+#if !__FIRST_ARG_IN_AX__
+#ifdef __AS386_16__
+#ifdef __STANDALONE__
+
+#include <dos.h>
+#include <errno.h>
+int errno;
+
+#ifdef L_bios_putc
+#define CTRL(x) ((x)&0x1F)
+static int last_attr = 0x07;
+static int con_mode;
+static unsigned char con_height = 24, con_width = 79;
+
+static int con_colour = 0;
+static unsigned char con_row, con_col;
+
+#ifdef VT52_CON
+bios_putc(c)
+int c;
+{
+static int ctrl = 0;
+ int new_attr;
+ if( con_mode==0 ) asm_coninit();
+
+ switch( ctrl )
+ {
+ case 1:
+ ctrl=0;
+ switch(c)
+ {
+ case 'A': if( con_row ) con_row--; asm_cpos(con_row, con_col); break;
+ case 'B': if( con_row != con_height ) con_row++;
+ asm_cpos(con_row, con_col); break;
+ case 'C': if( con_col != con_height ) con_col++;
+ asm_cpos(con_row, con_col); break;
+ case 'D': if( con_col ) con_col--; asm_cpos(con_row, con_col); break;
+ case 'E': last_attr = 0x07; asm_cls();
+ case 'H': asm_cpos(0,0); break;
+ case 'J': asm_cls(); break;
+ case 'K': break;
+ case 'R': ctrl = 2; break; /* Foreground */
+ case 'S': ctrl = 3; break; /* Background */
+ case 'Y': ctrl = 4; break; /* ttypos */
+ }
+ break;
+ case 2: ctrl=0; new_attr = (last_attr & 0xF0) + (c&0xF);
+ if(0) {
+ case 3: ctrl=0; new_attr = (last_attr & 0x0F) + (c<<4);
+ }
+ switch(c)
+ {
+ case '_': if( !con_colour ) last_attr = (last_attr&0x88) + 1;
+ break;
+ case '!': last_attr = (last_attr&0x88) + 0x70; break;
+ case ' ': last_attr = 0x07; break;
+ case '+': last_attr |= 0x08; break;
+ case '*': last_attr |= 0x80; break;
+
+ default: if( con_colour )
+ last_attr = new_attr;
+ }
+ break;
+ case 4: ctrl=5; con_col = c-' '; break;
+ case 5: ctrl=0; con_row = c-' '; asm_cpos(con_row, con_col); break;
+ break;
+
+ default:
+ if( c & 0xE0 )
+ { asm_colour(last_attr) ; asm_putc(c); }
+ else switch(c)
+ {
+ default:
+ asm_putc(c);
+ break;
+ case CTRL('I'):
+ asm_putc(' '); /* Only some BIOS's have this, so play safe */
+ break;
+ case CTRL('L'):
+ asm_cpos(0,0);
+ asm_cls();
+ break;
+ case CTRL('['):
+ ctrl = 1;
+ asm_gpos();
+ break;
+ }
+ break;
+ }
+}
+#endif
+
+#ifdef ANSI_CON
+#define MAX_ARGS 8
+static int colconv[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+static int vidcnt = 0;
+static int ansi_2 = 0;
+static int ansi_argc = 0;
+static int ansi_argv[MAX_ARGS];
+
+bios_putc(c)
+int c;
+{
+ if( con_mode==0 ) asm_coninit();
+
+ if( vidcnt == 0 || c < ' ' || c > '~' )
+ {
+ switch(c & 0xFF)
+ {
+ default:
+ asm_colour(last_attr);
+ asm_putc(c);
+ break;
+ case CTRL('L'):
+ asm_cpos(0,0);
+ asm_cls();
+ break;
+ case CTRL('['):
+ vidcnt=1;
+ break;
+ }
+ return;
+ }
+
+ /* ... ansi/vt100 interpretation, this collects _all_ ansi control strings */
+ switch(vidcnt)
+ {
+ case 1: for(ansi_argc=0; ansi_argc<MAX_ARGS; ansi_argc++)
+ ansi_argv[ansi_argc] = 0;
+ ansi_2 = 0;
+ ansi_argc = 0;
+ vidcnt++;
+
+ if( c != '[' )
+ {
+ do_ansi(c + 0x1B00, ansi_argc, ansi_argv);
+ vidcnt = 0;
+ }
+ break;
+
+ case 2: if( c == ';' )
+ {
+ if( ansi_argc < MAX_ARGS )
+ ansi_argc++;
+ }
+ else if( c >= '0' && c <= '9' )
+ ansi_argv[ansi_argc] = ansi_argv[ansi_argc] * 10 + c - '0';
+ else if( c >= '@' )
+ {
+ do_ansi(c+ansi_2, ++ansi_argc, ansi_argv);
+ vidcnt = 0;
+ }
+ else
+ ansi_2 = (c<<8);
+ break;
+
+ default: vidcnt = 0; /* This definitly won't happen ... definitly ... */
+ }
+}
+
+do_ansi(ctrl, argc, argv)
+int ctrl, argc, *argv;
+{
+ switch(ctrl)
+ {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ asm_gpos();
+ if( argv[0] < 1 ) argv[0] = 1;
+ switch(ctrl)
+ {
+ case 'A': if( argv[0]>con_row ) con_row=0; else con_row-=argv[0]; break;
+ case 'B': if( argv[0]+con_row>con_height )
+ con_row = con_height;
+ else
+ con_row += argv[0];
+ break;
+ case 'C': if( argv[0]+con_col>con_width )
+ con_col = con_width;
+ else
+ con_col += argv[0];
+ break;
+ case 'D': if( argv[0]>con_col ) con_col=0; else con_col-=argv[0]; break;
+ }
+ asm_cpos(con_row, con_col);
+ break;
+
+ case 'H':
+ if( --argv[0] < 0 ) argv[0] = 0;
+ if( --argv[1] < 0 ) argv[1] = 0;
+ asm_cpos(argv[0],argv[1]);
+ break;
+ case 'J': if( argv[0] == 2 ) asm_cls();
+ break;
+ case 'm':
+ {
+ int ar;
+ for(ar=0; ar<argc; ar++) switch(argv[ar])
+ {
+ case 0: last_attr = 0x07; break;
+ case 1: last_attr |= 0x08; break;
+ case 5: last_attr |= 0x80; break;
+ case 7: last_attr = 0x70; break;
+ case 30: case 31: case 32: case 33:
+ case 34: case 35: case 36: case 37:
+ if( con_colour )
+ last_attr = ((last_attr&0xF8)|(colconv[argv[ar]-30]));
+ break;
+ case 40: case 41: case 42: case 43:
+ case 44: case 45: case 46: case 47:
+ if( con_colour )
+ last_attr = ((last_attr&0x8F)|((colconv[argv[ar]-40])<<4));
+ break;
+ default: break;
+ }
+ }
+ }
+}
+#endif
+
+#ifdef SPEC_CON
+static char vidbuf[3];
+static int vidcnt=0;
+
+bios_putc(c)
+int c;
+{
+ if( con_mode==0 ) asm_coninit();
+ if( vidcnt == 0 )
+ {
+ if( c & 0xE0 )
+ { asm_colour(last_attr) ; asm_putc(c); }
+ else switch(c)
+ {
+ default:
+ asm_putc(c);
+ break;
+ case CTRL('L'):
+ asm_cpos(0,0);
+ asm_cls();
+ break;
+ case CTRL('P'):
+ case CTRL(']'):
+ vidbuf[vidcnt++] = c;
+ break;
+ }
+ }
+ else
+ {
+ vidbuf[vidcnt++] = c;
+ if( vidcnt < 3 &&
+ (vidbuf[0] != CTRL(']') || vidbuf[1] < '`' || vidbuf[1] > 'p'))
+ return;
+
+ if( vidbuf[0] == CTRL('P') )
+ {
+ if( vidbuf[1] >= 32 && vidbuf[1] <= 56
+ && vidbuf[2] >= 32 && vidbuf[2] <= 111 )
+ asm_cpos((vidbuf[1]-32), (vidbuf[2]-32));
+ }
+ else
+ {
+ if( vidbuf[1] >= '`' )
+ last_attr = ( (vidbuf[1]&0xF) | (last_attr&0xF0));
+ else
+ last_attr = ( (vidbuf[2]&0xF) | ((vidbuf[1]&0xF)<<4));
+
+ if( !con_colour )
+ last_attr = (last_attr&0x88) + ((last_attr&7)?0x07:0x70);
+ }
+ vidcnt=0;
+ }
+}
+#endif
+
+#ifdef DUMB_CON
+bios_putc(c)
+int c;
+{
+ if( con_mode==0 ) asm_coninit();
+ if( c & 0xE0 ) asm_putc(c);
+ else switch(c)
+ {
+ default:
+ asm_putc(c);
+ break;
+ case CTRL('L'):
+ asm_cls();
+ case CTRL('^'):
+ asm_cpos(0,0);
+ break;
+ }
+}
+#endif
+
+static asm_coninit()
+{
+#asm
+ mov ax,#$0F00
+ int $10
+ mov _con_mode,ax
+#endasm
+ if( (con_mode &0xFF) > 39 ) con_width = (con_mode>>8);
+ if( (con_mode&0xFF) != 0x7)
+ con_colour = 1;
+}
+
+static asm_putc(c)
+{
+#asm
+#if !__FIRST_ARG_IN_AX__
+ mov bx,sp
+ mov ax,[bx+2]
+#endif
+ mov ah,#$0E
+ mov bx,#7
+ int $10
+#endasm
+}
+
+static asm_cls()
+{
+#asm
+ push bp ! Bug in some old BIOS`s
+ !mov ax,#$0500
+ !int $10
+ mov ax,#$0600
+ mov bh,_last_attr
+ mov cx,#$0000
+ mov dl,_con_width
+ mov dh,_con_height
+ int $10
+ pop bp
+#endasm
+}
+
+static asm_cpos(r,c)
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov bx,sp
+ mov dh,al
+ mov ax,[bx+2]
+ mov dl,al
+#else
+ mov bx,sp
+ mov ax,[bx+2]
+ mov dh,al
+ mov ax,[bx+4]
+ mov dl,al
+#endif
+ mov ah,#$02
+ mov bx,#7
+ int $10
+#endasm
+}
+
+#ifndef DUMB_CON
+static asm_colour(c)
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov bx,ax
+#else
+ mov bx,sp
+ mov bx,[bx+2]
+#endif
+ mov ah,#$08
+ int $10
+ mov ah,#$09
+ mov cx,#1
+ int $10
+#endasm
+}
+
+static asm_gpos()
+{
+#asm
+ mov ah,#$03
+ mov bx,#7
+ int $10
+ mov [_con_row],dh
+ mov [_con_col],dl
+ mov ax,cx
+#endasm
+}
+#endif
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_rdline
+bios_rdline(buf, len)
+char * buf;
+int len;
+{
+ int ch;
+ int pos=0;
+
+ if( len == 1 )
+ {
+ buf[0]=((ch=bios_getc())&0xFF?ch&0xFF:((ch>>8)&0xFF|0x80));
+ return 1;
+ }
+
+ for(ch=0;;)
+ {
+ if(ch != '\003')
+ {
+ ch = bios_getc();
+ if( pos == 0 && (ch&0xFF) == 0 )
+ {
+ buf[0] = ((ch>>8)|0x80);
+ return 1;
+ }
+ ch &= 0x7F;
+ if( ch == '\033' ) ch=3; /* ESC= Interrupt too */
+ }
+ if( ch == '\r' )
+ {
+ bios_putc('\r'); bios_putc('\n');
+ buf[pos++] = '\n';
+ return pos;
+ }
+ if( ch >= ' ' && ch != 0x7F && pos < len-1)
+ bios_putc(buf[pos++] = ch);
+ else if( (ch == '\003' || ch == '\b') && pos > 0 )
+ {
+ bios_putc('\b'); bios_putc(' '); bios_putc('\b');
+ pos--;
+ }
+ else if( ch == '\003' )
+ return 0;
+ else
+ bios_putc('\007');
+ }
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_getc
+bios_getc()
+{
+#asm
+ xor ax,ax
+ int $16
+#endasm
+}
+#endif
+
+/****************************************************************************/
+
+#ifdef L_bios_khit
+bios_khit()
+{
+#asm
+ mov ah,#1
+ int $16
+ jz nokey
+ cmp ax,#0
+ jnz dort
+ mov ax,#3
+dort:
+ ret
+nokey:
+ xor ax,ax
+#endasm
+}
+#endif
+
+/****************************************************************************/
+
+#endif
+#endif
+#endif
diff --git a/libc/crt0.c b/libc/crt0.c
new file mode 100644
index 0000000..bdf1585
--- /dev/null
+++ b/libc/crt0.c
@@ -0,0 +1,62 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#if defined(__AS386_16__) || defined(__AS386_32__)
+#define CRT0_OK
+/*
+ * Change of aim here, to allow easy alteration for generation of COM files
+ * this code has been moved into libc. This means only the linker needs to
+ * to be told to fetch a different libc the crt0 is unaltered.
+ *
+ * This also allows us to deal with __FIRST_ARG_IN_AX__ and __CALLER_SAVES__
+ * in the same way.
+ */
+
+#asm
+.text
+entry startup ! Crt0 startup
+startup:
+ br ___cstartup
+export no_op
+no_op: ! Generic no operation call
+ ret
+
+ .ascii __LIBC_VER__ ! Version id.
+
+ loc 1 ! Segment 1 is where the pointers to the autostart
+ ! functions are stored.
+#if !__AS386_32__
+ZP_safety:
+ .word 0 ! But first some zeros to avoid null pointer writes.
+ .word 0
+ .word 0
+ .word 0
+#endif
+export auto_start
+auto_start:
+
+#endasm
+#endif /* __AS386_16__ or __AS386_32__ */
+
+#if defined(__GNUC__) && defined(__i386__)
+#define CRT0_OK
+
+#ifdef __ELF__
+__asm__(".globl __startup\n__startup:");
+__asm__("jmp __cstartup");
+__asm__(".globl __no_op\n__no_op:");
+__asm__("ret");
+#else
+__asm__(".globl startup\nstartup:");
+__asm__("jmp ___cstartup");
+__asm__(".globl no_op\nno_op:");
+__asm__("ret");
+#endif
+
+#endif /* defined(__GNUC__) && defined(__i386__) */
+
+#ifndef CRT0_OK
+#error You are not going to get far without crt0.o!
+#endif
diff --git a/libc/error/Config b/libc/error/Config
new file mode 100644
index 0000000..1f384b7
--- /dev/null
+++ b/libc/error/Config
@@ -0,0 +1,2 @@
+
+error: Unix error functions
diff --git a/libc/error/Makefile b/libc/error/Makefile
new file mode 100644
index 0000000..ae3d1c0
--- /dev/null
+++ b/libc/error/Makefile
@@ -0,0 +1,18 @@
+# Copyright (C) 1996 Robert de Bath <robert@debath.thenet.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+ifeq ($(LIB_OS),ELKS)
+OBJ=error.o sys_errlist.o perror.o sys_siglist.o __assert.o
+
+all: $(LIBC)($(OBJ))
+ @:
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/error/README b/libc/error/README
new file mode 100644
index 0000000..02c123f
--- /dev/null
+++ b/libc/error/README
@@ -0,0 +1,10 @@
+Copyright (C) 1996 Robert de Bath <robert@debath.thenet.co.uk>
+This file is part of the Linux-8086 C library and is distributed
+under the GNU Library General Public License.
+
+These routines assume the existance of a file /usr/lib/liberror.txt,
+this file contains the actual error messages. One useful feature,
+the language of the error messages can be easily changed.
+
+
+-Robert
diff --git a/libc/error/__assert.c b/libc/error/__assert.c
new file mode 100644
index 0000000..bcf04e8
--- /dev/null
+++ b/libc/error/__assert.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <unistd.h>
+
+static void errput(str)
+const char * str;
+{
+ write(2, str, strlen(str));
+}
+
+void
+__assert(assertion, filename, linenumber)
+const char * assertion;
+const char * filename;
+int linenumber;
+{
+ errput("Failed assertion '");
+ errput(assertion);
+ errput("' in file ");
+ errput(filename);
+ errput(" at line ");
+ errput(itoa(linenumber));
+ errput(".\n");
+ abort();
+}
diff --git a/libc/error/error.c b/libc/error/error.c
new file mode 100644
index 0000000..3695719
--- /dev/null
+++ b/libc/error/error.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 1996 Robert de Bath <robert@debath.thenet.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+
+char **__sys_errlist =0;
+int __sys_nerr = 0;
+
+char *
+strerror(err)
+int err;
+{
+ int fd;
+ static char retbuf[80];
+ char inbuf[256];
+ int cc;
+ int bufoff = 0;
+
+ if( __sys_nerr )
+ {
+ if( err < 0 || err >= __sys_nerr ) goto unknown;
+ return __sys_errlist[err];
+ }
+
+ if( err <= 0 ) goto unknown; /* NB the <= allows comments in the file */
+ fd = open("/usr/lib/liberror.txt", 0);
+ if( fd < 0 ) goto unknown;
+
+ while( (cc=read(fd, inbuf, sizeof(inbuf))) > 0 )
+ {
+ int i;
+ for(i=0; i<cc; i++)
+ {
+ if( inbuf[i] == '\n' )
+ {
+ retbuf[bufoff] = '\0';
+ if( err == atoi(retbuf) )
+ {
+ char * p = strchr(retbuf, ' ');
+ if( p == 0 ) goto unknown;
+ while(*p == ' ') p++;
+ close(fd);
+ return p;
+ }
+ bufoff = 0;
+ }
+ else if( bufoff < sizeof(retbuf)-1 )
+ retbuf[bufoff++] = inbuf[i];
+ }
+ }
+unknown:;
+ if( fd >= 0 ) close(fd);
+ strcpy(retbuf, "Unknown error ");
+ strcpy(retbuf+14, itoa(err));
+ return retbuf;
+}
diff --git a/libc/error/liberror.txt b/libc/error/liberror.txt
new file mode 100644
index 0000000..2b510bd
--- /dev/null
+++ b/libc/error/liberror.txt
@@ -0,0 +1,121 @@
+1 Operation not permitted
+2 No such file or directory
+3 No such process
+4 Interrupted system call
+5 I/O error
+6 No such device or address
+7 Arg list too long
+8 Exec format error
+9 Bad file number
+10 No child processes
+11 Try again
+12 Out of memory
+13 Permission denied
+14 Bad address
+15 Block device required
+16 Device or resource busy
+17 File exists
+18 Cross-device link
+19 No such device
+20 Not a directory
+21 Is a directory
+22 Invalid argument
+23 File table overflow
+24 Too many open files
+25 Not a typewriter
+26 Text file busy
+27 File too large
+28 No space left on device
+29 Illegal seek
+30 Read-only file system
+31 Too many links
+32 Broken pipe
+33 Math argument out of domain of func
+34 Math result not representable
+35 Resource deadlock would occur
+36 File name too long
+37 No record locks available
+38 Function not implemented
+39 Directory not empty
+40 Too many symbolic links encountered
+41 Operation would block
+42 No message of desired type
+43 Identifier removed
+44 Channel number out of range
+45 Level 2 not synchronized
+46 Level 3 halted
+47 Level 3 reset
+48 Link number out of range
+49 Protocol driver not attached
+50 No CSI structure available
+51 Level 2 halted
+52 Invalid exchange
+53 Invalid request descriptor
+54 Exchange full
+55 No anode
+56 Invalid request code
+57 Invalid slot
+58 File locking deadlock error
+59 Bad font file format
+60 Device not a stream
+61 No data available
+62 Timer expired
+63 Out of streams resources
+64 Machine is not on the network
+65 Package not installed
+66 Object is remote
+67 Link has been severed
+68 Advertise error
+69 Srmount error
+70 Communication error on send
+71 Protocol error
+72 Multihop attempted
+73 RFS specific error
+74 Not a data message
+75 Value too large for defined data type
+76 Name not unique on network
+77 File descriptor in bad state
+78 Remote address changed
+79 Can not access a needed shared library
+80 Accessing a corrupted shared library
+81 .lib section in a.out corrupted
+82 Attempting to link in too many shared libraries
+83 Cannot exec a shared library directly
+84 Illegal byte sequence
+85 Interrupted system call should be restarted
+86 Streams pipe error
+87 Too many users
+88 Socket operation on non-socket
+89 Destination address required
+90 Message too long
+91 Protocol wrong type for socket
+92 Protocol not available
+93 Protocol not supported
+94 Socket type not supported
+95 Operation not supported on transport endpoint
+96 Protocol family not supported
+97 Address family not supported by protocol
+98 Address already in use
+99 Cannot assign requested address
+100 Network is down
+101 Network is unreachable
+102 Network dropped connection because of reset
+103 Software caused connection abort
+104 Connection reset by peer
+105 No buffer space available
+106 Transport endpoint is already connected
+107 Transport endpoint is not connected
+108 Cannot send after transport endpoint shutdown
+109 Too many references: cannot splice
+110 Connection timed out
+111 Connection refused
+112 Host is down
+113 No route to host
+114 Operation already in progress
+115 Operation now in progress
+116 Stale NFS file handle
+117 Structure needs cleaning
+118 Not a XENIX named type file
+119 No XENIX semaphores available
+120 Is a named type file
+121 Remote I/O error
diff --git a/libc/error/perror.c b/libc/error/perror.c
new file mode 100644
index 0000000..f9b0965
--- /dev/null
+++ b/libc/error/perror.c
@@ -0,0 +1,19 @@
+
+#include <errno.h>
+
+void
+perror(str)
+__const char * str;
+{
+ register char * ptr;
+ if(str)
+ {
+ write(2, str, strlen(str));
+ write(2, ": ", 2);
+ }
+ else write(2, "perror: ", 8);
+
+ ptr = strerror(errno);
+ write(2, ptr, strlen(ptr));
+ write(2, "\n", 1);
+}
diff --git a/libc/error/sys_errlist.c b/libc/error/sys_errlist.c
new file mode 100644
index 0000000..79a40bf
--- /dev/null
+++ b/libc/error/sys_errlist.c
@@ -0,0 +1,74 @@
+/* Copyright (C) 1996 Robert de Bath <robert@debath.thenet.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is a flash way of auto-initing the error array from an external file
+ * I wouldn't be surprised tho if it's a lot better just to hard code the
+ * error messages into the array.
+ *
+ * Of course the best of all is to use strerror().
+ */
+
+#ifdef __AS386_16__
+#define NR_ERRORS 128
+
+extern char **__sys_errlist;
+extern int __sys_nerr;
+
+char *sys_errlist[NR_ERRORS];
+int sys_nerr = NR_ERRORS;
+
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .word _init_vars ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+
+static void init_vars()
+{
+ char inbuf[256];
+ char errbuf[80];
+ int i, cc, fd, err, len, bufoff=0;
+ char * ptr;
+
+ fd = open("/usr/lib/liberror.txt", 0);
+ if( fd < 0 ) return;
+
+ for(i=0; i<NR_ERRORS; i++) sys_errlist[i] = "Unknown error";
+
+ while( (cc=read(fd, inbuf, sizeof(inbuf))) > 0 )
+ {
+ for(i=0; i<cc; i++)
+ {
+ if( inbuf[i] == '\n' )
+ {
+ errbuf[bufoff] = '\0';
+ err = atoi(errbuf);
+ ptr = strchr(errbuf, ' ');
+ if( ptr && err > 0 && err < NR_ERRORS )
+ {
+ while(*ptr == ' ') ptr++;
+ len = strlen(ptr)+1;
+ sys_errlist[err] = (void*)sbrk(len);
+ if( (int)sys_errlist[err] == -1 )
+ {
+ sys_errlist[err] == "";
+ break;
+ }
+ memcpy(sys_errlist[err], ptr, len);
+ }
+ bufoff = 0;
+ }
+ else if( bufoff < sizeof(errbuf)-1 )
+ errbuf[bufoff++] = inbuf[i];
+ }
+ }
+ close(fd);
+
+ __sys_errlist = sys_errlist;
+ __sys_nerr = sys_nerr = NR_ERRORS;
+}
+
+#endif /* __AS386_16__ */
diff --git a/libc/error/sys_siglist.c b/libc/error/sys_siglist.c
new file mode 100644
index 0000000..8f502f6
--- /dev/null
+++ b/libc/error/sys_siglist.c
@@ -0,0 +1,38 @@
+
+#include <signal.h>
+
+__const char * __const sys_siglist[NSIG] =
+{
+ "Unknown signal",
+ "Hangup",
+ "Interrupt",
+ "Quit",
+ "Illegal instruction",
+ "Trace/breakpoint trap",
+ "IOT trap/Abort",
+ "Bus error",
+ "Floating point exception",
+ "Killed",
+ "User defined signal 1",
+ "Segmentation fault",
+ "User defined signal 2",
+ "Broken pipe",
+ "Alarm clock",
+ "Terminated",
+ "Stack fault",
+ "Child exited",
+ "Continued",
+ "Stopped (signal)",
+ "Stopped",
+ "Stopped (tty input)",
+ "Stopped (tty output)",
+ "Possible I/O",
+ "CPU time limit exceeded",
+ "File size limit exceeded",
+ "Virtual time alarm",
+ "Profile signal",
+ "Window size changed",
+ "File lock lost",
+ "Power failure",
+ "Unused signal"
+};
diff --git a/libc/getent/Config b/libc/getent/Config
new file mode 100644
index 0000000..0349aba
--- /dev/null
+++ b/libc/getent/Config
@@ -0,0 +1 @@
+getent: Managment for /etc/passwd /etc/group /etc/utmp
diff --git a/libc/getent/Makefile b/libc/getent/Makefile
new file mode 100644
index 0000000..9321ced
--- /dev/null
+++ b/libc/getent/Makefile
@@ -0,0 +1,36 @@
+# Copyright (C) 1996 Nat Friedman <ndf@aleph1.mit.edu>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+ifeq ($(PLATFORM),i386-ELKS)
+CFLAGS=$(ARCH) $(WALL) $(CCFLAGS) $(DEFS)
+else
+CFLAGS=$(ARCH) -ansi $(CCFLAGS) $(DEFS)
+endif
+
+PSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c fgetpwent.c
+GSRC=__getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c initgroups.c \
+ config-grp.h
+USRC=utent.c
+
+POBJ=__getpwent.o pwent.o getpwnam.o getpwuid.o putpwent.o getpw.o fgetpwent.o
+GOBJ=__getgrent.o grent.o getgrnam.o getgrgid.o fgetgrent.o initgroups.o
+UOBJ=utent.o
+
+ifeq ($(LIB_OS),ELKS)
+
+OBJ=$(POBJ) $(GOBJ) $(UOBJ)
+
+all: $(LIBC)($(OBJ))
+ @:
+
+$(LIBC)($(GOBJ)): config-grp.h
+
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
+
diff --git a/libc/getent/__getgrent.c b/libc/getent/__getgrent.c
new file mode 100644
index 0000000..612f112
--- /dev/null
+++ b/libc/getent/__getgrent.c
@@ -0,0 +1,168 @@
+/*
+ * __getgrent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <grp.h>
+#include "config.h"
+
+/*
+ * This is the core group-file read function. It behaves exactly like
+ * getgrent() except that it is passed a file descriptor. getgrent()
+ * is just a wrapper for this function.
+ */
+struct group *
+__getgrent(int grp_fd)
+{
+#ifndef GR_SCALE_DYNAMIC
+ static char line_buff[GR_MAX_LINE_LEN];
+ static char * members[GR_MAX_MEMBERS];
+#else
+ static char * line_buff = NULL;
+ static char ** members = NULL;
+ short line_index;
+ short buff_size;
+#endif
+ static struct group group;
+ register char * ptr;
+ char * field_begin;
+ short member_num;
+ char * endptr;
+ int line_len;
+
+
+ /* We use the restart label to handle malformatted lines */
+restart:
+#ifdef GR_SCALE_DYNAMIC
+ line_index=0;
+ buff_size=256;
+#endif
+
+#ifndef GR_SCALE_DYNAMIC
+ /* Read the line into the static buffer */
+ if ((line_len=read(grp_fd, line_buff, GR_MAX_LINE_LEN))<=0)
+ return NULL;
+ field_begin=strchr(line_buff, '\n');
+ if (field_begin!=NULL)
+ lseek(grp_fd, (long) (1+field_begin-(line_buff+line_len)), SEEK_CUR);
+ else /* The line is too long - skip it :-\ */
+ {
+ do { if ((line_len=read(grp_fd, line_buff, GR_MAX_LINE_LEN))<=0)
+ return NULL;
+ } while (!(field_begin=strchr(line_buff, '\n')));
+ lseek(grp_fd, (long) ((field_begin-line_buff)-line_len+1), SEEK_CUR);
+ goto restart;
+ }
+ if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' ||
+ *line_buff=='\t')
+ goto restart;
+ *field_begin='\0';
+
+#else /* !GR_SCALE_DYNAMIC */
+ line_buff=realloc(line_buff, buff_size);
+ while (1)
+ {
+ if ((line_len=read(grp_fd, line_buff+line_index,
+ buff_size-line_index))<=0)
+ return NULL;
+ field_begin=strchr(line_buff, '\n');
+ if (field_begin!=NULL)
+ {
+ lseek(grp_fd, (long) (1+field_begin-(line_len+line_index+line_buff)),
+ SEEK_CUR);
+ *field_begin='\0';
+ if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' ||
+ *line_buff=='\t')
+ goto restart;
+ break;
+ }
+ else /* Allocate some more space */
+ {
+ line_index=buff_size;
+ buff_size+=256;
+ line_buff=realloc(line_buff, buff_size);
+ }
+ }
+#endif /* GR_SCALE_DYNAMIC */
+
+ /* Now parse the line */
+ group.gr_name=line_buff;
+ ptr=strchr(line_buff, ':');
+ if (ptr==NULL) goto restart;
+ *ptr++='\0';
+
+ group.gr_passwd=ptr;
+ ptr=strchr(ptr, ':');
+ if (ptr==NULL) goto restart;
+ *ptr++='\0';
+
+ field_begin=ptr;
+ ptr=strchr(ptr, ':');
+ if (ptr==NULL) goto restart;
+ *ptr++='\0';
+
+ group.gr_gid=(gid_t) strtoul(field_begin, &endptr, 10);
+ if (*endptr!='\0') goto restart;
+
+ member_num=0;
+ field_begin=ptr;
+
+#ifndef GR_SCALE_DYNAMIC
+ while ((ptr=strchr(ptr, ','))!=NULL)
+ {
+ *ptr='\0';
+ ptr++;
+ members[member_num]=field_begin;
+ field_begin=ptr;
+ member_num++;
+ }
+ if (*field_begin=='\0')
+ members[member_num]=NULL;
+ else
+ {
+ members[member_num]=field_begin;
+ members[member_num+1]=NULL;
+ }
+#else /* !GR_SCALE_DYNAMIC */
+ if (members!=NULL)
+ free (members);
+ members=(char **) malloc(1*sizeof(char *));
+ while ((ptr=strchr(ptr, ','))!=NULL)
+ {
+ *ptr='\0';
+ ptr++;
+ members[member_num]=field_begin;
+ field_begin=ptr;
+ member_num++;
+ members=(char **)realloc((void *)members, (member_num+1)*sizeof(char *));
+ }
+ if (*field_begin=='\0')
+ members[member_num]=NULL;
+ else
+ {
+ members[member_num]=field_begin;
+ members[member_num+1]=NULL;
+ }
+#endif /* GR_SCALE_DYNAMIC */
+
+ group.gr_mem=members;
+ return &group;
+}
diff --git a/libc/getent/__getpwent.c b/libc/getent/__getpwent.c
new file mode 100644
index 0000000..9836ca7
--- /dev/null
+++ b/libc/getent/__getpwent.c
@@ -0,0 +1,99 @@
+/*
+ * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+#define PWD_BUFFER_SIZE 256
+
+/* This isn't as flash as my previous version -- it doesn't dynamically
+ scale down the gecos on too-long lines, but it also makes fewer syscalls,
+ so it's probably nicer. Write me if you want the old version. Maybe I
+ should include it as a build-time option... ?
+ -Nat <ndf@linux.mit.edu> */
+
+struct passwd *
+__getpwent(int pwd_fd)
+{
+ static char line_buff[PWD_BUFFER_SIZE];
+ static struct passwd passwd;
+ char * field_begin;
+ char * endptr;
+ char * gid_ptr;
+ char * uid_ptr;
+ int line_len;
+ int i;
+
+ /* We use the restart label to handle malformatted lines */
+restart:
+ /* Read the passwd line into the static buffer using a minimal of
+ syscalls. */
+ if ((line_len=read(pwd_fd, line_buff, PWD_BUFFER_SIZE))<=0)
+ return NULL;
+ field_begin=strchr(line_buff, '\n');
+ if (field_begin!=NULL)
+ lseek(pwd_fd, (long) (1+field_begin-(line_buff+line_len)), SEEK_CUR);
+ else /* The line is too long - skip it. :-\ */
+ {
+ do { if ((line_len=read(pwd_fd, line_buff, PWD_BUFFER_SIZE))<=0)
+ return NULL;
+ } while (!(field_begin=strchr(line_buff, '\n')));
+ lseek(pwd_fd, (long) (field_begin-line_buff)-line_len+1, SEEK_CUR);
+ goto restart;
+ }
+ if (*line_buff=='#' || *line_buff==' ' || *line_buff=='\n' ||
+ *line_buff=='\t')
+ goto restart;
+ *field_begin='\0';
+
+ /* We've read the line; now parse it. */
+ field_begin=line_buff;
+ for (i=0;i<7;i++)
+ {
+ switch(i)
+ {
+ case 0: passwd.pw_name=field_begin; break;
+ case 1: passwd.pw_passwd=field_begin; break;
+ case 2: uid_ptr=field_begin; break;
+ case 3: gid_ptr=field_begin; break;
+ case 4: passwd.pw_gecos=field_begin; break;
+ case 5: passwd.pw_dir=field_begin; break;
+ case 6: passwd.pw_shell=field_begin; break;
+ }
+ if (i<6)
+ {
+ field_begin=strchr(field_begin, ':');
+ if (field_begin==NULL) goto restart;
+ *field_begin++='\0';
+ }
+ }
+ passwd.pw_gid=(gid_t) strtoul(gid_ptr, &endptr, 10);
+ if (*endptr!='\0') goto restart;
+
+ passwd.pw_uid=(uid_t) strtoul(uid_ptr, &endptr, 10);
+ if (*endptr!='\0') goto restart;
+
+ return &passwd;
+}
+
+
diff --git a/libc/getent/config-grp.h b/libc/getent/config-grp.h
new file mode 100644
index 0000000..337d54b
--- /dev/null
+++ b/libc/getent/config-grp.h
@@ -0,0 +1,65 @@
+/*
+ * config-grp.h - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef _CONFIG_GRP_H
+#define _CONFIG_GRP_H
+
+/*
+ * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
+ * so that lines of any length can be used. On very very small systems,
+ * you may want to leave this undefined becasue it will make the grp functions
+ * somewhat larger (because of the inclusion of malloc and the code necessary).
+ * On larger systems, you will want to define this, because grp will _not_
+ * deal with long lines gracefully (they will be skipped).
+ */
+#define GR_SCALE_DYNAMIC
+
+#ifndef GR_SCALE_DYNAMIC
+/*
+ * If scaling is not dynamic, the buffers will be statically allocated, and
+ * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of
+ * characters per line in the group file. GR_MAX_MEMBERS is the maximum
+ * number of members of any given group.
+ */
+#define GR_MAX_LINE_LEN 128
+/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
+#define GR_MAX_MEMBERS 11
+
+#endif /* !GR_SCALE_DYNAMIC */
+
+
+/*
+ * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
+ * space for it's GID array before calling setgroups(). This is probably
+ * unnecessary scalage, so it's undefined by default.
+ */
+#undef GR_DYNAMIC_GROUP_LIST
+
+#ifndef GR_DYNAMIC_GROUP_LIST
+/*
+ * GR_MAX_GROUPS is the size of the static array initgroups() uses for
+ * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined.
+ */
+#define GR_MAX_GROUPS 64
+
+#endif /* !GR_DYNAMIC_GROUP_LIST */
+
+#endif /* !_CONFIG_GRP_H */
diff --git a/libc/getent/config.h b/libc/getent/config.h
new file mode 100644
index 0000000..337d54b
--- /dev/null
+++ b/libc/getent/config.h
@@ -0,0 +1,65 @@
+/*
+ * config-grp.h - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#ifndef _CONFIG_GRP_H
+#define _CONFIG_GRP_H
+
+/*
+ * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
+ * so that lines of any length can be used. On very very small systems,
+ * you may want to leave this undefined becasue it will make the grp functions
+ * somewhat larger (because of the inclusion of malloc and the code necessary).
+ * On larger systems, you will want to define this, because grp will _not_
+ * deal with long lines gracefully (they will be skipped).
+ */
+#define GR_SCALE_DYNAMIC
+
+#ifndef GR_SCALE_DYNAMIC
+/*
+ * If scaling is not dynamic, the buffers will be statically allocated, and
+ * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of
+ * characters per line in the group file. GR_MAX_MEMBERS is the maximum
+ * number of members of any given group.
+ */
+#define GR_MAX_LINE_LEN 128
+/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
+#define GR_MAX_MEMBERS 11
+
+#endif /* !GR_SCALE_DYNAMIC */
+
+
+/*
+ * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
+ * space for it's GID array before calling setgroups(). This is probably
+ * unnecessary scalage, so it's undefined by default.
+ */
+#undef GR_DYNAMIC_GROUP_LIST
+
+#ifndef GR_DYNAMIC_GROUP_LIST
+/*
+ * GR_MAX_GROUPS is the size of the static array initgroups() uses for
+ * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined.
+ */
+#define GR_MAX_GROUPS 64
+
+#endif /* !GR_DYNAMIC_GROUP_LIST */
+
+#endif /* !_CONFIG_GRP_H */
diff --git a/libc/getent/fgetgrent.c b/libc/getent/fgetgrent.c
new file mode 100644
index 0000000..800236f
--- /dev/null
+++ b/libc/getent/fgetgrent.c
@@ -0,0 +1,35 @@
+/*
+ * fgetgrent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <grp.h>
+
+struct group *
+fgetgrent(FILE * file)
+{
+ if (file==NULL)
+ {
+ errno=EINTR;
+ return NULL;
+ }
+
+ return __getgrent(fileno(file));
+}
diff --git a/libc/getent/fgetpwent.c b/libc/getent/fgetpwent.c
new file mode 100644
index 0000000..e12b890
--- /dev/null
+++ b/libc/getent/fgetpwent.c
@@ -0,0 +1,35 @@
+/*
+ * fgetpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <pwd.h>
+
+struct passwd *
+fgetpwent(FILE * file)
+{
+ if (file==NULL)
+ {
+ errno=EINTR;
+ return NULL;
+ }
+
+ return __getpwent(fileno(file));
+}
diff --git a/libc/getent/getgrgid.c b/libc/getent/getgrgid.c
new file mode 100644
index 0000000..c1dd20e
--- /dev/null
+++ b/libc/getent/getgrgid.c
@@ -0,0 +1,48 @@
+/*
+ * getgrgid.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+
+struct group *
+getgrgid(const gid_t gid)
+{
+ struct group * group;
+ int grp_fd;
+
+ if ((grp_fd=open("/etc/group", O_RDONLY))<0)
+ return NULL;
+
+ while ((group=__getgrent(grp_fd))!=NULL)
+ if (group->gr_gid==gid)
+ {
+ close(grp_fd);
+ return group;
+ }
+
+ close(grp_fd);
+ return NULL;
+}
+
+
+
+
diff --git a/libc/getent/getgrnam.c b/libc/getent/getgrnam.c
new file mode 100644
index 0000000..e6c27fc
--- /dev/null
+++ b/libc/getent/getgrnam.c
@@ -0,0 +1,51 @@
+/*
+ * getgrnam.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+
+struct group *
+getgrnam(const char * name)
+{
+ int grp_fd;
+ struct group * group;
+
+ if (name==NULL)
+ {
+ errno=EINVAL;
+ return NULL;
+ }
+
+ if ((grp_fd=open("/etc/group", O_RDONLY))<0)
+ return NULL;
+
+ while ((group=__getgrent(grp_fd))!=NULL)
+ if (!strcmp(group->gr_name, name))
+ {
+ close(grp_fd);
+ return group;
+ }
+
+ close(grp_fd);
+ return NULL;
+}
diff --git a/libc/getent/getpw.c b/libc/getent/getpw.c
new file mode 100644
index 0000000..4f4e390
--- /dev/null
+++ b/libc/getent/getpw.c
@@ -0,0 +1,51 @@
+/*
+ * getpw.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#include <pwd.h>
+
+int
+getpw(uid_t uid, char *buf)
+{
+ struct passwd * passwd;
+
+ if (buf==NULL)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+ if ((passwd=getpwuid(uid))==NULL)
+ return -1;
+
+ if (sprintf(buf, "%s:%s:%u:%u:%s:%s:%s", passwd->pw_name, passwd->pw_passwd,
+ passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos,
+ passwd->pw_dir, passwd->pw_shell)<0)
+ {
+ errno=ENOBUFS;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
diff --git a/libc/getent/getpwnam.c b/libc/getent/getpwnam.c
new file mode 100644
index 0000000..85dbc8e
--- /dev/null
+++ b/libc/getent/getpwnam.c
@@ -0,0 +1,52 @@
+/*
+ * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+
+struct passwd *
+getpwnam(const char * name)
+{
+ int passwd_fd;
+ struct passwd * passwd;
+
+ if (name==NULL)
+ {
+ errno=EINVAL;
+ return NULL;
+ }
+
+ if ((passwd_fd=open("/etc/passwd", O_RDONLY))<0)
+ return NULL;
+
+ while ((passwd=__getpwent(passwd_fd))!=NULL)
+ if (!strcmp(passwd->pw_name, name))
+ {
+ close(passwd_fd);
+ return passwd;
+ }
+
+ close(passwd_fd);
+ return NULL;
+}
diff --git a/libc/getent/getpwuid.c b/libc/getent/getpwuid.c
new file mode 100644
index 0000000..ffd58c1
--- /dev/null
+++ b/libc/getent/getpwuid.c
@@ -0,0 +1,44 @@
+/*
+ * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+struct passwd *
+getpwuid(uid_t uid)
+{
+ int passwd_fd;
+ struct passwd * passwd;
+
+ if ((passwd_fd=open("/etc/passwd", O_RDONLY))<0)
+ return NULL;
+
+ while ((passwd=__getpwent(passwd_fd))!=NULL)
+ if (passwd->pw_uid==uid)
+ {
+ close(passwd_fd);
+ return passwd;
+ }
+
+ close (passwd_fd);
+ return NULL;
+}
diff --git a/libc/getent/grent.c b/libc/getent/grent.c
new file mode 100644
index 0000000..19d618b
--- /dev/null
+++ b/libc/getent/grent.c
@@ -0,0 +1,57 @@
+/*
+ * grent.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * setgrent(), endgrent(), and getgrent() are mutually-dependent functions,
+ * so they are all included in the same object file, and thus all linked
+ * in together.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <grp.h>
+
+static int grp_fd=-1;
+
+void
+setgrent(void)
+{
+ if (grp_fd!=-1)
+ close(grp_fd);
+ grp_fd=open("/etc/group", O_RDONLY);
+}
+
+void
+endgrent(void)
+{
+ if (grp_fd!=-1)
+ close(grp_fd);
+ grp_fd=-1;
+}
+
+struct group *
+getgrent(void)
+{
+ if (grp_fd==-1)
+ return NULL;
+ return __getgrent(grp_fd);
+}
+
+
diff --git a/libc/getent/initgroups.c b/libc/getent/initgroups.c
new file mode 100644
index 0000000..35e1d03
--- /dev/null
+++ b/libc/getent/initgroups.c
@@ -0,0 +1,80 @@
+/*
+ * initgroups.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <grp.h>
+#include "config.h"
+
+int
+initgroups(__const char * user, gid_t gid)
+{
+ register struct group * group;
+#ifndef GR_DYNAMIC_GROUP_LIST
+ gid_t group_list[GR_MAX_GROUPS];
+#else
+ gid_t * group_list=NULL;
+#endif
+ register char ** tmp_mem;
+ int num_groups;
+ int grp_fd;
+
+
+ if ((grp_fd=open("/etc/group", O_RDONLY))<0)
+ return -1;
+
+ num_groups=0;
+#ifdef GR_DYNAMIC_GROUP_LIST
+ group_list=(gid_t *) realloc(group_list, 1);
+#endif
+ group_list[num_groups]=gid;
+#ifndef GR_DYNAMIC_GROUP_LIST
+ while (num_groups<GR_MAX_GROUPS &&
+ (group=__getgrent(grp_fd))!=NULL)
+#else
+ while ((group=__getgrent(grp_fd))!=NULL)
+#endif
+ {
+ if (group->gr_gid!=gid);
+ {
+ tmp_mem=group->gr_mem;
+ while(*tmp_mem!=NULL)
+ {
+ if (!strcmp(*tmp_mem, user))
+ {
+ num_groups++;
+#ifdef GR_DYNAMIC_GROUP_LIST
+ group_list=(gid_t *)realloc(group_list,
+ num_groups*sizeof(gid_t *));
+#endif
+ group_list[num_groups]=group->gr_gid;
+ }
+ tmp_mem++;
+ }
+ }
+ }
+ close(grp_fd);
+ return setgroups(num_groups, group_list);
+}
+
+
+
+
diff --git a/libc/getent/putpwent.c b/libc/getent/putpwent.c
new file mode 100644
index 0000000..a0035ea
--- /dev/null
+++ b/libc/getent/putpwent.c
@@ -0,0 +1,39 @@
+/*
+ * putpwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+
+int
+putpwent(const struct passwd * passwd, FILE * f)
+{
+ if (passwd == NULL || f == NULL)
+ {
+ errno=EINVAL;
+ return -1;
+ }
+ if (fprintf(f, "%s:%s:%u:%u:%s:%s:%s\n", passwd->pw_name, passwd->pw_passwd,
+ passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos,
+ passwd->pw_dir, passwd->pw_shell)<0)
+ return -1;
+
+ return 0;
+}
diff --git a/libc/getent/pwent.c b/libc/getent/pwent.c
new file mode 100644
index 0000000..fd65db2
--- /dev/null
+++ b/libc/getent/pwent.c
@@ -0,0 +1,62 @@
+/*
+ * pwent.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pwd.h>
+#include <fcntl.h>
+
+/*
+ * setpwent(), endpwent(), and getpwent() are included in the same object
+ * file, since one cannot be used without the other two, so it makes sense to
+ * link them all in together.
+ */
+
+/* file descriptor for the password file currently open */
+static int pw_fd = -1;
+
+void
+setpwent(void)
+{
+ if (pw_fd!=-1)
+ close(pw_fd);
+
+ pw_fd=open("/etc/passwd", O_RDONLY);
+}
+
+void
+endpwent(void)
+{
+ if (pw_fd!=-1)
+ close(pw_fd);
+ pw_fd=-1;
+}
+
+struct passwd *
+getpwent(void)
+{
+ if (pw_fd!=-1)
+ return __getpwent(pw_fd);
+ return NULL;
+}
+
+
+
diff --git a/libc/getent/test_grp.c b/libc/getent/test_grp.c
new file mode 100644
index 0000000..b5ecd36
--- /dev/null
+++ b/libc/getent/test_grp.c
@@ -0,0 +1,107 @@
+/*
+ * test_grp.c - This file is part of the libc-8086/grp package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <grp.h>
+
+int
+main(int argc, char ** argv)
+{
+ struct group * group;
+ char ** tmp_mem;
+ int test_gid;
+
+ fprintf(stderr, "Beginning test of libc/grp...\n");
+
+ fprintf(stderr, "=> Testing setgrent(), getgrent(), endgrent()...\n");
+ fprintf(stderr, "-> setgrent()...\n");
+ setgrent();
+ fprintf(stderr, "-> getgrent()...\n");
+ printf("********************************************************************************\n");
+ while ((group=getgrent())!=NULL)
+ {
+ printf("gr_name\t\t: %s\n", group->gr_name);
+ printf("gr_passwd\t: %s\n", group->gr_passwd);
+ printf("gr_gid\t\t: %d\n", (int) group->gr_gid);
+ printf("gr_mem\t\t: ");
+ fflush(stdout);
+ tmp_mem=group->gr_mem;
+ while(*tmp_mem!=NULL)
+ {
+ printf("%s, ", *tmp_mem);
+ tmp_mem++;
+ }
+ printf("\n********************************************************************************\n");
+ }
+ fprintf(stderr, "-> endgrent()...\n");
+ endgrent();
+ fprintf(stderr, "=> Test of setgrent(), getgrent(), endgrent() complete.\n");
+ fprintf(stderr, "=> Testing getgrid(), getgrnam()...\n");
+ fprintf(stderr, "-> getgrgid()...\n");
+ printf("********************************************************************************\n");
+ for(test_gid=0;test_gid<100;test_gid++)
+ {
+ fprintf(stderr, "-> getgrgid(%d)...\n", test_gid);
+ group=getgrgid((gid_t) test_gid);
+ if (group!=NULL)
+ {
+ printf("gr_name\t: %s\n", group->gr_name);
+ printf("gr_passwd\t: %s\n", group->gr_passwd);
+ printf("gr_gid\t: %d\n", (int) group->gr_gid);
+ printf("gr_mem\t\t: ");
+ fflush(stdout);
+ tmp_mem=group->gr_mem;
+ while(*tmp_mem!=NULL)
+ {
+ printf("%s, ", *tmp_mem);
+ tmp_mem++;
+ }
+ }
+ printf("\n********************************************************************************\n");
+ }
+ fprintf(stderr, "-> getgrnam()...\n");
+ group=getgrnam("root");
+ if (group==NULL)
+ {
+ printf(">NULL<\n");
+ }
+ else
+ {
+ printf("gr_name\t: %s\n", group->gr_name);
+ printf("gr_passwd\t: %s\n", group->gr_passwd);
+ printf("gr_gid\t: %d\n", (int) group->gr_gid);
+ printf("gr_mem\t\t: ");
+ fflush(stdout);
+ tmp_mem=group->gr_mem;
+ while(*tmp_mem!=NULL)
+ {
+ printf("%s, ", *tmp_mem);
+ tmp_mem++;
+ }
+ printf("\n");
+ }
+
+
+ return 0;
+}
+
+
diff --git a/libc/getent/test_pwd.c b/libc/getent/test_pwd.c
new file mode 100644
index 0000000..74f7657
--- /dev/null
+++ b/libc/getent/test_pwd.c
@@ -0,0 +1,91 @@
+/*
+ * test_pwd.c - This file is part of the libc-8086/pwd package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <pwd.h>
+
+int
+main(int argc, char ** argv)
+{
+ struct passwd * passwd;
+ int test_uid;
+
+ fprintf(stderr, "Beginning test of libc/pwd...\n");
+
+ fprintf(stderr, "=> Testing setpwent(), getpwent(), endpwent()...\n");
+ fprintf(stderr, "-> setpwent()...\n");
+ setpwent();
+ fprintf(stderr, "-> getpwent()...\n");
+ printf("********************************************************************************\n");
+ while ((passwd=getpwent())!=NULL)
+ {
+ printf("pw_name\t\t: %s\n", passwd->pw_name);
+ printf("pw_passwd\t: %s\n", passwd->pw_passwd);
+ printf("pw_uid\t\t: %d\n", (int) passwd->pw_uid);
+ printf("pw_gid\t\t: %d\n", (int) passwd->pw_gid);
+ printf("pw_gecos\t: %s\n", passwd->pw_gecos);
+ printf("pw_dir\t\t: %s\n", passwd->pw_dir);
+ printf("pw_shell\t: %s\n", passwd->pw_shell);
+ printf("********************************************************************************\n");
+ }
+ fprintf(stderr, "-> endpwent()...\n");
+ endpwent();
+ fprintf(stderr, "=> Test of setpwent(), getpwent(), endpwent() complete.\n");
+ fprintf(stderr, "=> Testing getpwuid(), getpwnam()...\n");
+ fprintf(stderr, "-> getpwuid()...\n");
+ printf("********************************************************************************\n");
+ for(test_uid=0;test_uid<1000;test_uid++)
+ {
+ fprintf(stderr, "-> getpwuid(%d)...\n", test_uid);
+ passwd=getpwuid((uid_t) test_uid);
+ if (passwd!=NULL)
+ {
+ printf("pw_name\t\t: %s\n", passwd->pw_name);
+ printf("pw_passwd\t: %s\n", passwd->pw_passwd);
+ printf("pw_uid\t\t: %d\n", (int) passwd->pw_uid);
+ printf("pw_gid\t\t: %d\n", (int) passwd->pw_gid);
+ printf("pw_gecos\t: %s\n", passwd->pw_gecos);
+ printf("pw_dir\t\t: %s\n", passwd->pw_dir);
+ printf("pw_shell\t: %s\n", passwd->pw_shell);
+ printf("********************************************************************************\n");
+ }
+ }
+ fprintf(stderr, "-> getpwnam()...\n");
+ passwd=getpwnam("root");
+ if (passwd==NULL)
+ {
+ printf(">NULL<\n");
+ }
+ else
+ {
+ printf("pw_name\t\t: %s\n", passwd->pw_name);
+ printf("pw_passwd\t: %s\n", passwd->pw_passwd);
+ printf("pw_uid\t\t: %d\n", (int) passwd->pw_uid);
+ printf("pw_gid\t\t: %d\n", (int) passwd->pw_gid);
+ printf("pw_gecos\t: %s\n", passwd->pw_gecos);
+ printf("pw_dir\t\t: %s\n", passwd->pw_dir);
+ printf("pw_shell\t: %s\n", passwd->pw_shell);
+ }
+ return 0;
+}
+
+
diff --git a/libc/getent/utent.c b/libc/getent/utent.c
new file mode 100644
index 0000000..7f9e19a
--- /dev/null
+++ b/libc/getent/utent.c
@@ -0,0 +1,152 @@
+/* utent.c <ndf@linux.mit.edu> */
+/* Let it be known that this is very possibly the worst standard ever. HP-UX
+ does one thing, someone else does another, linux another... If anyone
+ actually has the standard, please send it to me.
+
+ Note that because of the way this stupid stupid standard works, you
+ have to call endutent() to close the file even if you've not called
+ setutent -- getutid and family use the same file descriptor. */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <errno.h>
+#include <string.h>
+#include <utmp.h>
+
+static const char * ut_name=_PATH_UTMP;
+
+static int ut_fd=-1;
+
+struct utmp *
+__getutent(int utmp_fd)
+{
+ static struct utmp utmp;
+ if (read(utmp_fd, (char *) &utmp, sizeof(struct utmp))!=sizeof(struct utmp))
+ return NULL;
+ return &utmp;
+}
+
+void
+setutent(void)
+{
+ if (ut_fd!=-1)
+ close(ut_fd);
+ if ((ut_fd=open(ut_name, O_RDONLY))<0)
+ {
+ perror("setutent: Can't open utmp file");
+ ut_fd=-1;
+ }
+}
+
+void
+endutent(void)
+{
+ if (ut_fd!=-1)
+ close(ut_fd);
+ ut_fd=-1;
+}
+
+struct utmp *
+getutent(void)
+{
+ if (ut_fd==-1)
+ setutent();
+ if (ut_fd==-1)
+ return NULL;
+ return __getutent(ut_fd);
+}
+
+struct utmp *
+getutid(struct utmp * utmp_entry)
+{
+ struct utmp * utmp;
+
+ if (ut_fd==-1)
+ setutent();
+ if (ut_fd==-1)
+ return NULL;
+
+ while ((utmp=__getutent(ut_fd))!=NULL)
+ {
+ if ((utmp_entry->ut_type==RUN_LVL ||
+ utmp_entry->ut_type==BOOT_TIME ||
+ utmp_entry->ut_type==NEW_TIME ||
+ utmp_entry->ut_type==OLD_TIME) &&
+ utmp->ut_type==utmp_entry->ut_type)
+ return utmp;
+ if ((utmp_entry->ut_type==INIT_PROCESS ||
+ utmp_entry->ut_type==DEAD_PROCESS ||
+ utmp_entry->ut_type==LOGIN_PROCESS ||
+ utmp_entry->ut_type==USER_PROCESS) &&
+ !strcmp(utmp->ut_id, utmp_entry->ut_id))
+ return utmp;
+ }
+
+ return NULL;
+}
+
+struct utmp *
+getutline(struct utmp * utmp_entry)
+{
+ struct utmp * utmp;
+
+ if (ut_fd==-1)
+ setutent();
+ if (ut_fd==-1)
+ return NULL;
+
+#if 0 /* This is driving me nuts. It's not an implementation problem -
+ it's a matter of how things _SHOULD_ behave. Groan. */
+ lseek(ut_fd, SEEK_CUR, -sizeof(struct utmp));
+#endif
+
+ while ((utmp=__getutent(ut_fd))!=NULL)
+ {
+ if ((utmp->ut_type==USER_PROCESS ||
+ utmp->ut_type==LOGIN_PROCESS) &&
+ !strcmp(utmp->ut_line, utmp_entry->ut_line))
+ return utmp;
+ }
+
+ return NULL;
+}
+
+struct utmp *
+pututline(struct utmp * utmp_entry)
+{
+ struct utmp * ut;
+
+ /* Ignore the return value. That way, if they've already positioned
+ the file pointer where they want it, everything will work out. */
+ (void) lseek(ut_fd, (off_t) -sizeof(utmp_entry), SEEK_CUR);
+
+ if ((ut=getutid(utmp_entry))!=NULL)
+ {
+ lseek(ut_fd, (off_t) -sizeof(utmp_entry), SEEK_CUR);
+ if (write(ut_fd, (char *) utmp_entry, sizeof(utmp_entry))
+ != sizeof(utmp_entry))
+ return NULL;
+ }
+ else
+ {
+ lseek(ut_fd, (off_t) 0, SEEK_END);
+ if (write(ut_fd, (char *) utmp_entry, sizeof(utmp_entry))
+ != sizeof(utmp_entry))
+ return NULL;
+ }
+
+ return utmp_entry;
+}
+
+void
+utmpname(const char * new_ut_name)
+{
+ if (new_ut_name!=NULL)
+ ut_name=new_ut_name;
+
+ if (ut_fd!=-1)
+ close(ut_fd);
+}
+
+
diff --git a/libc/gtermcap/COPYING b/libc/gtermcap/COPYING
new file mode 100644
index 0000000..a43ea21
--- /dev/null
+++ b/libc/gtermcap/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/libc/gtermcap/ChangeLog b/libc/gtermcap/ChangeLog
new file mode 100644
index 0000000..22d6ceb
--- /dev/null
+++ b/libc/gtermcap/ChangeLog
@@ -0,0 +1,52 @@
+Sat Apr 17 13:50:10 1993 H.J. Lu (hlu@nighthawk)
+
+ * modify termcap.c and tparam.c for Linux.
+
+Thu Apr 15 12:45:10 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * Version 1.2.
+
+ * tparam.c [!emacs] (xmalloc, xrealloc, memory_out): New functions.
+ (tparam1): Use them.
+
+ * termcap.c, tparam.c: Use NULL or '\0' where appropriate
+ instead of 0. Rename some vars.
+ * termcap.c (tgetent): If EOF is reached on termcap file,
+ free allocated resources before returning.
+
+ * termcap.c (tgetent): Use /etc/termcap if TERMCAP is an entry
+ for a term type other than TERM.
+ From pjr@jet.UK (Paul J Rippin).
+
+Sat Apr 10 23:55:12 1993 Richard Stallman (rms@mole.gnu.ai.mit.edu)
+
+ * tparam.c (tparam1): Don't set the 0200 bit on a non-0 character code.
+ From junio@twinsun.COM (Junio Hamano).
+
+Tue Dec 8 22:02:15 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * termcap.c, tparam.c: Use HAVE_STRING_H instead of USG.
+
+Thu Dec 3 13:47:56 1992 David J. MacKenzie (djm@nutrimat.gnu.ai.mit.edu)
+
+ * termcap.c, tparam.c [HAVE_CONFIG_H]: Include config.h.
+
+Fri Oct 23 12:35:29 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * termcap.h [__STDC__]: Add consts. From Franc,ois Pinard.
+
+Tue Oct 13 15:52:21 1992 David J. MacKenzie (djm@goldman.gnu.ai.mit.edu)
+
+ * Version 1.1.
+
+Tue Sep 29 21:04:39 1992 David J. MacKenzie (djm@geech.gnu.ai.mit.edu)
+
+ * termcap.[ch], tparam.c: Fix some lint.
+
+ * version.c: New file.
+
+Local Variables:
+mode: indented-text
+left-margin: 8
+version-control: never
+End:
diff --git a/libc/gtermcap/Makefile b/libc/gtermcap/Makefile
new file mode 100644
index 0000000..44e21da
--- /dev/null
+++ b/libc/gtermcap/Makefile
@@ -0,0 +1,19 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+ifeq ($(LIB_OS),ELKS)
+OBJ=termcap.o tparam.o
+
+all: $(LIBC)($(OBJ))
+ @:
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
+
diff --git a/libc/gtermcap/Makefile.old b/libc/gtermcap/Makefile.old
new file mode 100644
index 0000000..453c47a
--- /dev/null
+++ b/libc/gtermcap/Makefile.old
@@ -0,0 +1,25 @@
+#
+# Makefile for termcap functions
+#
+
+override DEBUG=false
+override PROFILE=false
+#override CHECKER=false
+JUMP_LIB=libtermcap
+
+TOPDIR=..
+
+include $(TOPDIR)/Makeconfig
+include $(TOPDIR)/Makerules
+
+override STATIC_LIB=$(STATIC_DIR)/libtermcap.a
+override SHARED_LIB=$(SHARED_DIR)/libtermcap.a
+override CHECKER_LIB=$(CHECKER_DIR)/libtermcap.a
+
+DIRS:=
+SRCS = termcap.c tparam.c
+ASMS= $(SRCS:.c=.s)
+OBJS= $(SRCS:.c=.o)
+ALIASES=
+
+include $(TOPDIR)/Maketargets
diff --git a/libc/gtermcap/NEWS b/libc/gtermcap/NEWS
new file mode 100644
index 0000000..c696fdf
--- /dev/null
+++ b/libc/gtermcap/NEWS
@@ -0,0 +1,12 @@
+Major changes in release 1.2:
+
+For `%.', only set the high bit on NUL.
+Fix a file descriptor and memory leak.
+Add const in termcap.h prototypes.
+Configuration improvements.
+
+Major changes in release 1.1:
+
+Fix portability problems.
+Improve configuration and installation.
+Fix compiler warnings.
diff --git a/libc/gtermcap/README b/libc/gtermcap/README
new file mode 100644
index 0000000..9db9095
--- /dev/null
+++ b/libc/gtermcap/README
@@ -0,0 +1,14 @@
+This is the GNU termcap library -- a library of C functions that
+enable programs to send control strings to terminals in a way
+independent of the terminal type. Most of this package is also
+distributed with GNU Emacs, but it is available in this separate
+distribution to make it easier to install as -ltermcap.
+
+The GNU termcap library does not place an arbitrary limit on the size
+of termcap entries, unlike most other termcap libraries.
+
+See the file INSTALL for compilation and installation instructions.
+
+Please report any bugs in this library to bug-gnu-emacs@prep.ai.mit.edu.
+You can check which version of the library you have by using the RCS
+`ident' command on libtermcap.a.
diff --git a/libc/gtermcap/termcap.c b/libc/gtermcap/termcap.c
new file mode 100644
index 0000000..d79f51a
--- /dev/null
+++ b/libc/gtermcap/termcap.c
@@ -0,0 +1,827 @@
+/* Work-alike for termcap, plus extra features.
+ Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Emacs config.h may rename various library functions such as malloc. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#else /* not HAVE_CONFIG_H */
+
+#ifdef __linux__
+#undef STDC_HEADERS
+#define STDC_HEADERS
+#define HAVE_UNISTD_H
+#define HAVE_SYS_IOCTL_H
+#else
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+char *getenv ();
+char *malloc ();
+char *realloc ();
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef _POSIX_VERSION
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <stdio.h>
+#include <sys/ioctl.h>
+#endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#ifndef NULL
+#define NULL (char *) 0
+#endif
+
+/* BUFSIZE is the initial size allocated for the buffer
+ for reading the termcap file.
+ It is not a limit.
+ Make it large normally for speed.
+ Make it variable when debugging, so can exercise
+ increasing the space dynamically. */
+
+#ifndef BUFSIZE
+#ifdef DEBUG
+#define BUFSIZE bufsize
+
+int bufsize = 128;
+#else
+#define BUFSIZE 2048
+#endif
+#endif
+
+#ifdef TIOCGWINSZ
+#define ADJUST_WIN_EXTENT
+#endif
+
+#ifndef emacs
+static void
+memory_out ()
+{
+ write (2, "virtual memory exhausted\n", 25);
+ exit (1);
+}
+
+static char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *tem = malloc (size);
+
+ if (!tem)
+ memory_out ();
+ return tem;
+}
+
+static char *
+xrealloc (ptr, size)
+ char *ptr;
+ unsigned size;
+{
+ register char *tem = realloc (ptr, size);
+
+ if (!tem)
+ memory_out ();
+ return tem;
+}
+#endif /* not emacs */
+
+/* Looking up capabilities in the entry already found. */
+
+/* The pointer to the data made by tgetent is left here
+ for tgetnum, tgetflag and tgetstr to find. */
+static char *term_entry;
+
+static char *tgetst1 ();
+
+/* Search entry BP for capability CAP.
+ Return a pointer to the capability (in BP) if found,
+ 0 if not found. */
+
+static char *
+find_capability (bp, cap)
+ register char *bp, *cap;
+{
+ for (; *bp; bp++)
+ if (bp[0] == ':'
+ && bp[1] == cap[0]
+ && bp[2] == cap[1])
+ return &bp[4];
+ return NULL;
+}
+
+int
+tgetnum (cap)
+ char *cap;
+{
+ register char *ptr = find_capability (term_entry, cap);
+ if (!ptr || ptr[-1] != '#')
+ return -1;
+ return atoi (ptr);
+}
+
+int
+tgetflag (cap)
+ char *cap;
+{
+ register char *ptr = find_capability (term_entry, cap);
+ return ptr && ptr[-1] == ':';
+}
+
+/* Look up a string-valued capability CAP.
+ If AREA is non-null, it points to a pointer to a block in which
+ to store the string. That pointer is advanced over the space used.
+ If AREA is null, space is allocated with `malloc'. */
+
+char *
+tgetstr (cap, area)
+ char *cap;
+ char **area;
+{
+ register char *ptr = find_capability (term_entry, cap);
+ if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
+ return NULL;
+ return tgetst1 (ptr, area);
+}
+
+/* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
+ gives meaning of character following \, or a space if no special meaning.
+ Eight characters per line within the string. */
+
+static char esctab[]
+ = " \007\010 \033\014 \
+ \012 \
+ \015 \011 \013 \
+ ";
+
+/* PTR points to a string value inside a termcap entry.
+ Copy that value, processing \ and ^ abbreviations,
+ into the block that *AREA points to,
+ or to newly allocated storage if AREA is NULL.
+ Return the address to which we copied the value,
+ or NULL if PTR is NULL. */
+
+static char *
+tgetst1 (ptr, area)
+ char *ptr;
+ char **area;
+{
+ register char *p, *r;
+ register int c;
+ register int size;
+ char *ret;
+ register int c1;
+
+ if (!ptr)
+ return NULL;
+
+ /* `ret' gets address of where to store the string. */
+ if (!area)
+ {
+ /* Compute size of block needed (may overestimate). */
+ p = ptr;
+ while ((c = *p++) && c != ':' && c != '\n')
+ ;
+ ret = (char *) xmalloc (p - ptr + 1);
+ }
+ else
+ ret = *area;
+
+ /* Copy the string value, stopping at null or colon.
+ Also process ^ and \ abbreviations. */
+ p = ptr;
+ r = ret;
+ while ((c = *p++) && c != ':' && c != '\n')
+ {
+ if (c == '^')
+ c = *p++ & 037;
+ else if (c == '\\')
+ {
+ c = *p++;
+ if (c >= '0' && c <= '7')
+ {
+ c -= '0';
+ size = 0;
+
+ while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
+ {
+ c *= 8;
+ c += c1 - '0';
+ p++;
+ }
+ }
+ else if (c >= 0100 && c < 0200)
+ {
+ c1 = esctab[(c & ~040) - 0100];
+ if (c1 != ' ')
+ c = c1;
+ }
+ }
+ *r++ = c;
+ }
+ *r = '\0';
+ /* Update *AREA. */
+ if (area)
+ *area = r + 1;
+ return ret;
+}
+
+/* Outputting a string with padding. */
+
+#ifdef __linux__
+speed_t ospeed;
+#else
+short ospeed;
+#endif
+/* If OSPEED is 0, we use this as the actual baud rate. */
+int tputs_baud_rate;
+char PC;
+
+/* Actual baud rate if positive;
+ - baud rate / 100 if negative. */
+
+static short speeds[] =
+ {
+#ifdef VMS
+ 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
+ -20, -24, -36, -48, -72, -96, -192
+#else /* not VMS */
+ 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
+ -18, -24, -48, -96, -192, -384
+#endif /* not VMS */
+ };
+
+void
+tputs (str, nlines, outfun)
+ register char *str;
+ int nlines;
+ register int (*outfun) ();
+{
+ register int padcount = 0;
+ register int speed;
+
+#ifdef emacs
+ extern baud_rate;
+ speed = baud_rate;
+#else
+ if (ospeed == 0)
+ speed = tputs_baud_rate;
+ else
+ speed = speeds[ospeed];
+#endif
+
+ if (!str)
+ return;
+
+ while (*str >= '0' && *str <= '9')
+ {
+ padcount += *str++ - '0';
+ padcount *= 10;
+ }
+ if (*str == '.')
+ {
+ str++;
+ padcount += *str++ - '0';
+ }
+ if (*str == '*')
+ {
+ str++;
+ padcount *= nlines;
+ }
+ while (*str)
+ (*outfun) (*str++);
+
+ /* padcount is now in units of tenths of msec. */
+ padcount *= speeds[ospeed];
+ padcount += 500;
+ padcount /= 1000;
+ if (speeds[ospeed] < 0)
+ padcount = -padcount;
+ else
+ {
+ padcount += 50;
+ padcount /= 100;
+ }
+
+ while (padcount-- > 0)
+ (*outfun) (PC);
+}
+
+/* Finding the termcap entry in the termcap data base. */
+
+struct buffer
+ {
+ char *beg;
+ int size;
+ char *ptr;
+ int ateof;
+ int full;
+ };
+
+/* Forward declarations of static functions. */
+
+static int scan_file ();
+static char *gobble_line ();
+static int compare_contin ();
+static int name_match ();
+
+#ifdef ADJUST_WIN_EXTENT
+#ifdef TIOCGWINSZ
+static int
+get_win_extent(li, co)
+int *li, *co;
+{
+ struct winsize ws;
+
+ /* Some TIOCGWINSZ may be broken. Make sure ws.ws_row and
+ * ws.ws_col are not zero.
+ */
+ if (ioctl(0, TIOCGWINSZ, &ws) != 0 || !ws.ws_row || !ws.ws_col)
+ return -1;
+ *li = ws.ws_row;
+ *co = ws.ws_col;
+ return 0;
+}
+#endif /* TIOCGWINSZ */
+
+static int
+adjust_win_extent(bpp, howalloc, li, co)
+char **bpp;
+int howalloc; /* 0 must do in place, 1 must use malloc, 2 must use realloc */
+int li, co;
+{
+ int licolen, o_len, t, colon;
+ char *licobuf, *s;
+
+ if (li < 0 || co < 0)
+ return 0;
+ for (s = *bpp, colon = -1; *s; ++s)
+ if (*s == ':' && colon < 0)
+ colon = s - *bpp;
+ o_len = s - *bpp;
+ licolen = 11;
+ for (t = li; (t /= 10) > 0; ++licolen);
+ for (t = co; (t /= 10) > 0; ++licolen);
+
+ licobuf = xmalloc(licolen + 1);
+ sprintf(licobuf, ":li#%d:co#%d:", li, co);
+
+ if (howalloc == 0)
+ {
+ bcopy(*bpp + colon, *bpp + colon + licolen, o_len - colon + 1);
+ bcopy(licobuf, *bpp + colon, licolen);
+ }
+ else if (howalloc == 1)
+ {
+ char *newbp;
+
+ newbp = xmalloc(o_len + licolen + 1);
+ bcopy(*bpp, newbp, colon);
+ bcopy(licobuf, newbp + colon, licolen);
+ strcpy(newbp + colon + licolen, *bpp + colon);
+ *bpp = newbp;
+ }
+ else /* (howalloc == 2) */
+ {
+ char *newbp;
+
+ newbp = xrealloc(*bpp, o_len + licolen + 1);
+ bcopy(newbp + colon, newbp + colon + licolen, o_len - colon + 1);
+ bcopy(licobuf, newbp + colon, licolen);
+ *bpp = newbp;
+ }
+
+ free(licobuf);
+ return 1;
+}
+#endif /* ADJUST_WIN_EXTENT */
+
+#ifdef VMS
+
+#include <rmsdef.h>
+#include <fab.h>
+#include <nam.h>
+
+static int
+valid_filename_p (fn)
+ char *fn;
+{
+ struct FAB fab = cc$rms_fab;
+ struct NAM nam = cc$rms_nam;
+ char esa[NAM$C_MAXRSS];
+
+ fab.fab$l_fna = fn;
+ fab.fab$b_fns = strlen(fn);
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = sizeof esa;
+
+ return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
+}
+
+#else /* !VMS */
+
+#define valid_filename_p(fn) (*(fn) == '/')
+
+#endif /* !VMS */
+
+/* Find the termcap entry data for terminal type NAME
+ and store it in the block that BP points to.
+ Record its address for future use.
+
+ If BP is null, space is dynamically allocated.
+
+ Return -1 if there is some difficulty accessing the data base
+ of terminal types,
+ 0 if the data base is accessible but the type NAME is not defined
+ in it, and some other value otherwise. */
+
+int
+tgetent (bp, name)
+ char *bp, *name;
+{
+ register char *termcap_name;
+ register int fd;
+ struct buffer buf;
+ register char *bp1;
+ char *bp2;
+ char *term;
+ int malloc_size = 0;
+ register int c;
+ char *tcenv; /* TERMCAP value, if it contains :tc=. */
+ char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
+ int filep;
+#ifdef ADJUST_WIN_EXTENT
+ int li, co; /* #lines and columns on this tty */
+
+ if (get_win_extent(&li, &co) != 0)
+ li = co = -1;
+#endif /* ADJUST_WIN_EXTENT */
+
+ termcap_name = getenv ("TERMCAP");
+ if (termcap_name && *termcap_name == '\0')
+ termcap_name = NULL;
+
+ filep = termcap_name && valid_filename_p (termcap_name);
+
+ /* If termcap_name is non-null and starts with / (in the un*x case, that is),
+ it is a file name to use instead of /etc/termcap.
+ If it is non-null and does not start with /,
+ it is the entry itself, but only if
+ the name the caller requested matches the TERM variable. */
+
+ if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
+ {
+ indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
+ if (!indirect)
+ {
+ if (!bp)
+ {
+ bp = termcap_name;
+#ifdef ADJUST_WIN_EXTENT
+ if (adjust_win_extent(&bp, 1, li, co))
+ malloc_size = 1; /* force return of bp */
+#endif /* ADJUST_WIN_EXTENT */
+ }
+ else
+ {
+ strcpy (bp, termcap_name);
+#ifdef ADJUST_WIN_EXTENT
+ adjust_win_extent(&bp, 0, li, co);
+#endif /* ADJUST_WIN_EXTENT */
+ }
+ goto ret;
+ }
+ else
+ { /* It has tc=. Need to read /etc/termcap. */
+ tcenv = termcap_name;
+ termcap_name = NULL;
+ }
+ }
+
+ if (!termcap_name || !filep)
+#ifdef VMS
+ termcap_name = "emacs_library:[etc]termcap.dat";
+#else
+ termcap_name = "/etc/termcap";
+#endif
+
+ /* Here we know we must search a file and termcap_name has its name. */
+
+ fd = open (termcap_name, 0, 0);
+ if (fd < 0)
+ return -1;
+
+ buf.size = BUFSIZE;
+ /* Add 1 to size to ensure room for terminating null. */
+ buf.beg = (char *) xmalloc (buf.size + 1);
+ term = indirect ? indirect : name;
+
+ if (!bp)
+ {
+ malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
+ bp = (char *) xmalloc (malloc_size);
+ }
+ bp1 = bp;
+
+ if (indirect)
+ /* Copy the data from the environment variable. */
+ {
+ strcpy (bp, tcenv);
+ bp1 += strlen (tcenv);
+ }
+
+ while (term)
+ {
+ /* Scan the file, reading it via buf, till find start of main entry. */
+ if (scan_file (term, fd, &buf) == 0)
+ {
+ close (fd);
+ free (buf.beg);
+ if (malloc_size)
+ free (bp);
+ return 0;
+ }
+
+ /* Free old `term' if appropriate. */
+ if (term != name)
+ free (term);
+
+ /* If BP is malloc'd by us, make sure it is big enough. */
+ if (malloc_size)
+ {
+ malloc_size = bp1 - bp + buf.size;
+ termcap_name = (char *) xrealloc (bp, malloc_size);
+ bp1 += termcap_name - bp;
+ bp = termcap_name;
+ }
+
+ bp2 = bp1;
+
+ /* Copy the line of the entry from buf into bp. */
+ termcap_name = buf.ptr;
+ while ((*bp1++ = c = *termcap_name++) && c != '\n')
+ /* Drop out any \ newline sequence. */
+ if (c == '\\' && *termcap_name == '\n')
+ {
+ bp1--;
+ termcap_name++;
+ }
+ *bp1 = '\0';
+
+ /* Does this entry refer to another terminal type's entry?
+ If something is found, copy it into heap and null-terminate it. */
+ term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
+ }
+
+ close (fd);
+ free (buf.beg);
+
+ if (malloc_size)
+ bp = (char *) xrealloc (bp, bp1 - bp + 1);
+#ifdef ADJUST_WIN_EXTENT
+ adjust_win_extent(&bp, malloc_size ? 2 : 0, li, co);
+#endif /* ADJUST_WIN_EXTENT */
+
+ ret:
+ term_entry = bp;
+ if (malloc_size)
+ return (int) bp;
+ return 1;
+}
+
+/* Given file open on FD and buffer BUFP,
+ scan the file from the beginning until a line is found
+ that starts the entry for terminal type STR.
+ Return 1 if successful, with that line in BUFP,
+ or 0 if no entry is found in the file. */
+
+static int
+scan_file (str, fd, bufp)
+ char *str;
+ int fd;
+ register struct buffer *bufp;
+{
+ register char *end;
+
+ bufp->ptr = bufp->beg;
+ bufp->full = 0;
+ bufp->ateof = 0;
+ *bufp->ptr = '\0';
+
+ lseek (fd, 0L, 0);
+
+ while (!bufp->ateof)
+ {
+ /* Read a line into the buffer. */
+ end = NULL;
+ do
+ {
+ /* if it is continued, append another line to it,
+ until a non-continued line ends. */
+ end = gobble_line (fd, bufp, end);
+ }
+ while (!bufp->ateof && end[-2] == '\\');
+
+ if (*bufp->ptr != '#'
+ && name_match (bufp->ptr, str))
+ return 1;
+
+ /* Discard the line just processed. */
+ bufp->ptr = end;
+ }
+ return 0;
+}
+
+/* Return nonzero if NAME is one of the names specified
+ by termcap entry LINE. */
+
+static int
+name_match (line, name)
+ char *line, *name;
+{
+ register char *tem;
+
+ if (!compare_contin (line, name))
+ return 1;
+ /* This line starts an entry. Is it the right one? */
+ for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
+ if (*tem == '|' && !compare_contin (tem + 1, name))
+ return 1;
+
+ return 0;
+}
+
+static int
+compare_contin (str1, str2)
+ register char *str1, *str2;
+{
+ register int c1, c2;
+ while (1)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ while (c1 == '\\' && *str1 == '\n')
+ {
+ str1++;
+ while ((c1 = *str1++) == ' ' || c1 == '\t');
+ }
+ if (c2 == '\0')
+ {
+ /* End of type being looked up. */
+ if (c1 == '|' || c1 == ':')
+ /* If end of name in data base, we win. */
+ return 0;
+ else
+ return 1;
+ }
+ else if (c1 != c2)
+ return 1;
+ }
+}
+
+/* Make sure that the buffer <- BUFP contains a full line
+ of the file open on FD, starting at the place BUFP->ptr
+ points to. Can read more of the file, discard stuff before
+ BUFP->ptr, or make the buffer bigger.
+
+ Return the pointer to after the newline ending the line,
+ or to the end of the file, if there is no newline to end it.
+
+ Can also merge on continuation lines. If APPEND_END is
+ non-null, it points past the newline of a line that is
+ continued; we add another line onto it and regard the whole
+ thing as one line. The caller decides when a line is continued. */
+
+static char *
+gobble_line (fd, bufp, append_end)
+ int fd;
+ register struct buffer *bufp;
+ char *append_end;
+{
+ register char *end;
+ register int nread;
+ register char *buf = bufp->beg;
+ register char *tem;
+
+ if (!append_end)
+ append_end = bufp->ptr;
+
+ while (1)
+ {
+ end = append_end;
+ while (*end && *end != '\n') end++;
+ if (*end)
+ break;
+ if (bufp->ateof)
+ return buf + bufp->full;
+ if (bufp->ptr == buf)
+ {
+ if (bufp->full == bufp->size)
+ {
+ bufp->size *= 2;
+ /* Add 1 to size to ensure room for terminating null. */
+ tem = (char *) xrealloc (buf, bufp->size + 1);
+ bufp->ptr = (bufp->ptr - buf) + tem;
+ append_end = (append_end - buf) + tem;
+ bufp->beg = buf = tem;
+ }
+ }
+ else
+ {
+ append_end -= bufp->ptr - buf;
+ bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
+ bufp->ptr = buf;
+ }
+ if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
+ bufp->ateof = 1;
+ bufp->full += nread;
+ buf[bufp->full] = '\0';
+ }
+ return end + 1;
+}
+
+#ifdef TEST
+
+#ifdef NULL
+#undef NULL
+#endif
+
+#include <stdio.h>
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *term;
+ char *buf;
+
+ term = argv[1];
+ printf ("TERM: %s\n", term);
+
+ buf = (char *) tgetent (0, term);
+ if ((int) buf <= 0)
+ {
+ printf ("No entry.\n");
+ return 0;
+ }
+
+ printf ("Entry: %s\n", buf);
+
+ tprint ("cm");
+ tprint ("AL");
+
+ printf ("co: %d\n", tgetnum ("co"));
+ printf ("am: %d\n", tgetflag ("am"));
+}
+
+tprint (cap)
+ char *cap;
+{
+ char *x = tgetstr (cap, 0);
+ register char *y;
+
+ printf ("%s: ", cap);
+ if (x)
+ {
+ for (y = x; *y; y++)
+ if (*y <= ' ' || *y == 0177)
+ printf ("\\%0o", *y);
+ else
+ putchar (*y);
+ free (x);
+ }
+ else
+ printf ("none");
+ putchar ('\n');
+}
+
+#endif /* TEST */
+
diff --git a/libc/gtermcap/tparam.c b/libc/gtermcap/tparam.c
new file mode 100644
index 0000000..565946c
--- /dev/null
+++ b/libc/gtermcap/tparam.c
@@ -0,0 +1,330 @@
+/* Merge parameters into a termcap entry string.
+ Copyright (C) 1985, 1987, 1993 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Emacs config.h may rename various library functions such as malloc. */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#else /* not HAVE_CONFIG_H */
+
+#ifdef __linux__
+#undef STDC_HEADERS
+#define STDC_HEADERS
+#define HAVE_UNISTD_H
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <string.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#ifndef NULL
+#define NULL (char *) 0
+#endif
+
+#ifndef emacs
+static void
+memory_out ()
+{
+ write (2, "virtual memory exhausted\n", 25);
+ exit (1);
+}
+
+static char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *tem = malloc (size);
+
+ if (!tem)
+ memory_out ();
+ return tem;
+}
+
+static char *
+xrealloc (ptr, size)
+ char *ptr;
+ unsigned size;
+{
+ register char *tem = realloc (ptr, size);
+
+ if (!tem)
+ memory_out ();
+ return tem;
+}
+#endif /* not emacs */
+
+/* Assuming STRING is the value of a termcap string entry
+ containing `%' constructs to expand parameters,
+ merge in parameter values and store result in block OUTSTRING points to.
+ LEN is the length of OUTSTRING. If more space is needed,
+ a block is allocated with `malloc'.
+
+ The value returned is the address of the resulting string.
+ This may be OUTSTRING or may be the address of a block got with `malloc'.
+ In the latter case, the caller must free the block.
+
+ The fourth and following args to tparam serve as the parameter values. */
+
+static char *tparam1 ();
+
+/* VARARGS 2 */
+char *
+tparam (string, outstring, len, arg0, arg1, arg2, arg3)
+ char *string;
+ char *outstring;
+ int len;
+ int arg0, arg1, arg2, arg3;
+{
+#ifdef NO_ARG_ARRAY
+ int arg[4];
+ arg[0] = arg0;
+ arg[1] = arg1;
+ arg[2] = arg2;
+ arg[3] = arg3;
+ return tparam1 (string, outstring, len, NULL, NULL, arg);
+#else
+ return tparam1 (string, outstring, len, NULL, NULL, &arg0);
+#endif
+}
+
+char *BC;
+char *UP;
+
+static char tgoto_buf[50];
+
+char *
+tgoto (cm, hpos, vpos)
+ char *cm;
+ int hpos, vpos;
+{
+ int args[2];
+ if (!cm)
+ return NULL;
+ args[0] = vpos;
+ args[1] = hpos;
+ return tparam1 (cm, tgoto_buf, 50, UP, BC, args);
+}
+
+static char *
+tparam1 (string, outstring, len, up, left, argp)
+ char *string;
+ char *outstring;
+ int len;
+ char *up, *left;
+ register int *argp;
+{
+ register int c;
+ register char *p = string;
+ register char *op = outstring;
+ char *outend;
+ int outlen = 0;
+
+ register int tem;
+ int *old_argp = argp;
+ int doleft = 0;
+ int doup = 0;
+
+ outend = outstring + len;
+
+ while (1)
+ {
+ /* If the buffer might be too short, make it bigger. */
+ if (op + 5 >= outend)
+ {
+ register char *new;
+ if (outlen == 0)
+ {
+ outlen = len + 40;
+ new = (char *) xmalloc (outlen);
+ outend += 40;
+ bcopy (outstring, new, op - outstring);
+ }
+ else
+ {
+ outend += outlen;
+ outlen *= 2;
+ new = (char *) xrealloc (outstring, outlen);
+ }
+ op += new - outstring;
+ outend += new - outstring;
+ outstring = new;
+ }
+ c = *p++;
+ if (!c)
+ break;
+ if (c == '%')
+ {
+ c = *p++;
+ tem = *argp;
+ switch (c)
+ {
+ case 'd': /* %d means output in decimal. */
+ if (tem < 10)
+ goto onedigit;
+ if (tem < 100)
+ goto twodigit;
+ case '3': /* %3 means output in decimal, 3 digits. */
+ if (tem > 999)
+ {
+ *op++ = tem / 1000 + '0';
+ tem %= 1000;
+ }
+ *op++ = tem / 100 + '0';
+ case '2': /* %2 means output in decimal, 2 digits. */
+ twodigit:
+ tem %= 100;
+ *op++ = tem / 10 + '0';
+ onedigit:
+ *op++ = tem % 10 + '0';
+ argp++;
+ break;
+
+ case 'C':
+ /* For c-100: print quotient of value by 96, if nonzero,
+ then do like %+. */
+ if (tem >= 96)
+ {
+ *op++ = tem / 96;
+ tem %= 96;
+ }
+ case '+': /* %+x means add character code of char x. */
+ tem += *p++;
+ case '.': /* %. means output as character. */
+ if (left)
+ {
+ /* If want to forbid output of 0 and \n and \t,
+ and this is one of them, increment it. */
+ while (tem == 0 || tem == '\n' || tem == '\t')
+ {
+ tem++;
+ if (argp == old_argp)
+ doup++, outend -= strlen (up);
+ else
+ doleft++, outend -= strlen (left);
+ }
+ }
+ *op++ = tem ? tem : 0200;
+ case 'f': /* %f means discard next arg. */
+ argp++;
+ break;
+
+ case 'b': /* %b means back up one arg (and re-use it). */
+ argp--;
+ break;
+
+ case 'r': /* %r means interchange following two args. */
+ argp[0] = argp[1];
+ argp[1] = tem;
+ old_argp++;
+ break;
+
+ case '>': /* %>xy means if arg is > char code of x, */
+ if (argp[0] > *p++) /* then add char code of y to the arg, */
+ argp[0] += *p; /* and in any case don't output. */
+ p++; /* Leave the arg to be output later. */
+ break;
+
+ case 'a': /* %a means arithmetic. */
+ /* Next character says what operation.
+ Add or subtract either a constant or some other arg. */
+ /* First following character is + to add or - to subtract
+ or = to assign. */
+ /* Next following char is 'p' and an arg spec
+ (0100 plus position of that arg relative to this one)
+ or 'c' and a constant stored in a character. */
+ tem = p[2] & 0177;
+ if (p[1] == 'p')
+ tem = argp[tem - 0100];
+ if (p[0] == '-')
+ argp[0] -= tem;
+ else if (p[0] == '+')
+ argp[0] += tem;
+ else if (p[0] == '*')
+ argp[0] *= tem;
+ else if (p[0] == '/')
+ argp[0] /= tem;
+ else
+ argp[0] = tem;
+
+ p += 3;
+ break;
+
+ case 'i': /* %i means add one to arg, */
+ argp[0] ++; /* and leave it to be output later. */
+ argp[1] ++; /* Increment the following arg, too! */
+ break;
+
+ case '%': /* %% means output %; no arg. */
+ goto ordinary;
+
+ case 'n': /* %n means xor each of next two args with 140. */
+ argp[0] ^= 0140;
+ argp[1] ^= 0140;
+ break;
+
+ case 'm': /* %m means xor each of next two args with 177. */
+ argp[0] ^= 0177;
+ argp[1] ^= 0177;
+ break;
+
+ case 'B': /* %B means express arg as BCD char code. */
+ argp[0] += 6 * (tem / 10);
+ break;
+
+ case 'D': /* %D means weird Delta Data transformation. */
+ argp[0] -= 2 * (tem % 16);
+ break;
+ }
+ }
+ else
+ /* Ordinary character in the argument string. */
+ ordinary:
+ *op++ = c;
+ }
+ *op = 0;
+ while (doup-- > 0)
+ strcat (op, up);
+ while (doleft-- > 0)
+ strcat (op, left);
+ return outstring;
+}
+
+#ifdef DEBUG
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char buf[50];
+ int args[3];
+ args[0] = atoi (argv[2]);
+ args[1] = atoi (argv[3]);
+ args[2] = atoi (argv[4]);
+ tparam1 (argv[1], buf, "LEFT", "UP", args);
+ printf ("%s\n", buf);
+ return 0;
+}
+
+#endif /* DEBUG */
diff --git a/libc/gtermcap/version.c b/libc/gtermcap/version.c
new file mode 100644
index 0000000..d4c44bc
--- /dev/null
+++ b/libc/gtermcap/version.c
@@ -0,0 +1,2 @@
+/* Make the library identifiable with the RCS ident command. */
+static char *version_string = "\n$Version: GNU termcap 1.2.2 $\n";
diff --git a/libc/i386fp/Config b/libc/i386fp/Config
new file mode 100644
index 0000000..dac69f0
--- /dev/null
+++ b/libc/i386fp/Config
@@ -0,0 +1 @@
+386fp: Bcc 386 floating point
diff --git a/libc/i386fp/Makefile b/libc/i386fp/Makefile
new file mode 100644
index 0000000..55d06da
--- /dev/null
+++ b/libc/i386fp/Makefile
@@ -0,0 +1,38 @@
+# Makefile for bcc 386 software floating point library
+
+.SUFFIXES: .x # .x files are .s files that need C-preprocessing
+.x.o:
+ cp $< tmp.c
+ $(CC) $(CFLAGS) -E tmp.c >tmp.s
+ $(CC) $(CFLAGS) -c tmp.s -A-n -A$* -o $@
+
+FPDIST =Makefile $(FPSRC) test.c bccfp.tex
+FPSRC =fadd.x fcomp.x fdiv.x fmul.x fbsr.x \
+ fperr.c fperror.x fptoi.x fpushd.x fpulld.x \
+ fpushi.x fpushf.x fpullf.x frexp.x ftst.x \
+ gcclib.x \
+ fabs.x ldexp.x modf.c \
+ fperr.h fplib.h
+FPOBJ =fadd.o fcomp.o fdiv.o fmul.o fpbsr.o \
+ fperr.o fperror.o fptoi.o fpushd.o fpulld.o \
+ fpushi.o fpushf.o fpullf.o frexp.o ftst.o \
+ fabs.o ldexp.o modf.o
+JUNK =tmp tmp.c tmp.s tmp.lst
+LIB =.
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+ifeq ($(LIB_CPU),i386)
+all: $(LIBC)($(FPOBJ))
+ rm -f $(JUNK)
+else
+all:
+ @:
+endif
+
+$(LIBC)($(FPOBJ)): fplib.h
+$(LIBC)(fperr.o fperror.o): fperr.h
+
+clean:
+ rm -f $(FPOBJ) $(JUNK) test
+ rm -f $(LIB)/libfp.a bccfp.tar.Z bccfp.uue
diff --git a/libc/i386fp/bccfp.tex b/libc/i386fp/bccfp.tex
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libc/i386fp/bccfp.tex
diff --git a/libc/i386fp/changes b/libc/i386fp/changes
new file mode 100644
index 0000000..2cc632a
--- /dev/null
+++ b/libc/i386fp/changes
@@ -0,0 +1,30 @@
+fcomp:
+Fixes for negative 0 (perhaps this shouldn't be generated, like denormals
+and infinities (these would cause even more trouble) but Fsub routine or
+something generated one).
+
+frexp.x:
+Deleted 3rd arg (used to return value when bcc wasn't doing it right).
+
+Fixed frexp(value = 0) and ldexp(value = 0) returning nonzero.
+
+Most files:
+Changed comment symbol to '!' for new assembler (not the native ';' in
+case this is ported to ACK someday).
+
+Avoided using ebp and unnecessary register saves.
+
+Changed assembler style to make it a bit more portable or like I do it
+(no '$' for hex, 8[esp] instead of [esp+8], use only .define and not export
+or .globl, use '#' (could use nothing) instead of '*' for immediate).
+The partly-supported 8(ebp) and .globl would be still more portable.
+
+Changed terminology 'mantissa' to 'fraction'.
+
+Round to even. Required for 'paranioa' not to find any defects.
+
+Used preprocessor.
+
+Parametrized most of the magic numbers. Phew!
+
+Supported denormals. Now 'paranioa' doesn't find any flaws.
diff --git a/libc/i386fp/fabs.x b/libc/i386fp/fabs.x
new file mode 100644
index 0000000..fe81676
--- /dev/null
+++ b/libc/i386fp/fabs.x
@@ -0,0 +1,17 @@
+! bcc 386 floating point routines (version 2) -- _fabs
+! author: Bruce Evans
+
+#include "fplib.h"
+
+! double fabs(double value);
+! returns the absolute value of a number
+! this works for all NaNs, like the 80*87 fabs, but perhaps we should check
+! for exceptions that can happen when an 80*87 register is loaded
+
+ .globl _fabs
+ .align ALIGNMENT
+_fabs:
+ mov eax,PC_SIZE+D_LOW[esp]
+ mov edx,PC_SIZE+D_HIGH[esp]
+ and edx,~D_SIGN_MASK
+ ret
diff --git a/libc/i386fp/fadd.x b/libc/i386fp/fadd.x
new file mode 100644
index 0000000..d1e60b1
--- /dev/null
+++ b/libc/i386fp/fadd.x
@@ -0,0 +1,485 @@
+! bcc 386 floating point routines (version 2)
+! -- Fadd, Faddd, Faddf, Fsub, Fsubd, Fsubf, normalize2
+! author: Bruce Evans
+
+#include "fplib.h"
+
+#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE)
+
+ .extern Fpushf
+ .extern fpdenormal
+ .extern fpoverflow
+ .extern fpunderflow
+
+ .globl Fadd
+ .align ALIGNMENT
+Fadd:
+ push ebp
+ push edi
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp]
+ mov edx,FRAME_SIZE+D_HIGH[esp]
+ mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp]
+ mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp]
+ call addition
+ mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret #D_SIZE
+
+ .globl Faddd
+ .align ALIGNMENT
+Faddd:
+ push ebp
+ push edi
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp]
+ mov edx,FRAME_SIZE+D_HIGH[esp]
+ mov ecx,D_HIGH[ebx]
+ mov ebx,D_LOW[ebx]
+ call addition
+ mov FRAME_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+ .globl Faddf
+ .align ALIGNMENT
+Faddf:
+ push ebp
+ push edi
+ push esi
+ call Fpushf
+ pop ebx ! yl
+ pop ecx ! yu
+ mov eax,FRAME_SIZE+D_LOW[esp] ! xl
+ mov edx,FRAME_SIZE+D_HIGH[esp] ! xu
+ call addition
+ mov FRAME_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+ .globl Fsub
+ .align ALIGNMENT
+Fsub:
+ push ebp
+ push edi
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp]
+ mov edx,FRAME_SIZE+D_HIGH[esp]
+ mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp]
+ mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp]
+ xor ecx,#D_SIGN_MASK ! complement sign
+ call addition
+ mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret #D_SIZE
+
+ .globl Fsubd
+ .align ALIGNMENT
+Fsubd:
+ push ebp
+ push edi
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp]
+ mov edx,FRAME_SIZE+D_HIGH[esp]
+ mov ecx,D_HIGH[ebx]
+ mov ebx,D_LOW[ebx]
+ xor ecx,#D_SIGN_MASK ! complement sign
+ call addition
+ mov FRAME_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+ .globl Fsubf
+ .align ALIGNMENT
+Fsubf:
+ push ebp
+ push edi
+ push esi
+ call Fpushf
+ pop ebx ! yl
+ pop ecx ! yu
+ mov eax,FRAME_SIZE+D_LOW[esp] ! xl
+ mov edx,FRAME_SIZE+D_HIGH[esp] ! xu
+ xor ecx,#D_SIGN_MASK ! complement sign
+ call addition
+ mov FRAME_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+ .align ALIGNMENT
+exp_y_0:
+
+! Check for x denormal, to split off special case where both are denormal,
+! so the norm bit (or 1 higher) is known to be set for addition, so addition
+! can be done faster
+
+ test esi,#D_EXP_MASK
+ jnz x_normal_exp_y_0
+ test esi,esi ! test top bits of x fraction
+ jnz both_denorm ! denormal iff nonzero fraction with zero exp
+ test eax,eax ! test rest of fraction
+ jz return_edx_eax ! everything 0 (XXX - do signs matter?)
+both_denorm:
+ call fpdenormal
+ test ebp,#D_SIGN_MASK
+ jnz denorm_subtract
+
+! Add denormal x to denormal or zero y
+
+#if D_NORM_BIT != D_EXP_SHIFT
+#include "error, carry into norm bit does not go into exponent"
+#endif
+
+ add eax,ebx
+ adc esi,edi
+ or edx,esi
+ ret
+
+denorm_subtract:
+ sub eax,ebx
+ sbb esi,edi
+ or edx,esi
+ ret
+
+ .align ALIGNMENT
+x_normal_exp_y_0:
+ test edi,edi ! this is like the check for x denormal
+ jnz y_denorm
+ test ebx,ebx
+ jz return_edx_eax ! y = 0
+y_denorm:
+ call fpdenormal
+ or ecx,#1 << D_EXP_SHIFT ! normalize y by setting exponent to 1
+ jmp got_y
+
+ .align ALIGNMENT
+return_edx_eax:
+ ret
+
+ .align ALIGNMENT
+add_bigshift:
+ cmp ecx,#D_FRAC_BIT+2
+ jae return_edx_eax ! x dominates y
+ sub ecx,#REG_BIT
+ shrd ebp,ebx,cl
+ shrd ebx,edi,cl
+ shr edi,cl
+ add eax,edi
+ adc esi,#0
+ xchg ebp,ebx
+ br normalize
+
+ .align ALIGNMENT
+addition:
+ mov esi,edx ! this mainly for consistent naming
+ and esi,#D_EXP_MASK | D_FRAC_MASK ! discard sign so comparison is simple
+ mov edi,ecx ! free cl for shifts
+ and edi,#D_EXP_MASK | D_FRAC_MASK
+ cmp esi,edi
+ ja xbigger
+ jb swap
+ cmp eax,ebx
+ jae xbigger
+swap:
+ xchg edx,ecx
+ xchg eax,ebx
+ xchg esi,edi
+xbigger:
+
+! edx holds sign of result from here on
+! and exponent of result before the normalization step
+
+ mov ebp,edx ! prepare difference of signs
+ xor ebp,ecx
+
+ and ecx,#D_EXP_MASK ! extract exp_y and check for y 0 or denormal
+ beq exp_y_0 ! otherwise x is not 0 or denormal either
+ and edi,#D_FRAC_MASK ! extract fraction
+ or edi,#D_NORM_MASK ! normalize
+got_y:
+ and esi,#D_FRAC_MASK ! extract fraction
+ or esi,#D_NORM_MASK ! normalize
+
+ sub ecx,edx ! carries from non-exp bits in edx killed later
+ neg ecx
+ and ecx,#D_EXP_MASK
+ shr ecx,#D_EXP_SHIFT ! difference of exponents
+
+got_x_and_y:
+ and ebp,#D_SIGN_MASK ! see if signs are same
+ bne subtract ! else roundoff reg ebp has been cleared
+
+ cmp cl,#REG_BIT
+ bhis add_bigshift
+ shrd ebp,ebx,cl
+ shrd ebx,edi,cl
+ shr edi,cl
+ add eax,ebx
+ adc esi,edi
+
+! result edx(D_SIGN_MASK | D_EXP_MASK bits):esi:eax:ebp but needs normalization
+
+ mov edi,edx
+ and edi,#D_EXP_MASK
+ test esi,#D_NORM_MASK << 1
+ jnz add_loverflow
+
+add_round:
+ cmp ebp,#1 << (REG_BIT-1) ! test roundoff register
+ jb add_done ! no rounding
+ jz tie
+add_roundup:
+ add eax,#1
+ adc esi,#0
+ test esi,#D_NORM_MASK << 1
+ jnz pre_add_loverflow ! rounding may cause overflow!
+add_done:
+ mov ecx,edx ! duplicated code from 'done'
+ and edx,#D_SIGN_MASK
+ or edx,edi
+ and esi,#D_FRAC_MASK
+ or edx,esi
+ ret
+
+ .align ALIGNMENT
+tie:
+ test al,#1 ! tie case, round to even
+ jz add_done ! even, no rounding
+ jmp add_roundup
+
+ .align ALIGNMENT
+pre_add_loverflow:
+ sub ebp,ebp ! clear rounding register
+ ! probably avoiding tests for more rounding
+add_loverflow:
+ shrd ebp,eax,#1
+ jnc over_set_sticky_bit
+ or ebp,#1
+over_set_sticky_bit:
+ shrd eax,esi,#1
+ shr esi,#1
+ add edi,1 << D_EXP_SHIFT
+ cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT
+ jl add_round
+overflow:
+ call fpoverflow
+ mov eax,ecx ! XXX - wrong reg
+ ret
+
+! result edx(D_SIGN_MASK | D_EXP_MASK bits):
+! esi((D_NORM_MASK << 1) | D_NORM_MASK | D_FRAC_MASK bits):eax:ebp:ebx
+! but needs normalization
+
+ .align ALIGNMENT
+normalize:
+ mov edi,edx
+ and edi,#D_EXP_MASK
+ test esi,#D_NORM_MASK << 1
+ bne loverflow
+
+! result edx(D_SIGN_MASK bit):edi(D_EXP_MASK bits):
+! esi(D_NORM_MASK | D_FRAC_MASK bits):eax:ebp:ebx
+! but needs normalization
+
+ .globl normalize2
+normalize2:
+ test esi,#D_NORM_MASK ! already-normalized is very common
+ jz normalize3
+round:
+ cmp ebp,#1 << (REG_BIT-1) ! test roundoff register
+ jb done ! no rounding
+ jz near_tie
+roundup:
+ add eax,#1
+ adc esi,#0
+ test esi,#D_NORM_MASK << 1
+ bne pre_loverflow ! rounding may cause overflow!
+done:
+cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT
+jae overflow
+ and edx,#D_SIGN_MASK ! extract sign of largest and result
+ or edx,edi ! include exponent with sign
+ and esi,#D_FRAC_MASK ! discard norm bit
+ or edx,esi ! include fraction with sign and exponent
+ ret
+
+ .align ALIGNMENT
+near_tie:
+ test ebx,ebx
+ jnz roundup
+ test al,#1 ! tie case, round to even
+ jz done ! even, no rounding
+ jmp roundup
+
+ .align ALIGNMENT
+not_in_8_below:
+ shld ecx,esi,#REG_BIT-D_NORM_BIT+16 ! in 9 to 16 below?
+ jz not_in_16_below ! must be way below (17-20 for usual D_NORM_BIT)
+ mov cl,bsr_table[ecx] ! bsr(esi) - (D_NORM_BIT-16)
+ neg ecx ! (D_NORM_BIT-16) - bsr(esi)
+ add ecx,#16
+ jmp got_shift
+
+ .align ALIGNMENT
+not_in_16_below:
+ mov cl,bsr_table[esi] ! bsr(esi) directly
+ neg ecx ! -bsr(esi)
+ add ecx,#D_NORM_BIT ! D_NORM_BIT - bsr(esi)
+ jmp got_shift
+
+ .align ALIGNMENT
+normalize3:
+ test esi,esi
+ jz shift32
+
+! Find first nonzero bit in esi
+! Don't use bsr, it is very slow (const + 3 * bit_found)
+! We know that there is some nonzero bit, and the norm bit and above are clear
+
+ sub ecx,ecx ! prepare unsigned extension of cl
+ shld ecx,esi,#REG_BIT-D_NORM_BIT+8 ! any bits in 8 below norm bit?
+ jz not_in_8_below
+ mov cl,bsr_table[ecx] ! bsr(esi) - (D_NORM_BIT-8)
+ neg ecx ! (D_NORM_BIT-8) - bsr(esi)
+ add ecx,#8 ! D_NORM_BIT - bsr(esi)
+got_shift:
+ shld esi,eax,cl
+ shld eax,ebp,cl
+ shld ebp,ebx,cl
+ shl ebx,cl
+ shl ecx,D_EXP_SHIFT
+ sub edi,ecx
+ bhi round ! XXX - can rounding change the exponent to > 0?
+ ! not bgt since edi may be 0x80000000
+ neg edi
+ shr edi,#D_EXP_SHIFT
+ inc edi
+ br fpunderflow
+
+ .align ALIGNMENT
+pre_loverflow:
+ sub ebp,ebp ! clear rounding registers
+ sub ebx,ebx ! probably avoiding tests for more rounding
+
+loverflow:
+ shr esi,#1 ! carry bit stayed in the reg
+ rcr eax,#1
+ rcr ebp,#1
+ rcr ebx,#1
+ add edi,1 << D_EXP_SHIFT
+ cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT
+ blt round
+ call fpoverflow
+ mov eax,ecx ! XXX - wrong reg
+ ret
+
+ .align ALIGNMENT
+shift32:
+ test eax,eax
+ jz shift64
+ mov esi,eax
+ mov eax,ebp
+ mov ebp,ebx
+ sub ebx,ebx
+ sub edi,#REG_BIT << D_EXP_SHIFT
+shiftxx:
+ test esi,#~(D_NORM_MASK | D_FRAC_MASK)
+ jz over_adjust ! else too big already
+ shrd ebx,ebp,#D_BIT-D_FRAC_BIT
+ shrd ebp,eax,#D_BIT-D_FRAC_BIT
+ shrd eax,esi,#D_BIT-D_FRAC_BIT
+ shr esi,#D_BIT-D_FRAC_BIT
+ add edi,#(D_BIT-D_FRAC_BIT) << D_EXP_SHIFT
+over_adjust:
+ test edi,edi
+ bgt normalize2
+ neg edi
+ shr edi,#D_EXP_SHIFT
+ inc edi
+ br fpunderflow
+
+ .align ALIGNMENT
+shift64:
+ test ebp,ebp
+ jz shift96
+ mov esi,ebp
+ mov eax,ebx
+ sub ebp,ebp
+ mov ebx,ebp
+ sub edi,#(2*REG_BIT) << D_EXP_SHIFT
+ jmp shiftxx
+
+ .align ALIGNMENT
+shift96:
+ test ebx,ebx ! XXX - this test is probably unnecessary
+ ! since the shift must be small unless we
+ ! are subtracting 2 almost-equal numbers,
+ ! and then the bits beyond 64 will mostly
+ ! be 0
+ jz return_esi_eax ! all zero
+ mov esi,ebx
+ sub ebx,ebx
+ sub edi,#(3*REG_BIT) << D_EXP_SHIFT
+ jmp shiftxx
+
+ .align ALIGNMENT
+return_esi_eax:
+ mov edx,esi
+ ret
+
+ .align ALIGNMENT
+subtract:
+ sub ebp,ebp ! set up roundoff register
+ cmp ecx,#REG_BIT
+ jae subtract_bigshift
+ shrd ebp,ebx,cl
+ shrd ebx,edi,cl
+ shr edi,cl
+ neg ebp ! begin subtraction esi:eax:0 - edi:ebx:ebp
+ sbb eax,ebx
+ sbb esi,edi
+ sub ebx,ebx
+ mov edi,edx
+ and edi,#D_EXP_MASK
+ br normalize2
+
+ .align ALIGNMENT
+subtract_bigshift:
+ cmp ecx,#D_FRAC_BIT+2
+ bhis return_edx_eax ! x dominates y
+ sub ecx,#REG_BIT
+ shrd ebp,ebx,cl
+ shrd ebx,edi,cl
+ shr edi,cl
+ not ebp ! begin subtraction esi:eax:0:0 - 0:edi:ebx:ebp
+ not ebx
+ add ebp,#1
+ adc ebx,#0
+ cmc
+ sbb eax,edi
+ sbb esi,#0
+ xchg ebp,ebx
+ mov edi,edx
+ and edi,#D_EXP_MASK
+ br normalize2
+
+ .data
+ .extern bsr_table
diff --git a/libc/i386fp/fcomp.x b/libc/i386fp/fcomp.x
new file mode 100644
index 0000000..71148ab
--- /dev/null
+++ b/libc/i386fp/fcomp.x
@@ -0,0 +1,89 @@
+! bcc 386 floating point routines (version 2) -- Fcomp, Fcompd, Fcompf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern Fpushf
+
+! Pop 2 doubles from stack and compare them, return result in flags so
+! normal signed branches work (unlike 80x87 which returns the result in
+! the zero and carry flags).
+
+ .globl Fcomp
+ .align ALIGNMENT
+Fcomp:
+ pop ecx ! get return address
+ pop eax ! xl
+ pop edx ! xu
+ push ecx ! put back ret address - pop 2nd double later
+
+! All this popping is bad on 486's since plain mov takes 1+ cycle and pop
+! takes 4 cycles. But this code is designed for 386's where popping is
+! nominally the same speed and saves code space and so maybe instruction
+! fetch time as well as the instruction to adjust the stack (ret #n takes
+! no longer than plain ret but inhibits gotos).
+
+ mov ebx,PC_SIZE+D_LOW[esp] ! yl
+ mov ecx,PC_SIZE+D_HIGH[esp] ! yu
+ jmp compare
+
+! Pop double from stack and compare with double at [ebx]
+
+ .globl Fcompd
+ .align ALIGNMENT
+Fcompd:
+ mov eax,PC_SIZE+D_LOW[esp] ! xl
+ mov edx,PC_SIZE+D_HIGH[esp] ! xu
+ mov ecx,D_HIGH[ebx] ! yu
+ mov ebx,D_LOW[ebx] ! yl
+
+compare:
+ test edx,#D_SIGN_MASK ! is x >= 0?
+ jz cmp0 ! yes; just compare x and y
+ test ecx,#D_SIGN_MASK ! no; but is y >= 0?
+ jz cmp0 ! yes; just compare x and y
+
+ xchg edx,ecx ! x, y < 0, so ...
+ xchg eax,ebx ! ... swap x and y ...
+ xor edx,#D_SIGN_MASK ! ... and toggle signs
+ xor ecx,#D_SIGN_MASK
+
+cmp0:
+ cmp edx,ecx ! compare upper dwords
+ jnz checkneg0 ! if upper dwords differ, job is almost done
+ mov edx,eax ! upper dwords equal, so ...
+ mov ecx,ebx ! ... must make unsigned comparison of lower dwords
+ shr edx,#1 ! shift past sign
+ shr ecx,#1
+ cmp edx,ecx ! compare top 31 bits of lower dwords
+ jnz return ! if these differ, job is done
+ and eax,#1 ! compare lowest bits
+ and ebx,#1
+ cmp eax,ebx
+
+return:
+ ret #D_SIZE ! return, popping 1 double from stack
+
+checkneg0:
+ test edx,#D_EXP_MASK | D_FRAC_MASK ! check to catch unusual case ...
+ jnz recheck
+ test eax,eax
+ jnz recheck
+ test ecx,#D_EXP_MASK | D_FRAC_MASK
+ jnz recheck
+ test ebx,ebx
+ jz return ! ... both are (+-) zero, return 'z'
+
+recheck:
+ cmp edx,ecx ! the upper words were really different
+ ret #D_SIZE
+
+ .globl Fcompf
+ .align ALIGNMENT
+Fcompf:
+ call Fpushf
+ pop ebx ! yl
+ pop ecx ! yu
+ mov eax,PC_SIZE+D_LOW[esp] ! xl
+ mov edx,PC_SIZE+D_HIGH[esp] ! xu
+ jmp compare
diff --git a/libc/i386fp/fdiv.x b/libc/i386fp/fdiv.x
new file mode 100644
index 0000000..4a5cf74
--- /dev/null
+++ b/libc/i386fp/fdiv.x
@@ -0,0 +1,312 @@
+#define EF_SIZE 4
+
+! bcc 386 floating point routines (version 2) -- Fdiv, Fdivd, Fdivf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE)
+
+ .extern Fpushf
+ .extern fpdivzero
+ .extern fpoverflow
+ .extern fpunderflow
+
+! double Fdiv(double x, double y) returns x / y
+
+! pop 2 doubles from stack, divide first by second, and push quotient on stack
+
+! we denote upper and lower dwords of x and y (or their fractions)
+! by (xu,xl), (yu,yl)
+
+ .globl Fdivf
+ .align ALIGNMENT
+Fdivf:
+ sub esp,#D_SIZE ! make space for dummy double on stack
+ push ebp
+ push edi ! save some regs
+ push esi
+ mov eax,FRAME_SIZE-PC_SIZE+D_SIZE[esp] ! move return address ...
+ mov FRAME_SIZE-PC_SIZE[esp],eax ! ... to usual spot
+ call Fpushf
+ pop esi ! yl
+ pop edi ! yu
+ mov eax,FRAME_SIZE+D_SIZE+D_LOW[esp] ! xl
+ mov edx,FRAME_SIZE+D_SIZE+D_HIGH[esp] ! xu
+ jmp division
+
+ .globl Fdiv
+ .align ALIGNMENT
+Fdiv:
+ push ebp
+ push edi ! save some regs
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp] ! xl
+ mov edx,FRAME_SIZE+D_HIGH[esp] ! xu
+ mov esi,FRAME_SIZE+D_SIZE+D_LOW[esp] ! yl
+ mov edi,FRAME_SIZE+D_SIZE+D_HIGH[esp] ! yu
+ jmp division
+
+ .align ALIGNMENT
+exp_y_0:
+ mov ebx,edi
+ or ebx,esi
+ beq zerodivide
+ mov ebx,#1
+fix_y:
+ test edi,edi ! XXX - sloow
+ js y_unpacked
+ shld edi,esi,#1
+ shl esi,#1
+ dec bx
+ jmp fix_y
+
+ .align ALIGNMENT
+exp_x_0:
+ mov ecx,edx
+ or ecx,eax
+ beq retz
+ mov ecx,#1 ! change exponent from 0 to 1
+fix_x:
+ test edx,#1 << (REG_BIT-1-2) ! XXX - sloow
+ jnz x_unpacked
+ shld edx,eax,#1
+ shl eax,#1
+ dec cx
+ jmp fix_x
+
+! Fdivd pops double from stack, divides it by double at [ebx],
+! and pushes quotient back on stack
+
+ .globl Fdivd
+ .align ALIGNMENT
+Fdivd:
+ sub esp,#D_SIZE ! make space for dummy double on stack
+ push ebp
+ push edi ! save some regs
+ push esi
+ mov eax,FRAME_SIZE-PC_SIZE+D_SIZE[esp] ! move return address ...
+ mov FRAME_SIZE-PC_SIZE[esp],eax ! ... to usual spot
+ mov eax,FRAME_SIZE+D_SIZE+D_LOW[esp] ! xl
+ mov edx,FRAME_SIZE+D_SIZE+D_HIGH[esp] ! xu
+ mov esi,D_LOW[ebx] ! yl
+ mov edi,D_HIGH[ebx] ! yu
+
+division:
+
+! The full calculations are
+
+! (xu,xl,0) = yu * (zu,zl) + (0,r,0) (normal 96/32 -> 64 bit division)
+! yl * zu = yu * q1 + r1 (32*32 -> 64 bit mul and 64/32 -> 32 bit div)
+
+! so
+
+! (xu,xl,0,0) = (yu,yl) * (zu,zl-q1) + (0,0,r-r1,yl*(q1-zl))
+
+! where the calculations zl-q1, r-r1 and yl*(q1-zl) are more complicated
+! than the notation suggests. They may be negative and the one with the
+! multiplication may not fit in 32 bits and in both cases the overflow
+! has to be moved into higher bit positions.
+
+! See Knuth for why (zu,zl-q1) is the correct 64-bit quotient to within
+! 1 bit either way (assuming the normalization x < 2 * y).
+
+! We only need to calculate the remainder (0,0,r-r1,yl*(q1-zl)) to resolve
+! tie cases. It tells whether the approximate quotient is too high or too
+! low.
+
+#define NTEMPS 5
+
+ sub esp,#NTEMPS*GENREG_SIZE ! space to remember values for rounding of tie case
+
+! Offsets from esp for these values (offsets using FRAME_SIZE are invalid
+! while these temps are active)
+r = 0
+q1 = 4
+r1 = 8
+yl = 12
+zl = 16
+
+! Step 1: unpack and normalize x to fraction in edx:eax (left shifted as
+! far as possible less 2 so that x < y, and later z < y); unpack and normalize
+! y to a fraction in edi:esi (left shifted as far as possible), put difference
+! of signs (= sign of quotient) in ecx(D_SIGN_MASK) and difference of exponents
+! (= exponent of quotient before normalization) in cx.
+
+ mov ebp,edx ! xu
+ xor ebp,edi ! xu ^ yu
+ and ebp,#D_SIGN_MASK ! sign of result is difference of signs
+
+! Unpack y first to trap 0 / 0
+
+ mov ebx,edi ! remember yu for exponent of y
+ shld edi,esi,#D_BIT-D_FRAC_BIT ! extract fraction of y ...
+ shl esi,#D_BIT-D_FRAC_BIT
+ and ebx,#D_EXP_MASK ! exponent of y
+ jz exp_y_0
+ shr ebx,#D_EXP_SHIFT ! in ebx (actually in bx, with high bits 0)
+ or edi,#D_NORM_MASK << (D_BIT-D_FRAC_BIT) ! normalize
+y_unpacked:
+
+! Unpack x
+
+ mov ecx,edx ! remember xu for exponent of x
+ shld edx,eax,#D_BIT-D_FRAC_BIT-2 ! extract fraction of x ...
+ shl eax,#D_BIT-D_FRAC_BIT-2
+ and edx,#(D_NORM_MASK << (D_BIT-D_FRAC_BIT-2+1))-1
+ ! XXX - above may be shifted 1 extra unnecessarily
+ and ecx,#D_EXP_MASK ! exponent of x
+ jz exp_x_0
+ shr ecx,#D_EXP_SHIFT ! in ecx (actually in cx, with high bits 0)
+ or edx,#D_NORM_MASK << (D_BIT-D_FRAC_BIT-2) ! normalize
+x_unpacked:
+
+ sub cx,bx ! not ecx,ebx because we want to use high bit for sign
+ add cx,#D_EXP_BIAS ! adjust exponent of quotient
+
+ or ecx,ebp ! include sign with exponent
+
+! Step 2: quotient of fractions -> (edx,eax)
+
+! 2a: (xu,xl,0) div yu = (zu,zl) -> (ebx,esi)
+
+ div eax,edi ! (xu,xl) div yu = zu in eax; remainder (rem) in edx
+ mov ebx,eax ! save zu in ebx
+ sub eax,eax ! clear eax: (edx,eax) = (rem,0)
+ div eax,edi ! (rem,0) div yu = zl in eax
+ mov r[esp],edx
+ mov zl[esp],eax
+ xchg eax,esi ! store zl in esi; save yl in eax
+ mov yl[esp],eax
+
+! 2b: (yl * zu) div yu -> (0,eax)
+
+ mul eax,ebx ! yl * zu -> (edx,eax)
+ div eax,edi ! (yl * zu) div yu in eax
+ mov q1[esp],eax
+ mov r1[esp],edx
+
+! 2c: (xu,xl) / (yu,yl) = (zu,zl) - (yl * zu) div yu -> (edx,eax)
+
+ mov edx,ebx ! zu
+ xchg eax,esi ! eax <- zl; esi <- (yl * zu) div yu
+ sub eax,esi
+ sbb edx,#0
+
+! Step 3: normalise quotient
+
+ test edx,#1 << (REG_BIT-2) ! is fraction too small? (can only be by 1 bit)
+ jnz div4
+ shld edx,eax,#1 ! yes; multiply fraction ...
+ shl eax,#1 ! ... by 2 ...
+ dec cx ! ... and decrement exponent
+
+! Step 4: shift and round
+
+div4:
+ mov ebx,eax ! save for rounding
+ shrd eax,edx,#D_BIT-D_FRAC_BIT-1 ! shift fraction of result ...
+ shr edx,#D_BIT-D_FRAC_BIT-1 ! ... to proper position
+ and ebx,#(1 << (D_BIT-D_FRAC_BIT-1))-1 ! look at bits shifted out
+ cmp ebx,#D_NORM_MASK >> (D_BIT-D_FRAC_BIT) ! compare with middle value
+ jb div5 ! below middle, don't round up
+ ja roundup ! above middle, round up
+
+! The low bits don't contain enough information to resolve the tie case,
+! because the quotient itself is only an approximation.
+! Calculate the exact remainder.
+! This case is not very common, so don't worry much about speed.
+! Unfortunately we had to save extra in all cases to prepare for it.
+
+ push edx
+ push eax
+
+ sub esi,esi ! the calculation requires 33 bits - carry to here
+ mov eax,2*GENREG_SIZE+q1[esp]
+ sub eax,2*GENREG_SIZE+zl[esp]
+ pushfd
+ mul dword EF_SIZE+2*GENREG_SIZE+yl[esp]
+ popfd
+ jnc foo
+ sub edx,2*GENREG_SIZE+yl[esp]
+ sbb esi,#0
+foo:
+ add edx,2*GENREG_SIZE+r[esp]
+ adc esi,#0
+ sub edx,2*GENREG_SIZE+r1[esp]
+ sbb esi,#0
+ mov ebx,eax
+ mov edi,edx
+
+ pop eax
+ pop edx
+
+! Can finally decide rounding of tie case
+
+ js div5 ! remainder < 0 from looking at top 64 bits
+ jnz roundup ! remainder > 0 from looking at top 64 bits
+ or edi,ebx ! test bottom 64 bits
+ jnz roundup ! remainder > 0
+
+ test al,#1 ! at last we know it is the tie case, check parity bit
+ jz div5 ! already even, otherwise round up to make even
+
+roundup:
+ add eax,#1 ! add rounding bit
+ adc edx,#0
+ test edx,#D_NORM_MASK << 1 ! has fraction overflowed (very unlikely)
+ jz div5
+! Why were the shifts commented out?
+ shrd eax,edx,#1 ! yes, divide fraction ...
+ shr edx,#1 ! ... by 2 ...
+ inc cx ! ... and increment exponent
+
+! Step 5: put it all together
+
+div5:
+ mov ebx,ecx ! extract sign
+ and ebx,D_SIGN_MASK
+ cmp cx,#D_EXP_INFINITE ! is exponent too big?
+ jge overflow
+ test cx,cx
+ jle underflow
+ shl ecx,#D_EXP_SHIFT
+
+ and edx,#D_FRAC_MASK ! remove norm bit
+ or edx,ecx ! include exponent ...
+ or edx,ebx ! ... and sign
+
+return:
+ add esp,#NTEMPS*GENREG_SIZE ! reclaim temp space
+ mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax ! "push" lower dword of product ...
+ mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx ! ... and upper dword
+ pop esi ! restore registers
+ pop edi
+ pop ebp
+ ret #D_SIZE
+
+retz:
+ sub edx,edx ! clear upper dword
+ sub eax,eax ! ... and lower dword
+ jmp return
+
+overflow:
+ mov edx,ecx ! put sign in usual reg
+ call fpoverflow
+ mov eax,ecx ! XXX - wrong reg
+ jmp return
+
+underflow:
+ mov esi,edx ! put upper part of fraction in usual reg
+ mov edx,ecx ! sign
+ movsx edi,cx ! put shift in usual reg
+ neg edi
+ inc edi
+ call fpunderflow
+ jmp return
+
+zerodivide:
+ mov edx,ebp ! sign
+ call fpdivzero
+ mov eax,ecx ! XXX - wrong reg
+ jmp return
diff --git a/libc/i386fp/fmul.x b/libc/i386fp/fmul.x
new file mode 100644
index 0000000..aa62b5c
--- /dev/null
+++ b/libc/i386fp/fmul.x
@@ -0,0 +1,150 @@
+! bcc 386 floating point routines (version 2) -- Fmul, Fmuld, Fmulf
+! author: Bruce Evans
+
+#include "fplib.h"
+
+#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE)
+
+ .extern Fpushf
+ .extern fpoverflow
+ .extern fpunderflow
+ .extern normalize2
+
+ .globl Fmul
+ .align ALIGNMENT
+Fmul:
+ push ebp
+ push edi
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp]
+ mov edx,FRAME_SIZE+D_HIGH[esp]
+ mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp]
+ mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp]
+ call multiplication
+ mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret #D_SIZE
+
+ .globl Fmuld
+ .align ALIGNMENT
+Fmuld:
+ push ebp
+ push edi
+ push esi
+ mov eax,FRAME_SIZE+D_LOW[esp]
+ mov edx,FRAME_SIZE+D_HIGH[esp]
+ mov ecx,D_HIGH[ebx]
+ mov ebx,D_LOW[ebx]
+ call multiplication
+ mov FRAME_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+ .globl Fmulf
+ .align ALIGNMENT
+Fmulf:
+ push ebp
+ push edi
+ push esi
+ call Fpushf
+ pop ebx ! yl
+ pop ecx ! xu
+ mov eax,FRAME_SIZE+D_LOW[esp] ! xl
+ mov edx,FRAME_SIZE+D_HIGH[esp] ! xu
+ call multiplication
+ mov FRAME_SIZE+D_LOW[esp],eax
+ mov FRAME_SIZE+D_HIGH[esp],edx
+ pop esi
+ pop edi
+ pop ebp
+ ret
+
+ .align ALIGNMENT
+exp_x_0:
+ mov edx,#1 << D_EXP_SHIFT ! change exponent from 0 to 1
+ jmp x_unpacked ! XXX - check for denormal?
+
+ .align ALIGNMENT
+exp_y_0:
+ mov ecx,#1 << D_EXP_SHIFT
+ jmp y_unpacked
+
+ .align ALIGNMENT
+multiplication:
+ mov ebp,edx ! xu
+ xor ebp,ecx ! xu ^ yu
+ and ebp,#D_SIGN_MASK ! sign of result is difference of signs
+
+ mov esi,edx ! free edx for multiplications
+ and esi,#D_FRAC_MASK ! discard sign and exponent
+ and edx,#D_EXP_MASK ! exponent(x)
+ jz exp_x_0
+ or esi,#D_NORM_MASK ! normalize
+x_unpacked:
+
+ mov edi,ecx ! this mainly for consistent naming
+ and edi,#D_FRAC_MASK
+ and ecx,#D_EXP_MASK ! exponent(y)
+ jz exp_y_0
+ or edi,#D_NORM_MASK
+y_unpacked:
+
+ add ecx,edx ! add exponents
+
+! exponent is in ecx, sign in ebp, operands in esi:eax and edi:ebx, edx is free
+! product to go in esi:eax:ebp:ebx
+! terminology: x * y = (xu,xl) * (yu,yl)
+! = (xu * yu,0,0) + (0,xu * yl + xl * yu,0) + (0,0,xl * yl)
+
+ push ecx
+ push ebp
+ mov ecx,eax
+ mul ebx ! xl * yl
+ mov ebp,edx ! (xl * yl).u in ebp
+ xchg ebx,eax ! (xl * yl).l in ebx (final), yl in eax
+ mul esi ! xu * yl
+ push eax ! (xu * yl).l on stack
+ push edx ! (xu * yl).u on stack
+ mov eax,esi ! xu
+ mul edi ! xu * yu
+ mov esi,edx ! (xu * yu).u in esi (final except carries)
+ xchg ecx,eax ! (xu * yu).l in ecx, xl in eax
+ mul edi ! xl * yu
+
+ add ebp,eax ! (xl * yl).u + (xl * yu).l
+ pop eax ! (xu * yl).u
+ adc eax,edx ! (xu * yl).u + (xl * yu).u
+ adc esi,#0
+ pop edx ! (xu * yl).l
+ add ebp,edx ! ((xl * yl).u + (xl * yu).l) + (xu * yl).l
+ adc eax,ecx ! ((xu * yl).u + (xl * yu).u) + (xu * yu).l
+ adc esi,#0
+ pop edx ! sign
+ pop edi ! exponent
+ sub edi,#(D_EXP_BIAS+1-(D_EXP_BIT+2)) << D_EXP_SHIFT ! adjust
+! cmp edi,#(D_EXP_INFINITE-1+(D_EXP_BIT+2)) << D_EXP_SHIFT
+! jae outofbounds ! 0 will be caught as underflow by normalize2
+cmp edi,#(2*D_EXP_INFINITE-(D_EXP_BIAS+1)+(D_EXP_BIT+2)) << D_EXP_SHIFT
+ja underflow
+ br normalize2
+
+ .align ALIGNMENT
+overflow:
+ mov edx,ebp ! put sign in usual reg
+ call fpoverflow
+ mov eax,ecx ! XXX - wrong reg
+ ret
+
+ .align ALIGNMENT
+underflow:
+ mov edx,ebp ! put sign in usual reg
+ neg edi
+ shr edi,#D_EXP_SHIFT
+ inc edi
+ br fpunderflow
diff --git a/libc/i386fp/fpbsr.x b/libc/i386fp/fpbsr.x
new file mode 100644
index 0000000..8ff38d7
--- /dev/null
+++ b/libc/i386fp/fpbsr.x
@@ -0,0 +1,25 @@
+! bcc 386 floating point routines (version 2) -- bsr_table
+! author: Bruce Evans
+
+#include "fplib.h"
+
+ .globl bsr_table
+ .data
+ .align ALIGNMENT
+bsr_table: ! table to replace bsr on range 0-255
+.byte -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
+.byte 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+.byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+.byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
diff --git a/libc/i386fp/fperr.c b/libc/i386fp/fperr.c
new file mode 100644
index 0000000..fa1633e
--- /dev/null
+++ b/libc/i386fp/fperr.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <signal.h>
+
+#include "fperr.h"
+
+void fperr(errno)
+int errno;
+{
+
+#if defined(DEBUG) || 0
+ switch(errno) {
+
+ case EFDENORMAL:
+ fputs("\nDenormal - ", stderr);
+ break;
+
+ case EFINFINITY:
+ fputs("\nInfinity - ", stderr);
+ break;
+
+ case EFNAN:
+ fputs("\nNaN - ", stderr);
+ break;
+
+ case EFOVERFLOW:
+ fputs("\nOverflow - ", stderr);
+ break;
+
+ case EFUNDERFLOW:
+ fputs("\nUnderflow - ", stderr);
+ break;
+
+ case EFDIVZERO:
+ fputs("\nZero divide - ", stderr);
+ break;
+
+ default:
+ fprintf(stderr, "\nUnknown error 0x%x - ", errno);
+ }
+ fflush(stderr);
+#endif
+
+ kill(getpid(), SIGFPE);
+}
diff --git a/libc/i386fp/fperr.h b/libc/i386fp/fperr.h
new file mode 100644
index 0000000..f2a2a7d
--- /dev/null
+++ b/libc/i386fp/fperr.h
@@ -0,0 +1,8 @@
+/* fperr.h */
+
+#define EFDENORMAL 1
+#define EFINFINITY 2
+#define EFNAN 3
+#define EFOVERFLOW 4
+#define EFUNDERFLOW 5
+#define EFDIVZERO 6
diff --git a/libc/i386fp/fperror.x b/libc/i386fp/fperror.x
new file mode 100644
index 0000000..04f3f74
--- /dev/null
+++ b/libc/i386fp/fperror.x
@@ -0,0 +1,126 @@
+! bcc 386 floating point routines (version 2)
+! --- fpdenormal, fperror, fpinfinity, fpNaN, fpoverflow, fpunderflow,fpdivzero
+! author: Bruce Evans
+
+#include "fperr.h"
+#include "fplib.h"
+
+ .extern _fperr
+
+! Cause a denormal-operand exception
+! Preserves all general registers if signal handler returns
+
+ .globl fpdenormal
+ .align ALIGNMENT
+fpdenormal:
+#if 0
+ push eax
+ mov eax,#EFDENORMAL
+ call fperror
+ pop eax
+#endif
+ ret
+
+! Cause an exception with error code eax, preserving all genregs except eax
+
+ .globl fperror
+ .align ALIGNMENT
+fperror:
+ push ebp ! set up usual frame ...
+ mov ebp,esp ! ... for debugging
+ push edx ! save default
+ push ecx
+ push eax ! error code is arg to C routine
+ call _fperr
+ add esp,#GENREG_SIZE
+ pop ecx ! restore default
+ pop edx
+ pop ebp
+ ret
+
+ .align ALIGNMENT
+fphuge:
+ mov ecx,#D_HUGE_LOW ! prepare number +-HUGEVAL
+ or edx,#D_HUGE_HIGH ! ... in case signal handler returns
+ jmp fperror
+
+! Cause an infinite-operand exception
+! Return +-HUGEVAL in edx:ecx with sign from edx
+
+ .globl fpinfinity
+ .align ALIGNMENT
+fpinfinity:
+ mov eax,#EFINFINITY
+ jmp fphuge ! almost right
+
+! Cause an NaN-operand exception
+! Return +-HUGEVAL in edx:ecx with sign from edx
+
+ .globl fpNaN
+ .align ALIGNMENT
+fpNaN:
+ mov eax,#EFNAN ! there are different types of NaNs but...
+ jmp fphuge ! WRONG
+
+! Cause an overflow exception
+! Return +-HUGEVAL in edx:ecx with sign from edx
+
+ .globl fpoverflow
+ .align ALIGNMENT
+fpoverflow:
+ mov eax,#EFOVERFLOW
+ jmp fphuge ! almost right
+
+! Cause an underflow exception (actually assume it is masked for now)
+! Return denormal or 0.0 in edx:ecx
+! XXX - this should cause a denormal exception or none for the denormal case
+! Args: sign in edx, fraction in esi:eax, right shift in edi
+! Returns: denormalized number in edx:eax
+
+ .globl fpunderflow
+ .align ALIGNMENT
+fpunderflow:
+#if 0
+ mov eax,#EFUNDERFLOW
+ jmp fperror
+#endif
+ cmp edi,#REG_BIT
+ jb denormalize1
+ mov eax,esi
+ sub esi,esi
+ sub edi,#REG_BIT
+ cmp edi,#REG_BIT
+ jb denormalize1
+denormalize_underflow:
+#if 0
+ mov eax,#EFUNDERFLOW
+ jmp fperror
+#endif
+ sub eax,eax
+ mov edx,eax
+ ret
+
+ .align ALIGNMENT
+denormalize1:
+ mov ecx,edi
+ shrd eax,esi,cl
+ shr esi,cl
+ mov ecx,esi
+ or ecx,eax
+ jz denormalize_underflow
+ and edx,#D_SIGN_MASK
+ or edx,esi
+ ret
+
+! Cause an fp division by zero exception
+! Return +-HUGEVAL in edx:ecx with sign from edx
+
+ .globl fpdivzero
+ .align ALIGNMENT
+fpdivzero:
+ mov eax,#EFDIVZERO
+ test edx,#D_EXP_MASK
+ jnz fphuge ! almost right
+ sub ecx,ecx
+ mov edx,ecx
+ jmp fperror
diff --git a/libc/i386fp/fplib.h b/libc/i386fp/fplib.h
new file mode 100644
index 0000000..f110717
--- /dev/null
+++ b/libc/i386fp/fplib.h
@@ -0,0 +1,43 @@
+#define ALIGNMENT 4
+#define CHAR_BIT 8
+#define D_BIT (D_SIZE * CHAR_BIT)
+#define D_EXP_BIAS ((1 << (D_EXP_BIT - 1)) - 1)
+#define D_EXP_BIT 11
+#define D_EXP_INFINITE ((1 << D_EXP_BIT) - 1)
+#define D_EXP_MASK (((1 << D_EXP_BIT) - 1) << D_EXP_SHIFT)
+#define D_EXP_SHIFT (REG_BIT - (1 + D_EXP_BIT))
+#define D_FRAC_BIT 53
+#define D_FRAC_MASK (D_NORM_MASK - 1)
+#define D_HIGH 4
+#define D_HUGE_HIGH (D_EXP_MASK - 1)
+#define D_HUGE_LOW 0xFFFFFFFF
+#define D_LOW 0
+#define D_NORM_BIT (D_FRAC_BIT - 1 - REG_BIT)
+#define D_NORM_MASK (1 << D_NORM_BIT)
+#define D_SIGN_BIT 63
+#define D_SIGN_MASK (1 << (D_SIGN_BIT - REG_BIT))
+#define D_SIZE 8
+#define F_BIT (F_SIZE * CHAR_BIT)
+#define F_EXP_BIAS ((1 << (F_EXP_BIT - 1)) - 1)
+#define F_EXP_BIT 8
+#define F_EXP_INFINITE ((1 << F_EXP_BIT) - 1)
+#define F_EXP_MASK (((1 << F_EXP_BIT) - 1) << F_EXP_SHIFT)
+#define F_EXP_SHIFT (REG_BIT - (1 + F_EXP_BIT))
+#define F_FRAC_BIT 24
+#define F_FRAC_MASK (F_NORM_MASK - 1)
+#define F_HIGH 0
+#define F_HUGE_HIGH (F_EXP_MASK - 1)
+#define F_NORM_BIT (F_FRAC_BIT - 1)
+#define F_NORM_MASK (1 << F_NORM_BIT)
+#define F_SIGN_BIT 31
+#define F_SIGN_MASK (1 << F_SIGN_BIT)
+#define F_SIZE 4
+#define FREE_D_SIGN_BIT_TEST (D_SIGN_BIT % REG_BIT == REG_BIT - 1)
+#define GENREG_SIZE 4
+#define INT_BIT 32
+#define INT_MAX 0x7FFFFFFF
+#define INT_MIN (-0x7FFFFFFF - 1)
+#define PC_SIZE 4
+#define REG_BIT 32
+#define SHORT_BIT 16
+#define UINT_MAX 0xFFFFFFFF
diff --git a/libc/i386fp/fptoi.x b/libc/i386fp/fptoi.x
new file mode 100644
index 0000000..30de729
--- /dev/null
+++ b/libc/i386fp/fptoi.x
@@ -0,0 +1,117 @@
+! bcc 386 floating point routines (version 2)
+! -- dtoi, dtol, dtoui, dtoul, ftoi, ftol (todo: ftoui, ftoul)
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern fpoverflow
+ .extern Fpushf
+
+! Convert double x at [ebx] to int and return in eax
+
+ .globl dtoi
+ .globl dtol
+ .align ALIGNMENT
+dtoi:
+dtol:
+ mov eax,D_HIGH[ebx]
+ mov ecx,eax
+ and ecx,#D_EXP_MASK ! extract exponent
+ jz retz ! if 0 return 0
+ test eax,#D_SIGN_MASK
+ jnz negative
+ call into_dtoui
+ cmp eax,#INT_MAX
+ ja overflow_int_max
+ ret
+
+ .align ALIGNMENT
+negative:
+ and eax,#~D_SIGN_MASK
+ call into_dtoui
+ cmp eax,#INT_MIN
+ ja overflow_int_min
+ neg eax
+ ret
+
+ .align ALIGNMENT
+overflow_int_max:
+ call fpoverflow
+ mov eax,#INT_MAX
+ ret
+
+ .align ALIGNMENT
+overflow_int_min:
+ js return ! actually INT_MIN is OK
+ call fpoverflow
+ mov eax,#INT_MIN
+return:
+ ret
+
+ .align ALIGNMENT
+retz:
+ sub eax,eax ! clear return value
+ ret
+
+! Convert double x at [ebx] to unsigned and return in eax
+
+ .globl dtoui
+ .globl dtoul
+ .align ALIGNMENT
+dtoui:
+dtoul:
+ mov eax,D_HIGH[ebx]
+ mov ecx,eax
+ and ecx,#D_EXP_MASK ! extract exponent
+ jz retz ! if 0 return 0
+ test eax,#D_SIGN_MASK
+ jnz overflow_0
+into_dtoui:
+ mov edx,D_LOW[ebx]
+
+ and eax,#D_FRAC_MASK ! extract fraction
+ or eax,#D_NORM_MASK ! restore normalization bit
+
+ shr ecx,#D_EXP_SHIFT ! convert exponent to number
+ sub ecx,#D_EXP_BIAS+D_NORM_BIT ! adjust radix point
+ jl dtoui_rightshift ! should we shift left or right?
+ cmp ecx,#D_BIT-D_FRAC_BIT ! can shift left by at most this
+ ja overflow_uint_max ! if more, overflow
+ shld eax,edx,cl
+ ret
+
+ .align ALIGNMENT
+dtoui_rightshift:
+ neg ecx ! make shift count > 0
+ cmp ecx,#REG_BIT ! big shifts would be taken mod REG_BIT ...
+ jae retz ! ... no good
+ shr eax,cl ! otherwise it is faster to do the shift ...
+ ret ! ... then to jump for the slightly smaller
+ ! ... shift counts that shift out all bits
+
+ .align ALIGNMENT
+overflow_0:
+ call fpoverflow
+ sub eax,eax
+ ret
+
+ .align ALIGNMENT
+overflow_uint_max:
+ call fpoverflow
+ mov eax,#UINT_MAX
+ ret
+
+! ftoi is like dtoi except ebx points to a float instead of a double.
+! This is a quickly-written slowish version that does not take advantage
+! of the float being smaller.
+
+ .globl ftoi
+ .globl ftol
+ .align ALIGNMENT
+ftoi:
+ftol:
+ call Fpushf
+ mov ebx,esp
+ call dtoi
+ add esp,#D_SIZE
+ ret
diff --git a/libc/i386fp/fpulld.x b/libc/i386fp/fpulld.x
new file mode 100644
index 0000000..928a846
--- /dev/null
+++ b/libc/i386fp/fpulld.x
@@ -0,0 +1,20 @@
+! bcc 386 floating point routines (version 2) -- Fpulld
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+! Pop double from stack and store at address [ebx]
+
+ .globl Fpulld
+ .align ALIGNMENT
+Fpulld:
+ pop ecx
+ pop dword D_LOW[ebx]
+ pop dword D_HIGH[ebx]
+ jmp ecx ! return
+
+! This popping method is much slower on 486's because popping to memory
+! takes 5+ while moving twice takes 2 and the return address doesn't
+! have to be moved. However, popping is a little faster on a non-cached
+! 386/20 with static column RAM although the memory access pattern is
+! better for a double-width move than for popping. What about a cached 386?
diff --git a/libc/i386fp/fpullf.x b/libc/i386fp/fpullf.x
new file mode 100644
index 0000000..417ef92
--- /dev/null
+++ b/libc/i386fp/fpullf.x
@@ -0,0 +1,101 @@
+! bcc 386 floating point routines (version 2) -- Fpullf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern fpoverflow
+ .extern fpunderflow
+
+! pop double from stack, convert to float and store at address [ebx]
+
+ .globl Fpullf
+ .align ALIGNMENT
+Fpullf:
+
+! Step 1: load and shift left
+
+ mov eax,PC_SIZE+D_LOW[esp] ! lower dword
+ mov edx,PC_SIZE+D_HIGH[esp] ! upper dword
+ mov ecx,edx ! copy upper dword into ecx ...
+ and ecx,#D_SIGN_MASK ! ... and extract sign
+ and edx,#D_EXP_MASK | D_FRAC_MASK ! extract exponent and fraction
+ sub edx,#(D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT ! adjust exponent bias
+ jz underflow
+ cmp edx,#F_EXP_INFINITE << D_EXP_SHIFT ! check if exponent lies in reduced range
+ jae outofbounds
+ shld edx,eax,#D_EXP_BIT-F_EXP_BIT ! shift exponent and fraction
+
+! Step 2: round
+
+ test eax,#1 << (REG_BIT-1-(D_EXP_BIT-F_EXP_BIT)) ! test upper rounding bit
+ jz step3 ! below middle, don't round up
+ test eax,#(1 << (REG_BIT-1-(D_EXP_BIT-F_EXP_BIT)))-1 ! test other rounding bits
+ jnz roundup ! above middle, round up
+ test dl,#1 ! in middle, check parity bit
+ jz step3 ! already even, otherwise round up to make even
+
+roundup:
+ inc edx ! carry 1
+ test edx,#F_FRAC_MASK ! is fraction now 0? (carry into F_EXPMASK)
+ jnz step3 ! no -- carry complete
+ cmp edx,#(F_EXP_INFINITE << F_EXP_SHIFT) & ~F_NORM_MASK ! yes (very unlikely): check for overflow
+ ! XXX - I think these tests say 0x7e7fffff overflows
+ jae overflow
+
+! Step 3: put it all together
+
+step3:
+ or edx,ecx ! include sign
+ mov F_HIGH[ebx],edx ! store the result in [ebx]
+ ret #D_SIZE ! return and release double from stack
+
+ .align ALIGNMENT
+outofbounds:
+ jns overflow ! have just compared exponent with the max
+underflow:
+! call fpunderflow ! XXX
+ push ecx ! save sign
+ mov ecx,edx
+ and ecx,#~D_FRAC_MASK ! assume fraction is below exp
+ cmp ecx,#-((D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT) ! was exp = 0?
+ jz exp_x_0
+ shr ecx,#D_EXP_SHIFT
+ neg ecx
+ and edx,#D_FRAC_MASK
+ or edx,#D_NORM_MASK
+ shld edx,eax,#D_EXP_BIT-F_EXP_BIT-1
+ shl eax,#D_EXP_BIT-F_EXP_BIT-1
+ push ebx ! save to use for rounding
+ sub ebx,ebx
+ shrd ebx,eax,cl
+ shrd eax,edx,cl
+ shr edx,cl
+ cmp eax,#1 << (REG_BIT-1)
+ jb over_denorm_roundup
+ ja denorm_roundup
+ test dl,#1
+ jz over_denorm_roundup
+denorm_roundup:
+#if F_NORM_BIT != F_EXP_SHIFT
+#include "carry into norm bit doesn't go into low exp bit"
+#endif
+ inc edx
+over_denorm_roundup:
+ pop ebx
+ pop ecx
+ or edx,ecx
+ mov F_HIGH[ebx],edx
+ ret #D_SIZE
+
+ .align ALIGNMENT
+exp_x_0: ! XXX check for denormals - they underflow
+ pop ecx
+ mov dword F_HIGH[ebx],#0
+ ret #D_SIZE
+
+ .align ALIGNMENT
+overflow:
+ mov edx,ebx ! put sign in usual reg
+ call fpoverflow
+ mov F_HIGH[ebx],dword #F_HUGE_HIGH ! XXX - should use infinity
+ ret #D_SIZE ! ... if fpoverflow does
diff --git a/libc/i386fp/fpushd.x b/libc/i386fp/fpushd.x
new file mode 100644
index 0000000..68caab0
--- /dev/null
+++ b/libc/i386fp/fpushd.x
@@ -0,0 +1,60 @@
+! bcc 386 floating point routines (version 2) -- dtof, Fpushd, Fneg, Fnegd
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern Fpullf
+
+! dtof converts the double at [ebx] to a float and pushes the float onto
+! the stack (D_SIZE bytes are allocated for the float although only the bottom
+! F_SIZE are used).
+! This is a quickly-written slowish version.
+
+ .globl dtof
+ .align ALIGNMENT
+dtof:
+ pop eax
+ sub esp,#D_SIZE ! build result here
+ push eax ! put back return address
+ call Fpushd
+ lea ebx,D_SIZE+PC_SIZE[esp]
+ call Fpullf
+ ret
+
+! Push double at address [ebx] onto stack
+
+ .globl Fpushd
+ .align ALIGNMENT
+Fpushd:
+ pop ecx
+ push dword D_HIGH[ebx]
+ push dword D_LOW[ebx]
+ jmp ecx ! return
+
+! Push double at address [ebx] onto stack, negating it on the way.
+
+! Don't worry about generating -0 because other routines have to allow for
+! it anyway.
+
+! Perhaps this and Fneg should check for denormals and illegal operands
+! (I think only signalling NaNs are illegal).
+! fchs doesn't check, but fld does.
+! Our Fpushd is not quite like fld because no conversions are involved.
+
+ .globl Fnegd
+ .align ALIGNMENT
+Fnegd:
+ pop ecx
+ mov eax,D_HIGH[ebx]
+ xor eax,#D_SIGN_MASK ! toggle sign
+ push eax
+ push dword D_LOW[ebx]
+ jmp ecx ! return
+
+! Negate double on stack
+
+ .globl Fneg
+ .align ALIGNMENT
+Fneg:
+ xorb PC_SIZE+D_SIZE-1[esp],D_SIGN_MASK >> (REG_BIT-CHAR_BIT) ! toggle sign
+ ret
diff --git a/libc/i386fp/fpushf.x b/libc/i386fp/fpushf.x
new file mode 100644
index 0000000..7cb2f8d
--- /dev/null
+++ b/libc/i386fp/fpushf.x
@@ -0,0 +1,74 @@
+! bcc 386 floating point routines (version 2) -- Fpushf, Fnegf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern fpdenormal
+
+! Load float at [ebx], convert to double and push on stack
+
+ .globl Fpushf
+ .align ALIGNMENT
+Fpushf:
+ mov edx,F_HIGH[ebx]
+into_Fpushf:
+ test edx,#F_EXP_MASK ! is exponent 0?
+ jz exp_x_0
+
+ mov ecx,edx ! extract sign
+ and ecx,#F_SIGN_MASK
+
+ and edx,#F_EXP_MASK | F_FRAC_MASK ! extract exponent and fraction
+ sub eax,eax ! clear lower dword
+ shrd eax,edx,#D_EXP_BIT-F_EXP_BIT ! shift exponent and fraction to new position
+ shr edx,#D_EXP_BIT-F_EXP_BIT
+
+ add edx,#(D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT ! adjust exponent bias
+ or edx,ecx ! include sign
+
+ pop ecx
+ push edx ! upper dword
+ push eax ! lower dword
+ jmp ecx ! return
+
+ .align ALIGNMENT
+exp_x_0:
+ mov eax,edx
+ and eax,#F_FRAC_MASK
+ jnz x_denorm
+ pop ecx
+ push eax ! upper dword = 0
+ push eax ! lower dword = 0
+ jmp ecx ! return
+
+ .align ALIGNMENT
+x_denorm:
+ call fpdenormal
+ bsr ecx,eax ! zzzz
+ neg ecx
+ add ecx,#F_NORM_BIT
+ shl eax,cl
+ and eax,#F_FRAC_MASK
+ neg ecx
+ add ecx,#D_EXP_BIAS-F_EXP_BIAS+1
+ shl ecx,#D_EXP_SHIFT
+ and edx,#F_SIGN_MASK ! assumed same as D_SIGN_MASK
+ or edx,ecx
+ sub ecx,ecx
+ shrd ecx,eax,#D_EXP_BIT-F_EXP_BIT
+ shr eax,#D_EXP_BIT-F_EXP_BIT
+ or edx,eax
+
+ pop eax
+ push edx ! upper dword
+ push ecx ! lower dword
+ jmp eax ! return
+
+! Fnegf: as Fpushf, but negate double before pushing onto stack
+
+ .globl Fnegf
+ .align ALIGNMENT
+Fnegf:
+ mov edx,F_HIGH[ebx]
+ xor edx,#F_SIGN_MASK ! toggle sign
+ jmp into_Fpushf ! join Fpushf
diff --git a/libc/i386fp/fpushi.x b/libc/i386fp/fpushi.x
new file mode 100644
index 0000000..b19aae2
--- /dev/null
+++ b/libc/i386fp/fpushi.x
@@ -0,0 +1,126 @@
+! bcc 386 floating point routines (version 2)
+! -- Fpushi, Fpushl, Fpushs, Fpushc, Fpushuc, Fpushui, Fpushul, Fpushus
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+! Convert the short in ax to double and push on stack
+
+ .globl Fpushs
+ .align ALIGNMENT
+Fpushs:
+ cwde
+ add eax,#0 ! fast 3-byte instruction to align
+
+! Convert the int or long in eax to double and push on stack
+
+ .globl Fpushi
+ .globl Fpushl
+! .align ALIGNMENT ! don't do this until it pads with nop's
+Fpushi:
+Fpushl:
+ test eax,eax
+ jz return_eax ! got 0 in eax
+ mov ebx,#(D_EXP_BIAS+D_NORM_BIT) << D_EXP_SHIFT ! set no-sign and exponent
+ jns normalize ! sign and fraction bits already set up
+ mov ebx,#D_SIGN_MASK | ((D_EXP_BIAS+D_NORM_BIT) << D_EXP_SHIFT) ! adjust sign
+ neg eax ! adjust fraction
+ jmp normalize
+
+ .align ALIGNMENT
+ret1:
+ mov eax,#D_EXP_BIAS << D_EXP_SHIFT
+ add eax,#0 ! fast 3-byte instruction to align
+
+! .align ALIGNMENT ! don't do this until it pads with nop's
+return_eax:
+ pop ecx
+ push eax ! upper dword
+ push dword #0 ! lower dword = 0
+ jmp ecx ! return
+
+! Convert the (unsigned) char in al to double and push on stack
+
+ .globl Fpushc
+ .globl Fpushuc
+ .align ALIGNMENT
+Fpushc:
+Fpushuc:
+ and eax,#(1 << CHAR_BIT)-1
+ add eax,#0 ! fast 3-byte instruction to align
+
+! Convert the unsigned short in ax to double and push on stack
+
+ .globl Fpushus
+! .align ALIGNMENT ! don't do this until it pads with nop's
+Fpushus:
+ and eax,#(1 << SHORT_BIT)-1
+ add eax,#0 ! fast 3-byte instruction to align
+
+! Convert the unsigned int or long in eax to double and push on stack
+
+ .globl Fpushui
+ .globl Fpushul
+! .align ALIGNMENT ! don't do this until it pads with nop's
+Fpushui:
+Fpushul:
+ cmp eax,#1 ! this tests for both 0 and 1
+ jb return_eax ! got 0 in eax
+ jz ret1
+ mov ebx,#(D_EXP_BIAS+D_NORM_BIT) << D_EXP_SHIFT ! set no-sign and exponent
+
+! .align ALIGNMENT ! don't do this until it pads with nop's
+normalize:
+ sub edx,edx ! clear lower dword of result
+
+! Find first nonzero bit
+! Don't use bsr, it is slow (const + 3n on 386, const + n on 486)
+
+ sub ecx,ecx ! prepare unsigned extension of cl
+ test eax,#~D_FRAC_MASK
+ jnz large
+ test eax,#0xFF << (D_NORM_BIT-8)
+ jnz middle
+ shl eax,#8
+ sub ebx,#8 << D_EXP_SHIFT
+ test eax,#0xFF << (D_NORM_BIT-8)
+ jnz middle
+ shl eax,#8
+ sub ebx,#8 << D_EXP_SHIFT
+middle:
+ shld ecx,eax,#D_NORM_BIT
+ mov cl,bsr_table[ecx]
+ add ecx,#REG_BIT-D_NORM_BIT-D_NORM_BIT
+ neg ecx
+ shl eax,cl
+ shl ecx,#D_EXP_SHIFT
+ sub ebx,ecx
+return:
+ and eax,#D_FRAC_MASK ! remove normalization bit
+ or eax,ebx ! include exponent (and sign) to fraction
+ pop ecx
+ push eax ! upper dword
+ push edx ! lower dword
+ jmp ecx ! return
+
+ .align ALIGNMENT
+large:
+ shld ecx,eax,#REG_BIT-(D_NORM_BIT+8)
+ jnz huge
+ shld ecx,eax,#REG_BIT-D_NORM_BIT
+ mov cl,bsr_table[ecx]
+got_shift_right:
+ shrd edx,eax,cl
+ shr eax,cl
+ shl ecx,#D_EXP_SHIFT
+ add ebx,ecx
+ jmp return
+
+ .align ALIGNMENT
+huge:
+ mov cl,bsr_table[ecx]
+ add cl,#8
+ jmp got_shift_right
+
+ .data
+ .extern bsr_table
diff --git a/libc/i386fp/frexp.x b/libc/i386fp/frexp.x
new file mode 100644
index 0000000..318fc34
--- /dev/null
+++ b/libc/i386fp/frexp.x
@@ -0,0 +1,66 @@
+! bcc 386 floating point routines (version 2) -- _frexp
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern fpdenormal
+
+! void frexp(double value, int *exponent);
+! splits a double into exponent and fraction (where 0.5 <= fraction < 1.0)
+
+ .globl _frexp
+ .align ALIGNMENT
+_frexp:
+push ebx
+#undef PC_SIZE
+#define PC_SIZE 8
+ mov eax,PC_SIZE+D_LOW[esp] ! lower dword of x
+ mov ebx,PC_SIZE+D_HIGH[esp] ! upper dword of x
+ mov edx,PC_SIZE+D_SIZE[esp] ! exponent pointer
+ mov ecx,ebx ! extract exponent here
+ and ecx,#D_EXP_MASK
+ jz exp_x_0
+
+ shr ecx,#D_EXP_SHIFT ! exponent + bias
+got_x:
+ sub ecx,#D_EXP_BIAS-1 ! D_EXP_BIAS is for 1.x form, we want 0.1x form
+ mov [edx],ecx ! return exponent
+ and ebx,#D_SIGN_MASK | D_FRAC_MASK ! extract sign and fraction
+ or ebx,#(D_EXP_BIAS-1) << D_EXP_SHIFT ! set new exponent for 0.1x
+mov edx,ebx
+pop ebx
+ ret
+
+ .align ALIGNMENT
+exp_x_0:
+ test ebx,#D_FRAC_MASK
+ jnz xu_denorm
+ test eax,eax
+ jnz xl_denorm
+ mov [edx],ecx ! return zero exponent
+ mov ebx,ecx ! guard against -0 (may not be necessary)
+mov edx,ebx
+pop ebx
+ ret
+
+ .align ALIGNMENT
+xl_denorm:
+ call fpdenormal
+ bsr ecx,eax ! zzzz
+ neg ecx
+ add ecx,#REG_BIT-1
+ shl eax,cl
+ shld ebx,eax,#D_NORM_BIT+1
+ shl eax,#D_NORM_BIT+1
+ sub ecx,#D_NORM_BIT+1
+ jmp got_x
+
+ .align ALIGNMENT
+xu_denorm:
+ call fpdenormal
+ bsr ecx,ebx
+ neg ecx
+ add ecx,#D_NORM_BIT
+ shld ebx,eax,cl
+ shl eax,cl
+ jmp got_x
diff --git a/libc/i386fp/ftst.x b/libc/i386fp/ftst.x
new file mode 100644
index 0000000..2a92ef1
--- /dev/null
+++ b/libc/i386fp/ftst.x
@@ -0,0 +1,28 @@
+! bcc 386 floating point routines (version 2) -- Ftst, Ftstd, Ftstf
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+#if 0 /* bcc doesn't generate Ftst (but it might in future) */
+ .globl Ftst
+#endif
+ .align ALIGNMENT
+Ftst:
+ cmp dword PC_SIZE+D_HIGH[esp],#0 ! need only test upper dword of x
+ ret #D_SIZE
+
+! Compare double at address [ebx] with 0
+
+ .globl Ftstd
+ .align ALIGNMENT
+Ftstd:
+ cmp dword D_HIGH[ebx],#0 ! need only test upper dword of x
+ ret
+
+! Compare float at address [ebx] with 0
+
+ .globl Ftstf
+ .align ALIGNMENT
+Ftstf:
+ cmp dword F_HIGH[ebx],#0
+ ret
diff --git a/libc/i386fp/ldexp.x b/libc/i386fp/ldexp.x
new file mode 100644
index 0000000..bc9dd03
--- /dev/null
+++ b/libc/i386fp/ldexp.x
@@ -0,0 +1,74 @@
+! bcc 386 floating point routines (version 2) -- _ldexp
+! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans
+
+#include "fplib.h"
+
+ .extern fpoverflow
+ .extern fpunderflow
+
+! void ldexp(double value, int exponent);
+! returns value * (2 ** exponent)
+
+ .globl _ldexp
+ .align ALIGNMENT
+_ldexp:
+push ebx
+#undef PC_SIZE
+#define PC_SIZE 8
+ mov ebx,PC_SIZE+D_HIGH[esp] ! upper dword of x
+ mov ecx,PC_SIZE+D_SIZE[esp] ! exponent arg
+ mov eax,ebx ! extract exponent (of x) here
+ and eax,#D_EXP_MASK
+! jz exp_y_0 ! may need check for preposterous exponent arg too
+
+ shr eax,#D_EXP_SHIFT ! shift to low bits just for testing
+ jz underflow ! denormal?
+ add eax,ecx ! test-add the exponents
+ jz underflow ! XXX probably need to fiddle norm bit
+ cmp eax,#D_EXP_INFINITE ! check if still within range
+ jae outofbounds ! the unsigned compare catches all overflow cases
+ ! because the exponent of x is non-negative
+
+ shl ecx,#D_EXP_SHIFT ! shift exponent arg bits into final position ...
+ add ebx,ecx ! ... safe to add it to exponent of x now
+ mov eax,PC_SIZE+D_LOW[esp] ! lower dword of x
+mov edx,ebx
+pop ebx
+ ret
+
+
+ .align ALIGNMENT
+outofbounds:
+ test ecx,ecx ! overflow or underflow?
+ jns overflow
+underflow:
+ mov edx,ebx ! put sign in usual reg
+ push edi
+ push esi
+ mov edi,eax ! put exponent in usual reg
+ mov eax,2*GENREG_SIZE+PC_SIZE+D_LOW[esp]
+ ! put lower dword of x in usual reg
+ mov esi,ebx ! put upper dword of x in usual reg
+ and esi,#D_EXP_MASK | D_FRAC_MASK
+ test esi,#D_EXP_MASK
+ jz foo
+ and esi,#D_FRAC_MASK
+ or esi,#D_NORM_MASK
+foo:
+ neg edi
+! inc edi ! XXX ?
+ call fpunderflow
+ pop esi
+ pop edi
+ mov ebx,edx ! XXX = wrong reg
+pop ebx
+ ret
+
+ .align ALIGNMENT
+overflow:
+ mov edx,ebx ! put sign in usual reg
+ call fpoverflow
+ mov eax,ecx ! XXX = wrong reg
+ mov ebx,edx ! XXX = wrong reg
+pop ebx
+ ret
diff --git a/libc/i386fp/modf.c b/libc/i386fp/modf.c
new file mode 100644
index 0000000..3232543
--- /dev/null
+++ b/libc/i386fp/modf.c
@@ -0,0 +1,14 @@
+#include <math.h>
+
+/* Slooow version. */
+
+double modf(x, pint)
+double x;
+double *pint;
+{
+ if (x >= 0)
+ *pint = floor(x);
+ else
+ *pint = ceil(x);
+ return x - *pint;
+}
diff --git a/libc/i386fp/test.c b/libc/i386fp/test.c
new file mode 100644
index 0000000..bd92581
--- /dev/null
+++ b/libc/i386fp/test.c
@@ -0,0 +1,118 @@
+#include <sys/times.h>
+#include <limits.h>
+#include <stdio.h>
+#include <time.h>
+
+#define CONVTYPE int
+#define MAX (MIN + NITER - 1)
+#define MIN INT_MIN
+
+#define NITER 1000000
+
+double one = 1;
+double two = 2;
+double big = 1e99;
+
+double d;
+double d1;
+float f;
+
+int main()
+{
+ CONVTYPE cti;
+ CONVTYPE cto;
+ clock_t delta;
+ struct tms finish;
+ int i;
+ struct tms start;
+
+#if 0
+ times(&start);
+ for (cti = MIN; cti <= MAX; ++cti)
+ {
+ d = cti;
+ cto = d;
+ if (cti != cto)
+ printf("%08x %08x\n", cti, cto);
+ if (cti % 10000000 == 0)
+ {
+ printf("%8x ok ", cti);
+ fflush(stdout);
+ }
+ }
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for %d i -> d and d -> i conversions was %g s (%d t)\n",
+ MAX - MIN + 1, delta / (double) CLOCKS_PER_SEC, delta);
+#endif
+
+ times(&start);
+ for (cti = MIN; cti <= MAX; ++cti)
+ d = cti;
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for %d i -> d conversions was %g s (%d t)\n",
+ MAX - MIN + 1, delta / (double) CLOCKS_PER_SEC, delta);
+
+ times(&start);
+ for (cti = MIN; cti <= MAX; ++cti)
+ {
+ d = cti;
+ cto = d;
+ }
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime - delta;
+ printf("Time for %d d -> i conversions was %g s (%d t)\n",
+ MAX - MIN + 1, delta / (double) CLOCKS_PER_SEC, delta);
+
+ d = 0;
+ times(&start);
+ for (i = 0; i < NITER; ++i)
+ d = d + 1;
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for adding %d 1.0's to 0.0 was %g s (%d t), result = %g\n",
+ NITER, delta / (double) CLOCKS_PER_SEC, delta, d);
+
+ d = 0;
+ times(&start);
+ for (; d < NITER;)
+ d = d + 1;
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for adding %d 1.0's to 0.0 (d index) was %g s (%d t), result = %g\n",
+ NITER, delta / (double) CLOCKS_PER_SEC, delta, d);
+
+ times(&start);
+ for (i = 1; i <= NITER; ++i)
+ {
+ d1 = i;
+ d = d1 * d1;
+ }
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for %d mults was %g s (%d t), result = %g\n",
+ NITER, delta / (double) CLOCKS_PER_SEC, delta, d);
+
+ times(&start);
+ for (i = 1; i <= NITER; ++i)
+ {
+ d1 = i;
+ d = 1 / d1;
+ }
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for %d divs was %g s (%d t), result = %g\n",
+ NITER, delta / (double) CLOCKS_PER_SEC, delta, d);
+
+ f = 0;
+ times(&start);
+ for (i = 0; i < NITER; ++i)
+ f = f + 1;
+ times(&finish);
+ delta = finish.tms_utime - start.tms_utime;
+ printf("Time for adding %d 1.0f's to 0.0f was %g s (%d t), result = %g\n",
+ NITER, delta / (double) CLOCKS_PER_SEC, delta, f);
+
+ return 0;
+}
diff --git a/libc/i386sys/Config b/libc/i386sys/Config
new file mode 100644
index 0000000..1bf0110
--- /dev/null
+++ b/libc/i386sys/Config
@@ -0,0 +1 @@
+sys386: Linux-i386 system call routines
diff --git a/libc/i386sys/Makefile b/libc/i386sys/Makefile
new file mode 100644
index 0000000..ef01ac9
--- /dev/null
+++ b/libc/i386sys/Makefile
@@ -0,0 +1,52 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+LSRC=syslibc.c
+LOBJ=__cstart3.o time.o abort.o wait.o waitpid.o wait3.o killpg.o setpgrp.o \
+ sleep.o usleep.o
+
+ESRC=exec.c
+EOBJ=execl.o execv.o execle.o execlp.o execvp.o
+
+DSRC=dirent.c
+DOBJ=opendir.o closedir.o readdir.o
+
+ifeq ($(LIB_CPU)-$(LIB_OS),i386-ELKS)
+OBJ=$(LOBJ3) $(LOBJ) $(EOBJ) $(DOBJ)
+SYSCALLS=syscalls
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(SYSCALLS) $(LIBC)($(OBJ))
+ @:
+
+syscalls: syscall.mak
+ $(MAKE) -f syscall.mak LIBC="$(LIBC)" CFLAGS="$(CFLAGS)"
+
+syscall.mak: mksyscall syscall.dat
+ sh mksyscall
+
+$(LIBC)($(LOBJ)): $(LSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(DOBJ)): $(DSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(EOBJ)): $(ESRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
+ rm -f syscall.c syscall.mak
+
diff --git a/libc/i386sys/dirent.c b/libc/i386sys/dirent.c
new file mode 100644
index 0000000..8f7574c
--- /dev/null
+++ b/libc/i386sys/dirent.c
@@ -0,0 +1,106 @@
+
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <malloc.h>
+
+#ifdef L_opendir
+DIR *
+opendir(dname)
+const char *dname;
+{
+ struct stat st;
+ int fd;
+ DIR *p;
+
+ if (stat(dname, &st) < 0)
+ return 0;
+
+ if (!S_ISDIR(st.st_mode))
+ {
+ errno = ENOTDIR;
+ return 0;
+ }
+ if ((fd = open(dname, O_RDONLY)) < 0)
+ return 0;
+
+ p = malloc(sizeof(DIR));
+ if (p == 0)
+ {
+ close(fd);
+ return 0;
+ }
+
+ p->dd_buf = malloc(sizeof(struct dirent));
+ if (p->dd_buf == 0)
+ {
+ free(p);
+ close(fd);
+ return 0;
+ }
+ p->dd_fd = fd;
+ p->dd_loc = p->dd_size = 0;
+
+ return p;
+}
+#endif
+
+#ifdef L_closedir
+int
+closedir(dirp)
+DIR *dirp;
+{
+ int fd;
+ fd = dirp->dd_fd;
+ free(dirp->dd_buf);
+ free(dirp);
+ return close(fd);
+}
+#endif
+
+#ifdef __AS386_16__
+#ifdef L_readdir
+/*
+ * This currently assumes we see a v. simple diectory structure, it's
+ * probably faked!
+ */
+struct dirent *
+readdir(dirp)
+DIR *dirp;
+{
+ int cc;
+ cc = read(dirp->dd_fd, dirp->dd_buf, sizeof(struct dirent));
+
+ if (cc <= 0)
+ return 0;
+ if (cc != sizeof(struct dirent))
+ {
+ errno = EBADF;
+ return 0;
+ }
+ return dirp->dd_buf;
+}
+#endif
+#else
+
+/* This is for 386 linux */
+
+#ifdef L_readdir
+struct dirent *
+readdir(dirp)
+DIR *dirp;
+{
+ int cc;
+
+ cc = __readdir(dirp->dd_fd, dirp->dd_buf, 1);
+ if (cc <= 0)
+ return 0;
+ if (cc>1) dirp->dd_buf->d_name[cc] = 0;
+
+ return dirp->dd_buf;
+}
+#endif
+
+#endif
diff --git a/libc/i386sys/exec.c b/libc/i386sys/exec.c
new file mode 100644
index 0000000..411b744
--- /dev/null
+++ b/libc/i386sys/exec.c
@@ -0,0 +1,292 @@
+
+#include <errno.h>
+#include <sys/stat.h>
+
+extern char ** environ;
+
+#ifdef L_execl
+int
+execl(fname, arg0)
+char * fname, *arg0;
+{
+ return execve(fname, &arg0, environ);
+}
+#endif
+
+#ifdef L_execv
+int
+execv(fname, argv)
+char * fname, **argv;
+{
+ return execve(fname, argv, environ);
+}
+#endif
+
+#ifdef L_execle
+int
+execle(fname, arg0)
+char *fname, *arg0;
+{
+ char ** envp = &arg0;
+ while(*envp) envp++;
+ return execve(fname, &arg0, envp+1);
+}
+#endif
+
+#ifdef L_execve
+int
+execve(fname, argv, envp)
+char * fname;
+char ** argv;
+char ** envp;
+{
+ char **p;
+ int argv_len=0, argv_count=0;
+ int envp_len=0, envp_count=0;
+ int stack_bytes;
+ unsigned short * pip;
+ char * pcp, * stk_ptr, *baseoff;
+ int rv;
+
+ /* How much space for argv */
+ for(p=argv; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+
+ /* How much space for envp */
+ for(p=envp; p && *p && envp_len >= 0; p++)
+ {
+ envp_count++; envp_len += strlen(*p)+1;
+ }
+
+ /* tot it all up */
+ stack_bytes = 2 /* argc */
+ + argv_count * 2 + 2 /* argv */
+ + argv_len
+ + envp_count * 2 + 2 /* envp */
+ + envp_len;
+
+ /* Allocate it */
+ if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0
+ || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+/* Sanity check
+ printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
+ argv_count, argv_len, envp_count, envp_len, stack_bytes);
+*/
+
+ /* Now copy in the strings */
+ pip=(unsigned short *) stk_ptr;
+ pcp=stk_ptr+2*(1+argv_count+1+envp_count+1);
+
+ /* baseoff = stk_ptr + stack_bytes; */
+ baseoff = stk_ptr;
+ *pip++ = argv_count;
+ for(p=argv; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ for(p=envp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ rv = __exec(fname, stk_ptr, stack_bytes);
+ /* FIXME: This will probably have to interpret '#!' style exe's */
+ sbrk(-stack_bytes);
+ return rv;
+}
+#endif
+
+#ifdef L_execlp
+int
+execlp(fname, arg0)
+char * fname, *arg0;
+{
+ return execvp(fname, &arg0);
+}
+#endif
+
+#ifdef L_execvp
+int
+execvp(fname, argv)
+char * fname, **argv;
+{
+ char *pname = fname, *path;
+ int besterr = ENOENT;
+ int flen, plen;
+ char * bp = sbrk(0);
+
+ if( *fname != '/' && (path = getenv("PATH")) != 0 )
+ {
+ flen = strlen(fname)+2;
+
+ for(;path;)
+ {
+ if( *path == ':' || *path == '\0' )
+ {
+ tryrun(fname, argv);
+ if( errno == EACCES ) besterr = EACCES;
+ if( *path ) path++; else break;
+ }
+ else
+ {
+ char * p = strchr(path, ':');
+ if(p) *p = '\0';
+ plen = strlen(path);
+ pname = sbrk(plen+flen);
+
+ strcpy(pname, path);
+ strcat(pname, "/");
+ strcat(pname, fname);
+
+ tryrun(pname, argv);
+ if( errno == EACCES ) besterr = EACCES;
+
+ brk(pname);
+ pname = fname;
+ if(p) *p++ = ':';
+ path=p;
+ }
+ }
+ }
+
+ tryrun(pname, argv);
+ brk(bp);
+ if( errno == ENOENT || errno == 0 ) errno = besterr;
+ return -1;
+}
+
+static int tryrun(pname, argv)
+char * pname;
+char ** argv;
+{
+static char *shprog[] = {"/bin/sh", "", 0};
+ struct stat st;
+
+ if( stat(pname, &st) < 0 ) return;
+ if( !S_ISREG(st.st_mode) ) return;
+
+#ifdef __AS386_16__
+ __execvve(pname, (void*)0, argv, environ);
+ if( errno == ENOEXEC )
+ {
+ shprog[1] = pname;
+ __execvve(shprog[0], shprog, argv, environ);
+ }
+#else
+ execve(pname, argv, environ);
+ /* FIXME - running /bin/sh in 386 mode */
+#endif
+}
+
+#ifdef __AS386_16__
+static int
+__execvve(fname, interp, argv, envp)
+char * fname;
+char ** interp;
+char ** argv;
+char ** envp;
+{
+ char **p;
+ int argv_len=0, argv_count=0;
+ int envp_len=0, envp_count=0;
+ int stack_bytes;
+ unsigned short * pip;
+ char * pcp, * stk_ptr, *baseoff;
+ int rv;
+
+ /* How much space for argv */
+ for(p=interp; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+ for(p=argv; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+
+ /* How much space for envp */
+ for(p=envp; p && *p && envp_len >= 0; p++)
+ {
+ envp_count++; envp_len += strlen(*p)+1;
+ }
+
+ /* tot it all up */
+ stack_bytes = 2 /* argc */
+ + argv_count * 2 + 2 /* argv */
+ + argv_len
+ + envp_count * 2 + 2 /* envp */
+ + envp_len;
+
+ /* Allocate it */
+ if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0
+ || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+/* Sanity check
+ printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
+ argv_count, argv_len, envp_count, envp_len, stack_bytes);
+*/
+
+ /* Now copy in the strings */
+ pip=(unsigned short *) stk_ptr;
+ pcp=stk_ptr+2*(1+argv_count+1+envp_count+1);
+
+ /* baseoff = stk_ptr + stack_bytes; */
+ baseoff = stk_ptr;
+ *pip++ = argv_count;
+ for(p=interp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ for(p=argv; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ for(p=envp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ rv = __exec(fname, stk_ptr, stack_bytes);
+ /* FIXME: This will probably have to interpret '#!' style exe's */
+ sbrk(-stack_bytes);
+ return rv;
+}
+#endif
+#endif
diff --git a/libc/i386sys/mksyscall b/libc/i386sys/mksyscall
new file mode 100644
index 0000000..d9b7f3a
--- /dev/null
+++ b/libc/i386sys/mksyscall
@@ -0,0 +1,143 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+#
+# This script generates the 'simple' system calls for the 386
+#
+# Each call is put into it's own object file, if the semantics of the
+# call are not correct UNIX then the 4th field in the dat file has a
+# marker and the function is generated with a __ prefix.
+#
+#
+# Different levels of squeeze
+# 0 = each is complete
+# 1 = Short codes calling common function
+
+rm -f syscall.c syscall.mak
+
+tr '[A-Z]' '[a-z]' < syscall.dat | \
+awk 'BEGIN{
+ print "# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>" > "syscall.mak";
+ print "# This file is part of the Linux-8086 C library and is distributed" > "syscall.mak";
+ print "# under the GNU Library General Public License." > "syscall.mak";
+ print "# " > "syscall.mak";
+ print "# This file is automatically generated\n" > "syscall.mak"
+
+ print "/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>";
+ print " * This file is part of the Linux-8086 C library and is distributed";
+ print " * under the GNU Library General Public License.";
+ print " * ";
+ print " * This file is automatically generated */\n"
+ obj="OBJ=";
+
+ print "/* Standard start */\n\n"
+ printf("#ifndef __MSDOS__\n");
+ printf("#ifdef __AS386_32__\n");
+ printf("#asm\n");
+ printf(" .text\n");
+ printf(" .align 4\n");
+ printf("#endasm\n\n");
+
+ COMPACT=0;
+}
+/^[ ]*#/ { next; }
+/^[ ]*$/ { next; }
+{
+ if( $2 > max_call ) max_call = $2;
+
+ if( $3 == "x" || $3 == "" ) next;
+ else if( $4 == "-" ) next;
+ else if( $4 == "*" ) funcname="__" $1;
+ else funcname=$1;
+
+ if( length(obj) > 60 )
+ {
+ printf("%s\t\\\n", obj) > "syscall.mak";
+ obj=" ";
+ }
+ obj=obj funcname ".o ";
+
+ printf "/* CALL %s */\n\n", $0;
+
+ printf("#ifdef L_%s\n", funcname);
+ printf("#asm\n");
+ printf("export _%s\n", funcname);
+ printf("_%s:\n", funcname);
+
+ # Inline assembler max to 5 args (20 bytes)
+ if( $3 != 4 && $3 != 5 && ( COMPACT || $3 > 5 ))
+ {
+ if( $3 == 0 )
+ {
+ printf(" mov eax,#%d\n", $2);
+ }
+ else
+ {
+ printf("#if __FIRST_ARG_IN_AX__\n");
+ printf(" mov edx,#%d\n", $2);
+ printf("#else\n");
+ printf(" mov eax,#%d\n", $2);
+ printf("#endif\n");
+ }
+ printf(" br sys_call%d\n", $3);
+ }
+ else
+ {
+ if( $3 >= 1 ) printf("#if __FIRST_ARG_IN_AX__\n");
+ if( $3 >= 1 ) printf(" mov ebx,eax\n");
+ if( $3 >= 2 ) printf(" mov ecx,[esp+4]\n");
+ if( $3 >= 3 ) printf(" mov edx,[esp+8]\n");
+ if( $3 >= 4 ) printf(" push esi\n");
+ if( $3 >= 4 ) printf(" mov esi,[esp+16]\n");
+ if( $3 >= 5 ) printf(" push edi\n");
+ if( $3 >= 5 ) printf(" mov edi,[esp+24]\n");
+ if( $3 >= 1 ) printf("#else\n");
+ if( $3 >= 1 ) printf(" mov ebx,[esp+4]\n");
+ if( $3 >= 2 ) printf(" mov ecx,[esp+8]\n");
+ if( $3 >= 3 ) printf(" mov edx,[esp+12]\n");
+ if( $3 >= 4 ) printf(" push esi\n");
+ if( $3 >= 4 ) printf(" mov esi,[esp+20]\n");
+ if( $3 >= 5 ) printf(" push edi\n");
+ if( $3 >= 5 ) printf(" mov edi,[esp+28]\n");
+ if( $3 >= 1 ) printf("#endif\n");
+ printf(" mov eax,#%d\n", $2);
+ printf(" int $80\n");
+
+ if( $3 >= 5 ) printf(" pop edi\n");
+ if( $3 >= 4 ) printf(" pop esi\n");
+
+ printf(" test eax,eax\n");
+ printf(" jl syscall_err\n");
+ printf(" ret\n");
+ printf("syscall_err:\n");
+ printf(" neg eax\n");
+ printf(" mov [_errno],eax\n");
+ printf(" mov eax,#-1\n");
+ printf(" ret\n");
+ }
+ printf("#endasm\n");
+ printf("#endif\n\n");
+}
+END{
+
+ printf("#endif /* __AS386_32__ */\n\n");
+ printf("#endif /* __MSDOS__ */\n\n");
+ printf("%s\n", obj) > "syscall.mak";
+ printf "\n" > "syscall.mak";
+
+}' > syscall.c
+
+cat >> syscall.mak <<\!
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)($(OBJ))
+ @:
+
+$(LIBC)($(OBJ)): syscall.dat
+ $(CC) $(CFLAGS) -DL_$* syscall.c -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+!
+
+exit $?
diff --git a/libc/i386sys/signal.c b/libc/i386sys/signal.c
new file mode 100644
index 0000000..dad3389
--- /dev/null
+++ b/libc/i386sys/signal.c
@@ -0,0 +1,99 @@
+
+#ifndef __MSDOS__
+#ifdef __AS386_16__
+
+#include <errno.h>
+#include <signal.h>
+
+typedef __sighandler_t Sig;
+
+extern int __signal __P((int, __sighandler_t));
+static Sig system_signal();
+
+Sig __sigtable[_NSIG-1];
+
+/*
+ * Signal handler.
+ *
+ */
+
+/*
+ * KERNEL INTERFACE:
+ * It is assumed the kernel will never give us a signal we haven't
+ * _explicitly_ asked for!
+ *
+ * The Kernel need only save space for _one_ function pointer
+ * (to system_signal) and must deal with SIG_DFL and SIG_IGN
+ * in kernel space.
+ *
+ * When a signal is required the kernel must set all the registers as if
+ * returning from a interrupt normally then push the number of the signal
+ * to be generated, push the current pc value, then set the pc to the
+ * address of the 'system_signal' function.
+ */
+
+Sig
+signal(number, pointer)
+int number;
+Sig pointer;
+{
+ Sig old_sig;
+ int rv;
+ if( number < 1 || number >= _NSIG ) { errno=EINVAL; return SIG_ERR; }
+
+ if( pointer == SIG_DFL || pointer == SIG_IGN )
+ rv = __signal(number, pointer);
+ else
+ rv = __signal(number, (__sighandler_t) system_signal);
+
+ if( rv < 0 ) return SIG_ERR;
+
+ old_sig = __sigtable[number-1];
+ __sigtable[number-1] = pointer;
+
+ switch(rv)
+ {
+ case 0: return SIG_DFL;
+ case 1: return SIG_IGN;
+ return old_sig;
+ }
+}
+
+#asm
+ .text
+_system_signal: ! When this is called by the kernel the stack contains
+ pushf ! in order:
+ push ax !
+ push bx ! The signal number, (NOS)
+ push cx ! The program counter, (TOS)
+ push dx !
+ push si ! It does NOT contain the CS register or the flags.
+ push di ! This means it cannot be unraveled by an iret.
+ push bp
+ push es ! Note also only ES segment register is saved.
+ mov bx,sp ! Unlike minix the rv from a system call is in AX.
+ mov bx,[bx+20]
+#if __FIRST_ARG_IN_AX__
+ mov ax,bx
+#else
+ push bx ! NB this is _unchecked_, do we want to ?
+#endif
+ add bx,bx
+ mov bx,[bx+___sigtable-2] ! Offset by 2 cause no entry for signal 0
+ call bx ! Do we want to check BX for 0 or 1 ?
+ inc sp
+ inc sp
+ pop es
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ popf
+ ret #2 ! Get rid of the signum too.
+#endasm
+
+#endif /* __AS386_16__ */
+#endif /* __MSDOS__ */
diff --git a/libc/i386sys/syscall.dat b/libc/i386sys/syscall.dat
new file mode 100644
index 0000000..da9ad6c
--- /dev/null
+++ b/libc/i386sys/syscall.dat
@@ -0,0 +1,155 @@
+
+#
+# Name No Args Flag, comment
+#
+# . = Ok, with comment
+# * = Needs libc code (Prefix __)
+# - = Obsolete/not required
+#
+# Name N C
+setup 0 X
+exit 1 1 *
+fork 2 0
+vfork 2 0 . Fake alias of fork
+read 3 3
+write 4 3
+open 5 3
+close 6 1
+waitpid 7 3
+creat 8 2
+link 9 2
+unlink 10 1
+execve 11 3
+chdir 12 1
+time 13 1
+dv32_mknod 14 3 * Has correct args for 32bit dev_t
+chmod 15 2
+chown 16 3
+break 17 X - This is done in a special function
+oldstat 18 X -
+lseek 19 3
+getpid 20 0
+mount 21 5
+umount 22 1
+setuid 23 1
+getuid 24 0
+stime 25 1
+ptrace 26 4
+alarm 27 1
+oldfstat 28 X -
+pause 29 0
+utime 30 2
+stty 31 X -
+gtty 32 X -
+access 33 2
+nice 34 1
+ftime 35 1
+sync 36 0
+kill 37 2
+rename 38 2
+mkdir 39 2
+rmdir 40 1
+dup 41 1
+pipe 42 1
+times 43 1
+prof 44 X -
+brk 45 1 - need to save brk_addr & -ve is valid return.
+setgid 46 1
+getgid 47 0
+signal 48 2
+geteuid 49 0
+getegid 50 0
+acct 51 1
+phys 52 X -
+lock 53 X -
+ioctl 54 3
+fcntl 55 3
+mpx 56 X -
+setpgid 57 2
+ulimit 58 2
+oldolduname 59 X -
+umask 60 1
+chroot 61 1
+dv32_ustat 62 2 * Has correct args for 32bit dev_t
+dup2 63 2
+getppid 64 0
+getpgrp 65 0
+setsid 66 0
+sigaction 67 3
+siggetmask 68 0
+sigsetmask 69 1
+setreuid 70 2
+setregid 71 2
+sigsuspend 72 1
+sigpending 73 1
+sethostname 74 2
+setrlimit 75 2
+getrlimit 76 2
+getrusage 77 2
+gettimeofday 78 2
+settimeofday 79 2
+getgroups 80 2
+setgroups 81 2
+select 82 1 * select's arg is &arg1
+symlink 83 2
+oldlstat 84 X -
+readlink 85 3
+uselib 86 1
+swapon 87 2
+reboot 88 3
+readdir 89 3 * Takes the fd not a ddptr
+mmap 90 1 * Is a pointer to a buffer with the 6 args.
+munmap 91 2
+truncate 92 2
+ftruncate 93 2
+fchmod 94 2
+fchown 95 2
+getpriority 96 2
+setpriority 97 3
+profil 98 X - glibc has userspace
+statfs 99 2
+fstatfs 100 2
+ioperm 101 3
+socketcall 102 2 * This is a lib internal for socket stuff
+klog 103 X
+setitimer 104 3
+getitimer 105 2
+dv32_stat 106 2 * Has correct args for 32 bit dev_t
+dv32_lstat 107 2 * Has correct args for 32 bit dev_t
+dv32_fstat 108 2 * Has correct args for 32 bit dev_t
+olduname 109 X -
+iopl 110 1
+vhangup 111 0
+idle 112 0 - System internal
+vm86 113 1
+wait4 114 4
+swapoff 115 1
+sysinfo 116 1
+ipc 117 5 * SYSV ipc entry point
+fsync 118 1
+sigreturn 119 1 * Signal internal
+clone 120 2
+setdomainname 121 2
+uname 122 1
+modify_ldt 123 X
+adjtimex 124 1
+mprotect 125 3
+sigprocmask 126 3
+create_module 127 X - Module handling, NO WAY!
+init_module 128 X
+delete_module 129 X
+get_kernel_syms 130 X
+quotactl 131 X
+getpgid 132 1
+fchdir 133 1
+bdflush 134 2
+sysfs 135 3
+personality 136 1 * Linux specific.
+afs_syscall 137 X
+setfsuid 138 1
+setfsgid 139 1
+_llseek 140 X
+getdents 141 3 * New style readdir ?
+_newselect 142 X
+flock 143 2
+syscall_flock 143 X
diff --git a/libc/i386sys/syslibc.c b/libc/i386sys/syslibc.c
new file mode 100644
index 0000000..60dda42
--- /dev/null
+++ b/libc/i386sys/syslibc.c
@@ -0,0 +1,255 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/times.h>
+
+/* MSDOS has it's own versions */
+#ifndef __MSDOS__
+#ifdef __AS386_32__
+
+/********************** Function __cstartup *******************************/
+
+#ifdef L___cstart3
+
+void (*__cleanup)() = 0;
+char ** environ;
+
+#asm
+ loc 2
+call_main:
+ .long _main ! Segment 2 is the trailing pointers, main and the
+ .long call_exit ! routine to call exit.
+#if __FIRST_ARG_IN_AX__
+ .data
+saved_arg1:
+ .long 0
+#endif
+ .data
+loop_safe:
+ .long 0
+ .text
+
+export ___mkargv
+___mkargv: ! BCC Tells linker to init argv ... none needed.
+
+export ___cstartup
+___cstartup: ! Crt0 startup (Linux style)
+ mov eax,[esp]
+ test eax,eax
+ jz call_exit ! If argc == 0 this is being called by ldd, exit.
+ mov eax,[esp+8]
+ mov [_environ],eax
+#if __FIRST_ARG_IN_AX__
+ pop [saved_arg1] ! Argc will go into eax
+#endif
+
+ mov ebx,#auto_start ! Pointer to first autostart function
+auto_run:
+#if __FIRST_ARG_IN_AX__
+ mov eax,[saved_arg1]
+#endif
+ mov [loop_safe],ebx
+ mov ebx,[ebx]
+ test ebx,ebx
+ jz no_func
+ call ebx ! Call the function
+no_func:
+ mov ebx,[loop_safe]
+ add ebx,#4 ! next
+ jmp auto_run ! And round for the next.
+
+call_exit: ! Last item called by above.
+ pop ebx ! Be tidy.
+#if !__FIRST_ARG_IN_AX__
+ push eax ! At the end the last called was main() push it`s
+#endif
+ call _exit ! return val and call exit();
+bad_exit:
+ jmp bad_exit ! Exit returned !!
+
+export _exit
+export __exit
+_exit: ! exit(rv) function
+#if __FIRST_ARG_IN_AX__
+ mov [saved_arg1],eax
+#else
+ push [esp+4] ! Copy the `rv` for the exit fuctions.
+#endif
+ mov ebx,[___cleanup] ! Call exit, normally this is `__do_exit`
+ test ebx,ebx
+ je no_clean ! But it`s default is null
+ call ebx
+no_clean:
+#if __FIRST_ARG_IN_AX__
+ mov eax,[saved_arg1]
+#else
+ add esp,#4
+#endif
+__exit: ! _exit(rv)
+ br ___exit ! This is just an alias for __exit();
+
+#endasm
+#endif
+
+/********************** Function time ************************************/
+
+#ifdef L_time
+time_t time(where)
+time_t *where;
+{
+ struct timeval rv;
+ if( gettimeofday(&rv, (void*)0) < 0 ) return -1;
+ if(where) *where = rv.tv_sec;
+ return rv.tv_sec;
+}
+#endif
+
+/********************** Function abort ************************************/
+
+#ifdef L_abort
+#include <signal.h>
+
+int abort()
+{
+ signal(SIGABRT, SIG_DFL);
+ kill(SIGABRT, getpid()); /* Correct one */
+ pause(); /* System may just schedule */
+ signal(SIGKILL, SIG_DFL);
+ kill(SIGKILL, getpid()); /* Can't trap this! */
+ __exit(255); /* WHAT!! */
+}
+#endif
+
+/********************** Function wait ************************************/
+
+#ifdef L_wait
+int
+wait(status)
+int * status;
+{
+ return wait4(-1, status, 0, (void*)0);
+}
+#endif
+
+/********************** Function wait3 **************************************/
+
+#ifdef L_wait3
+int
+wait3(status, opts, usage)
+int * status;
+int opts;
+struct rusage * usage;
+{
+ return wait4(-1, status, opts, usage);
+}
+#endif
+
+/********************** Function waitpid ************************************/
+
+#ifdef L_waitpid
+int
+waitpid(pid, status, opts)
+int pid;
+int * status;
+int opts;
+{
+ return wait4(pid, status, opts, (void*)0);
+}
+#endif
+
+/********************** Function killpg ************************************/
+
+#ifdef L_killpg
+int
+killpg(pid, sig)
+int pid;
+int sig;
+{
+ if(pid == 0)
+ pid = getpgrp();
+ if(pid > 1)
+ return kill(-pid, sig);
+ errno = EINVAL;
+ return -1;
+}
+#endif
+
+/********************** Function setpgrp ************************************/
+
+#ifdef L_setpgrp
+int
+setpgrp()
+{
+ return setpgid(0,0);
+}
+#endif
+
+/********************** Function sleep ************************************/
+
+#ifdef L_sleep
+#include <signal.h>
+
+/* This uses SIGALRM, it does keep the previous alarm call but will lose
+ * any alarms that go off during the sleep
+ */
+
+static void alrm() { }
+
+unsigned int sleep(seconds)
+unsigned int seconds;
+{
+ void (*last_alarm)();
+ unsigned int prev_sec;
+
+ prev_sec = alarm(0);
+ if( prev_sec <= seconds ) prev_sec = 1; else prev_sec -= seconds;
+
+ last_alarm = signal(SIGALRM, alrm);
+ alarm(seconds);
+ pause();
+ seconds = alarm(prev_sec);
+ signal(SIGALRM, last_alarm);
+ return seconds;
+}
+#if 0
+ /* Is this a better way ? If we have select of course :-) */
+#include <sys/time.h>
+unsigned int
+sleep(seconds)
+unsigned int seconds;
+{
+ struct timeval timeout;
+ time_t start = time((void*)0);
+ timeout.tv_sec = seconds;
+ timeout.tv_usec = 0;
+ select(1, NULL, NULL, NULL, &timeout);
+ return seconds - (time((void*)0) - start);
+}
+#endif
+
+#endif
+
+/********************** Function usleep ************************************/
+
+#ifdef L_usleep
+#include <sys/time.h>
+void
+usleep(useconds)
+unsigned long useconds;
+{
+ struct timeval timeout;
+ timeout.tv_sec = useconds%1000000L;
+ timeout.tv_usec = useconds/1000000L;
+ select(1, NULL, NULL, NULL, &timeout);
+}
+#endif
+
+/********************** THE END ********************************************/
+
+#endif /* __MSDOS__ */
+#endif
diff --git a/libc/include/a.out.h b/libc/include/a.out.h
new file mode 100644
index 0000000..bd58346
--- /dev/null
+++ b/libc/include/a.out.h
@@ -0,0 +1,115 @@
+/* Copyright (C) 1990-1996
+ * This file is part of the ld86 command for Linux-86
+ * It is distributed under the GNU Library General Public License.
+ *
+ * - This may actually be BSD or Minix code, can someone clarify please. -RDB
+ */
+
+#ifndef __AOUT_H
+#define __AOUT_H
+
+struct exec { /* a.out header */
+ unsigned char a_magic[2]; /* magic number */
+ unsigned char a_flags; /* flags, see below */
+ unsigned char a_cpu; /* cpu id */
+ unsigned char a_hdrlen; /* length of header */
+ unsigned char a_unused; /* reserved for future use */
+ unsigned short a_version; /* version stamp (not used at present) */
+ long a_text; /* size of text segement in bytes */
+ long a_data; /* size of data segment in bytes */
+ long a_bss; /* size of bss segment in bytes */
+ long a_entry; /* entry point */
+ long a_total; /* total memory allocated */
+ long a_syms; /* size of symbol table */
+
+ /* SHORT FORM ENDS HERE */
+ long a_trsize; /* text relocation size */
+ long a_drsize; /* data relocation size */
+ long a_tbase; /* text relocation base */
+ long a_dbase; /* data relocation base */
+};
+
+#define A_MAGIC0 (unsigned char) 0x01
+#define A_MAGIC1 (unsigned char) 0x03
+#define BADMAG(X) ((X).a_magic[0] != A_MAGIC0 ||(X).a_magic[1] != A_MAGIC1)
+
+/* CPU Id of TARGET machine (byte order coded in low order two bits) */
+#define A_NONE 0x00 /* unknown */
+#define A_I8086 0x04 /* intel i8086/8088 */
+#define A_M68K 0x0B /* motorola m68000 */
+#define A_NS16K 0x0C /* national semiconductor 16032 */
+#define A_I80386 0x10 /* intel i80386 */
+#define A_SPARC 0x17 /* Sun SPARC */
+
+#define A_BLR(cputype) ((cputype&0x01)!=0) /* TRUE if bytes left-to-right */
+#define A_WLR(cputype) ((cputype&0x02)!=0) /* TRUE if words left-to-right */
+
+/* Flags. */
+#define A_UZP 0x01 /* unmapped zero page (pages) */
+#define A_PAL 0x02 /* page aligned executable */
+#define A_NSYM 0x04 /* new style symbol table */
+#define A_EXEC 0x10 /* executable */
+#define A_SEP 0x20 /* separate I/D */
+#define A_PURE 0x40 /* pure text */
+#define A_TOVLY 0x80 /* text overlay */
+
+/* Offsets of various things. */
+#define A_MINHDR 32
+#define A_TEXTPOS(X) ((long)(X).a_hdrlen)
+#define A_DATAPOS(X) (A_TEXTPOS(X) + (X).a_text)
+#define A_HASRELS(X) ((X).a_hdrlen > (unsigned char) A_MINHDR)
+#define A_HASEXT(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 8))
+#define A_HASLNS(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 16))
+#define A_HASTOFF(X) ((X).a_hdrlen > (unsigned char) (A_MINHDR + 24))
+#define A_TRELPOS(X) (A_DATAPOS(X) + (X).a_data)
+#define A_DRELPOS(X) (A_TRELPOS(X) + (X).a_trsize)
+#define A_SYMPOS(X) (A_TRELPOS(X) + (A_HASRELS(X) ? \
+ ((X).a_trsize + (X).a_drsize) : 0))
+
+struct reloc {
+ long r_vaddr; /* virtual address of reference */
+ unsigned short r_symndx; /* internal segnum or extern symbol num */
+ unsigned short r_type; /* relocation type */
+};
+
+/* r_tyep values: */
+#define R_ABBS 0
+#define R_RELLBYTE 2
+#define R_PCRBYTE 3
+#define R_RELWORD 4
+#define R_PCRWORD 5
+#define R_RELLONG 6
+#define R_PCRLONG 7
+#define R_REL3BYTE 8
+#define R_KBRANCHE 9
+
+/* r_symndx for internal segments */
+#define S_ABS ((unsigned short)-1)
+#define S_TEXT ((unsigned short)-2)
+#define S_DATA ((unsigned short)-3)
+#define S_BSS ((unsigned short)-4)
+
+struct nlist { /* symbol table entry */
+ char n_name[8]; /* symbol name */
+ long n_value; /* value */
+ unsigned char n_sclass; /* storage class */
+ unsigned char n_numaux; /* number of auxiliary entries (not used) */
+ unsigned short n_type; /* language base and derived type (not used) */
+};
+
+/* Low bits of storage class (section). */
+#define N_SECT 07 /* section mask */
+#define N_UNDF 00 /* undefined */
+#define N_ABS 01 /* absolute */
+#define N_TEXT 02 /* text */
+#define N_DATA 03 /* data */
+#define N_BSS 04 /* bss */
+#define N_COMM 05 /* (common) */
+
+/* High bits of storage class. */
+#define N_CLASS 0370 /* storage class mask */
+#define C_NULL
+#define C_EXT 0020 /* external symbol */
+#define C_STAT 0030 /* static */
+
+#endif /* _AOUT_H */
diff --git a/libc/include/ar.h b/libc/include/ar.h
new file mode 100644
index 0000000..c608371
--- /dev/null
+++ b/libc/include/ar.h
@@ -0,0 +1,18 @@
+#ifndef __AR_H
+#define __AR_H
+
+#define ARMAG "!<arch>\n"
+#define SARMAG 8
+#define ARFMAG "`\n"
+
+struct ar_hdr {
+ char ar_name[16],
+ ar_date[12],
+ ar_uid[6],
+ ar_gid[6],
+ ar_mode[8],
+ ar_size[10],
+ ar_fmag[2];
+};
+
+#endif /* __AR_H */
diff --git a/libc/include/assert.h b/libc/include/assert.h
new file mode 100644
index 0000000..c58c57f
--- /dev/null
+++ b/libc/include/assert.h
@@ -0,0 +1,23 @@
+#ifdef __ASSERT_H
+#define __ASSERT_H
+#include <features.h>
+
+/* If NDEBUG is defined, do nothing.
+ If not, and EXPRESSION is zero, print an error message and abort. */
+
+#ifdef NDEBUG
+
+#define assert(expr) ((void) 0)
+
+#else /* Not NDEBUG. */
+
+extern void __assert __P((const char *, const char *, int));
+
+#define assert(expr) \
+ ((void) ((expr) || \
+ (__assert (__STRING(expr), \
+ __FILE__, __LINE__), 0)))
+
+#endif /* NDEBUG. */
+
+#endif /* __ASSERT_H */
diff --git a/libc/include/bsd/bsd.h b/libc/include/bsd/bsd.h
new file mode 100644
index 0000000..5ab1173
--- /dev/null
+++ b/libc/include/bsd/bsd.h
@@ -0,0 +1,49 @@
+/* bsd.h - simplify porting BSD programs to Linux - rick sladkey */
+
+/* make sure BSD features are enabled, i.e. __USE_BSD and _FAVOR_BSD */
+
+/* cpp in gcc 2.3.3 is broken.
+#ifndef _BSD_BSD_H
+#define _BSD_BSD_H
+*/
+
+#define _BSD_SOURCE 1
+#include <features.h>
+#include <endian.h>
+
+/* some BSD progs expect MIN and MAX to be defined */
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/* make sure we get L_SET and L_INCR, which is in a different place */
+
+#include <sys/file.h>
+
+/* BSD has slight non-POSIX names (and meanings :-) for some things */
+
+#define FAPPEND O_APPEND
+
+#include <limits.h>
+
+/* (absolute) max # characters in exec arglist */
+
+#define NCARGS ARG_MAX
+
+/* ftpd uses this as bits per byte, I don't know why it's called NBBY */
+
+#define NBBY CHAR_BIT
+
+/* gloss over slight differences between BSD direct and POSIX dirent */
+
+#define d_namlen d_reclen
+
+#if 0
+
+/* See <bsd/signal.h> */
+
+typedef void sig_t;
+
+#endif
+
+/* #endif _BSD_BSD_H */
diff --git a/libc/include/bsd/errno.h b/libc/include/bsd/errno.h
new file mode 100644
index 0000000..c2d464e
--- /dev/null
+++ b/libc/include/bsd/errno.h
@@ -0,0 +1,9 @@
+/* make sure EWOULDBLOCK doesn't screw us up */
+#ifndef _BSD_ERRNO_H
+#define _BSD_ERRNO_H
+
+#include_next <errno.h>
+#undef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+
+#endif /* _BSD_ERRNO_H */
diff --git a/libc/include/bsd/sgtty.h b/libc/include/bsd/sgtty.h
new file mode 100644
index 0000000..4e21901
--- /dev/null
+++ b/libc/include/bsd/sgtty.h
@@ -0,0 +1,113 @@
+/* sgtty.h */
+
+/* This file contains defintions to help make linux termios look like
+ bsd sgtty. */
+
+/* Copyright (c) 1992 Ross Biro
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; if not, write to the Free
+Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#ifndef _BSD_SGTTY_H
+#define _BSD_SGTTY_H
+
+#include <termios.h>
+
+#define TIOCGETP 0x5481
+#define TIOCSETP 0x5482
+#define TIOCGETC 0x5483
+#define TIOCSETC 0x5484
+#define TIOCGLTC 0x5485
+#define TIOCSLTC 0x5486
+#define TIOCLGET 0x5487
+#define TIOCLSET 0x5488
+#define TIOCFLUSH 0x5489
+#define TIOCSETN 0x548a
+
+struct sgttyb
+{
+ unsigned short sg_flags;
+ char sg_ispeed;
+ char sg_ospeed;
+ char sg_erase;
+ char sg_kill;
+ struct termios t;
+ int check;
+};
+
+struct tchars
+{
+ char t_intrc;
+ char t_quitc;
+ char t_eofc;
+ char t_startc;
+ char t_stopc;
+ char t_brkc;
+};
+
+struct ltchars
+{
+ char t_werasc;
+ char t_suspc;
+ char t_dsuspc;
+ char t_rprntc;
+ char t_flushc;
+ char t_lnextc;
+};
+
+#define O_RAW 1
+#define O_LCASE 2
+#define O_CRMOD 4
+#define O_ECHO 8
+#define O_ODDP 16
+#define O_EVENP 32
+#define O_CBREAK 64
+/* these don't do anything yet. */
+#define O_TBDELAY 0
+#define O_LLITOUT 0
+#define O_XTABS 0
+#define O_ANYP 0
+
+#ifndef _SGTTY_SOURCE
+
+#undef ioctl
+#define ioctl bsd_ioctl
+
+#undef RAW
+#define RAW O_RAW
+#undef LCASE
+#define LCASE O_LCASE
+#undef ECHO
+#define ECHO O_ECHO
+#undef CRMOD
+#define CRMOD O_CRMOD
+#undef ODDP
+#define ODDP O_ODDP
+#undef EVENP
+#define EVENP O_EVENP
+#undef CBREAK
+#define CBREAK O_CBREAK
+#undef TBDELAY
+#define TBDELAY O_TBDELAY
+#undef LLITOUT
+#define LLITOUT O_LLITOUT
+#undef XTABS
+#define XTABS O_XTABS
+#undef ANYP
+#define ANYP O_ANYP
+#endif
+
+#endif /* _BSD_SGTTY_H */
diff --git a/libc/include/bsd/signal.h b/libc/include/bsd/signal.h
new file mode 100644
index 0000000..24d4502
--- /dev/null
+++ b/libc/include/bsd/signal.h
@@ -0,0 +1,25 @@
+#ifndef _BSD_SIGNAL_H
+#define _BSD_SIGNAL_H
+
+/* make sure we get BSD style signals (that don't need to be reset) */
+
+#define __USE_BSD_SIGNAL
+#include_next <signal.h>
+
+/* use rough approximation of sigaction to sigvec, not completely safe! */
+
+#define sigvec sigaction
+#define sv_mask sa_mask
+#define sv_flags sa_flags
+#define sv_handler sa_handler
+#define sv_onstack sa_mask /* ouch, this one really hurts */
+
+/* BSD uses some non-POSIX signals without ifdefs */
+
+#define SIGSYS SIGUNUSED
+
+/* BSD wants this typedef for signal handlers */
+
+#define sig_t __sighandler_t
+
+#endif /* _BSD_SIGNAL_H */
diff --git a/libc/include/bsd/stdlib.h b/libc/include/bsd/stdlib.h
new file mode 100644
index 0000000..20d34f9
--- /dev/null
+++ b/libc/include/bsd/stdlib.h
@@ -0,0 +1,12 @@
+/* some things shouldn't be macros, get out your barf bag */
+
+#ifndef _BSD_STDLIB_H
+#define _BSD_STDLIB_H
+
+#undef __MALLOC_0_RETURNS_NULL
+#define __MALLOC_0_RETURNS_NULL
+#include_next <stdlib.h>
+#undef atoi
+#undef atol
+
+#endif /* _BSD_STDLIB_H */
diff --git a/libc/include/bsd/sys/ttychars.h b/libc/include/bsd/sys/ttychars.h
new file mode 100644
index 0000000..b3a2036
--- /dev/null
+++ b/libc/include/bsd/sys/ttychars.h
@@ -0,0 +1,3 @@
+#ifndef _BSD_SYS_TTYCHARS_H
+#define _BSD_SYS_TTYCHARS_H
+#endif /* _BSD_SYS_TTYCHARS_H */
diff --git a/libc/include/bsd/tzfile.h b/libc/include/bsd/tzfile.h
new file mode 100644
index 0000000..459a603
--- /dev/null
+++ b/libc/include/bsd/tzfile.h
@@ -0,0 +1,10 @@
+#ifndef _BSD_TZFILE_H
+#define _BSD_TZFILE_H
+
+#define SECSPERDAY (60*60*24)
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+
+#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
+
+#endif /* _BSD_TZFILE_H */
diff --git a/libc/include/bsd/unistd.h b/libc/include/bsd/unistd.h
new file mode 100644
index 0000000..20c2ccc
--- /dev/null
+++ b/libc/include/bsd/unistd.h
@@ -0,0 +1,4 @@
+#include_next <unistd.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
diff --git a/libc/include/ctype.h b/libc/include/ctype.h
new file mode 100644
index 0000000..ed22ef7
--- /dev/null
+++ b/libc/include/ctype.h
@@ -0,0 +1,38 @@
+/*
+ * ctype.h Character classification and conversion
+ */
+
+#ifndef __CTYPE_H
+#define __CTYPE_H
+
+extern unsigned char __ctype[];
+
+#define __CT_d 0x01 /* numeric digit */
+#define __CT_u 0x02 /* upper case */
+#define __CT_l 0x04 /* lower case */
+#define __CT_c 0x08 /* control character */
+#define __CT_s 0x10 /* whitespace */
+#define __CT_p 0x20 /* punctuation */
+#define __CT_x 0x40 /* hexadecimal */
+
+#define toupper(c) (islower(c) ? (c)^0x20 : (c))
+#define tolower(c) (isupper(c) ? (c)^0x20 : (c))
+#define _toupper(c) ((c)^0x20)
+#define _tolower(c) ((c)^0x20)
+#define toascii(c) ((c)&0x7F)
+
+/* Note the '!!' is a cast to 'bool' and even BCC deletes it in an if() */
+#define isalnum(c) (!!(__ctype[(int) c]&(__CT_u|__CT_l|__CT_d)))
+#define isalpha(c) (!!(__ctype[(int) c]&(__CT_u|__CT_l)))
+#define isascii(c) (!((c)&~0x7F))
+#define iscntrl(c) (!!(__ctype[(int) c]&__CT_c))
+#define isdigit(c) (!!(__ctype[(int) c]&__CT_d))
+#define isgraph(c) (!(__ctype[(int) c]&(__CT_c|__CT_s)))
+#define islower(c) (!!(__ctype[(int) c]&__CT_l))
+#define isprint(c) (!(__ctype[(int) c]&__CT_c))
+#define ispunct(c) (!!(__ctype[(int) c]&__CT_p))
+#define isspace(c) (!!(__ctype[(int) c]&__CT_s))
+#define isupper(c) (!!(__ctype[(int) c]&__CT_u))
+#define isxdigit(c) (!!(__ctype[(int) c]&__CT_x))
+
+#endif /* __CTYPE_H */
diff --git a/libc/include/dirent.h b/libc/include/dirent.h
new file mode 100644
index 0000000..c2e8f37
--- /dev/null
+++ b/libc/include/dirent.h
@@ -0,0 +1,52 @@
+
+#ifndef __DIRENT_H
+#define __DIRENT_H
+
+#include <features.h>
+#include <sys/types.h>
+
+#ifndef MAXNAMLEN
+#define MAXNAMLEN 255
+#endif
+
+/* Directory stream type. */
+typedef struct {
+ int dd_fd; /* file descriptor */
+ int dd_loc; /* offset in buffer */
+ int dd_size; /* # of valid entries in buffer */
+ struct dirent *dd_buf; /* -> directory buffer */
+} DIR; /* stream data from opendir() */
+
+typedef int (*__dir_select_fn_t) __P ((__const struct dirent *));
+
+typedef int (*__dir_compar_fn_t) __P ((
+ __const struct dirent * __const *,
+ __const struct dirent * __const *
+ ));
+
+struct dirent {
+ long d_ino;
+ off_t d_off;
+ unsigned short d_reclen;
+ char d_name[MAXNAMLEN+1];
+};
+
+extern DIR *opendir __P ((__const char *__name));
+extern int closedir __P ((DIR * __dirp));
+extern struct dirent *readdir __P ((DIR * __dirp));
+extern void rewinddir __P ((DIR * __dirp));
+
+extern void seekdir __P ((DIR * __dirp, off_t __pos));
+extern off_t telldir __P ((DIR * __dirp));
+
+/* Scan the directory DIR, calling SELECT on each directory entry.
+ Entries for which SELECT returns nonzero are individually malloc'd,
+ sorted using qsort with CMP, and collected in a malloc'd array in
+ *NAMELIST. Returns the number of entries selected, or -1 on error. */
+extern int scandir __P ((__const char *__dir,
+ struct dirent ***__namelist,
+ __dir_select_fn_t __select,
+ __dir_compar_fn_t __compar));
+
+#endif /* dirent.h */
+
diff --git a/libc/include/dos.h b/libc/include/dos.h
new file mode 100644
index 0000000..1e2b11e
--- /dev/null
+++ b/libc/include/dos.h
@@ -0,0 +1,36 @@
+
+#ifndef __DOS_H
+#define __DOS_H
+#include <features.h>
+
+union REGS
+{
+ struct { unsigned int ax, bx, cx, dx, si, di, cflag; } x;
+ struct { unsigned char al, ah, bl, bh, cl, ch, dl, dh; } h;
+};
+
+struct SREGS
+{
+ unsigned int es, cs, ss, ds;
+};
+
+#ifdef __MSDOS__
+extern unsigned int __envseg;
+extern unsigned int __psp;
+char * __fconv __P((char * fname));
+
+unsigned int __segalloc __P((unsigned int paracount));
+void __setvect __P((int i, long j));
+long __getvect __P((int vecno));
+#endif
+
+unsigned int __get_ds __P((void));
+unsigned int __get_es __P((void));
+void __set_es __P((unsigned int seg));
+int __peek_es __P((unsigned int off));
+int __deek_es __P((unsigned int off));
+
+#define movedata __movedata
+
+#endif
+
diff --git a/libc/include/errno.h b/libc/include/errno.h
new file mode 100644
index 0000000..c8d2002
--- /dev/null
+++ b/libc/include/errno.h
@@ -0,0 +1,25 @@
+#ifndef __ERRNO_H
+#define __ERRNO_H
+
+#include <features.h>
+#include <linuxmt/errno.h>
+
+#ifdef __USE_BSD
+extern int sys_nerr;
+extern char *sys_errlist[];
+#endif
+#ifdef __USE_GNU
+extern int _sys_nerr;
+extern char *_sys_errlist[];
+#endif
+
+extern int errno;
+
+__BEGIN_DECLS
+
+extern void perror __P ((__const char* __s));
+extern char* strerror __P ((int __errno));
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h
new file mode 100644
index 0000000..ddd9afc
--- /dev/null
+++ b/libc/include/fcntl.h
@@ -0,0 +1,20 @@
+#ifndef __FCNTL_H
+#define __FCNTL_H
+
+#include <features.h>
+#include <sys/types.h>
+#include <linuxmt/fcntl.h>
+
+#ifndef FNDELAY
+#define FNDELAY O_NDELAY
+#endif
+
+__BEGIN_DECLS
+
+extern int creat __P ((__const char * __filename, mode_t __mode));
+extern int fcntl __P ((int __fildes,int __cmd, ...));
+extern int open __P ((__const char * __filename, int __flags, ...));
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/features.h b/libc/include/features.h
new file mode 100644
index 0000000..11eb610
--- /dev/null
+++ b/libc/include/features.h
@@ -0,0 +1,36 @@
+
+#ifndef __FEATURES_H
+#define __FEATURES_H
+
+#ifdef __STDC__
+
+#define __P(x) x
+#define __const const
+
+/* Almost ansi */
+#if __STDC__ != 1
+#define const
+#define volatile
+#endif
+
+#else /* K&R */
+
+#define __P(x) ()
+#define __const
+#define const
+#define volatile
+
+#endif
+
+/* No C++ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+
+/* GNUish things */
+#define __CONSTVALUE
+#define __CONSTVALUE2
+
+#include <sys/cdefs.h>
+
+#endif
+
diff --git a/libc/include/getopt.h b/libc/include/getopt.h
new file mode 100644
index 0000000..0d71ff6
--- /dev/null
+++ b/libc/include/getopt.h
@@ -0,0 +1,17 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#ifndef __GETOPT_H
+#define __GETOPT_H
+
+#include <features.h>
+
+extern char *optarg;
+extern int opterr;
+extern int optind;
+
+extern int getopt __P((int argc, char *const *argv, const char *shortopts));
+
+#endif /* __GETOPT_H */
diff --git a/libc/include/grp.h b/libc/include/grp.h
new file mode 100644
index 0000000..96b2b4b
--- /dev/null
+++ b/libc/include/grp.h
@@ -0,0 +1,37 @@
+#ifndef __GRP_H
+#define __GRP_H
+
+#include <sys/types.h>
+#include <features.h>
+#include <stdio.h>
+
+/* The group structure */
+struct group
+{
+ char *gr_name; /* Group name. */
+ char *gr_passwd; /* Password. */
+ gid_t gr_gid; /* Group ID. */
+ char **gr_mem; /* Member list. */
+};
+
+extern void setgrent __P ((void));
+extern void endgrent __P ((void));
+extern struct group * getgrent __P ((void));
+
+extern struct group * getgrgid __P ((__const gid_t gid));
+extern struct group * getgrnam __P ((__const char * name));
+
+extern struct group * fgetgrent __P ((FILE * file));
+
+extern int setgroups __P ((size_t n, __const gid_t * groups));
+extern int initgroups __P ((__const char * user, gid_t gid));
+
+
+#ifdef __LIBC__
+extern struct group * __getgrent __P ((int grp_fd));
+#endif
+
+#endif /* _GRP_H */
+
+
+
diff --git a/libc/include/limits.h b/libc/include/limits.h
new file mode 100644
index 0000000..520c1c4
--- /dev/null
+++ b/libc/include/limits.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#ifndef __LIMITS_H
+#define __LIMITS_H
+
+#if __AS386_16__
+#define MB_LEN_MAX 1 /* Longest multi-byte character */
+#define CHAR_MAX 127 /* maximum char value */
+#define CHAR_MIN (-127) /* mimimum char value */
+#define SCHAR_MAX 127 /* maximum signed char value */
+#define SCHAR_MIN (-127) /* minimum signed char value */
+#define CHAR_BIT 8 /* number of bits in a char */
+#define SHRT_MAX 32767 /* maximum (signed) short value */
+#define SHRT_MIN (-32767) /* minimum (signed) short value */
+#define INT_MAX 32767 /* maximum (signed) int value */
+#define INT_MIN (-32767) /* minimum (signed) int value */
+#define LONG_MAX 2147483647 /* maximum (signed) long value */
+#define LONG_MIN (-2147483647) /* minimum (signed) long value */
+#define UCHAR_MAX 255 /* maximum unsigned char value */
+#define USHRT_MAX 0xffff /* maximum unsigned short value */
+#define UINT_MAX 0xffff /* maximum unsigned int value */
+#define ULONG_MAX 0xffffffff /* maximum unsigned long value */
+#ifndef RAND_MAX
+#define RAND_MAX INT_MAX
+#endif
+#endif
+
+#if __AS386_32__
+#define MB_LEN_MAX 1 /* Longest multi-byte character */
+#define CHAR_MAX 127 /* maximum char value */
+#define CHAR_MIN (-127) /* mimimum char value */
+#define SCHAR_MAX 127 /* maximum signed char value */
+#define SCHAR_MIN (-127) /* minimum signed char value */
+#define CHAR_BIT 8 /* number of bits in a char */
+#define SHRT_MAX 32767 /* maximum (signed) short value */
+#define SHRT_MIN (-32767) /* minimum (signed) short value */
+#define INT_MAX 2147483647 /* maximum (signed) int value */
+#define INT_MIN (-2147483647) /* minimum (signed) int value */
+#define LONG_MAX 2147483647 /* maximum (signed) long value */
+#define LONG_MIN (-2147483647) /* minimum (signed) long value */
+#define UCHAR_MAX 255 /* maximum unsigned char value */
+#define USHRT_MAX 0xffff /* maximum unsigned short value */
+#define UINT_MAX 0xffffffff /* maximum unsigned int value */
+#define ULONG_MAX 0xffffffff /* maximum unsigned long value */
+#ifndef RAND_MAX
+#define RAND_MAX INT_MAX
+#endif
+#endif
+
+#ifndef CHAR_MAX
+#error "Limits.h not implemented"
+#endif
+
+#endif
diff --git a/libc/include/malloc.h b/libc/include/malloc.h
new file mode 100644
index 0000000..e8fdb0a
--- /dev/null
+++ b/libc/include/malloc.h
@@ -0,0 +1,30 @@
+
+#ifndef __MALLOC_H
+#define __MALLOC_H
+#include <features.h>
+#include <sys/types.h>
+
+/*
+ * Mini malloc allows you to use a less efficient but smaller malloc the
+ * cost is about 100 bytes of code in free but malloc (700bytes) doesn't
+ * have to be linked. Unfortunatly memory can only be reused if everything
+ * above it has been freed
+ *
+ */
+
+extern void free __P((void *));
+extern void *malloc __P((size_t));
+extern void *realloc __P((void *, size_t));
+extern void *alloca __P((size_t));
+
+extern void *(*__alloca_alloc) __P((size_t));
+
+#ifdef __LIBC__
+#define __MINI_MALLOC__
+#endif
+
+#ifdef __MINI_MALLOC__
+#define malloc(x) ((*__alloca_alloc)(x))
+#endif
+
+#endif
diff --git a/libc/include/math.h b/libc/include/math.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libc/include/math.h
diff --git a/libc/include/memory.h b/libc/include/memory.h
new file mode 100644
index 0000000..3b2f590
--- /dev/null
+++ b/libc/include/memory.h
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/libc/include/paths.h b/libc/include/paths.h
new file mode 100644
index 0000000..dc76939
--- /dev/null
+++ b/libc/include/paths.h
@@ -0,0 +1,21 @@
+/* paths.h <ndf@linux.mit.edu> */
+
+#ifndef ___PATHS_H
+#define ___PATHS_H
+
+
+#define _PATH_CONSOLE "/dev/console"
+#define _PATH_TTY "/dev/tty"
+#define _PATH_NOLOGIN "/etc/nologin"
+#define _PATH_LOGIN "/bin/login"
+#define _PATH_BSHELL "/bin/sh"
+#define _PATH_UTMP "/var/run/utmp"
+#define _PATH_WTMP "/var/log/wtmp"
+#define _PATH_DEFPATH "/bin:/usr/bin:/usr/local/bin:."
+#define _PATH_DEV "/dev/"
+#define _PATH_DEVNULL "/dev/null"
+#define _PATH_TMP "/tmp/"
+#define _PATH_LASTLOG "/var/log/lastlog"
+#define _PATH_LOCALE "/usr/lib/locale"
+
+#endif /* __PATHS_H */
diff --git a/libc/include/pwd.h b/libc/include/pwd.h
new file mode 100644
index 0000000..1b48c6a
--- /dev/null
+++ b/libc/include/pwd.h
@@ -0,0 +1,40 @@
+#ifndef __PWD_H
+#define __PWD_H
+
+#include <sys/types.h>
+#include <features.h>
+#include <stdio.h>
+
+/* The passwd structure. */
+struct passwd
+{
+ char *pw_name; /* Username. */
+ char *pw_passwd; /* Password. */
+ uid_t pw_uid; /* User ID. */
+ gid_t pw_gid; /* Group ID. */
+ char *pw_gecos; /* Real name. */
+ char *pw_dir; /* Home directory. */
+ char *pw_shell; /* Shell program. */
+};
+
+
+extern void setpwent __P ((void));
+extern void endpwent __P ((void));
+extern struct passwd * getpwent __P ((void));
+
+extern int putpwent __P ((__const struct passwd * __p, FILE * __f));
+extern int getpw __P ((uid_t uid, char *buf));
+
+extern struct passwd * fgetpwent __P ((FILE * file));
+
+extern struct passwd * getpwuid __P ((__const uid_t));
+extern struct passwd * getpwnam __P ((__const char *));
+
+#ifdef __LIBC__
+extern struct passwd * __getpwent __P ((__const int passwd_fd));
+#endif
+
+#endif /* pwd.h */
+
+
+
diff --git a/libc/include/regexp.h b/libc/include/regexp.h
new file mode 100644
index 0000000..73d6bf4
--- /dev/null
+++ b/libc/include/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/libc/include/regmagic.h b/libc/include/regmagic.h
new file mode 100644
index 0000000..5acf447
--- /dev/null
+++ b/libc/include/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/libc/include/search.h b/libc/include/search.h
new file mode 100644
index 0000000..b9c8a17
--- /dev/null
+++ b/libc/include/search.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 1993 Ulrich Drepper
+
+This file is intended to be included in the GNU C Library and the
+Linux C Library. So the copyright notice will be:
+
+
+Copyright (C) 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+
+For now the file can be distributed under the LGPL. */
+
+#ifndef _SEARCH_H
+#define _SEARCH_H
+
+#include <features.h>
+
+#define __need_size_t
+#define __need_NULL
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+#ifndef __COMPAR_FN_T
+#define __COMPAR_FN_T
+typedef int (*__compar_fn_t) __P ((__const __ptr_t, __const __ptr_t));
+#endif
+
+/* for use with hsearch(3) */
+
+typedef struct entry { char *key; char *data; } ENTRY;
+typedef enum { FIND, ENTER } ACTION;
+
+extern ENTRY * hsearch __P((ENTRY __item, ACTION __action));
+extern int hcreate __P((unsigned __nel));
+extern void hdestroy __P((void));
+
+
+/* The tsearch routines are very interesting. They make many
+ * assumptions about the compiler. It assumpts that the first field
+ * in node must be the "key" field, which points to the datum.
+ * Everything depends on that. It is a very tricky stuff. H.J.
+ */
+/* For tsearch */
+typedef enum { preorder, postorder, endorder, leaf } VISIT;
+
+extern void *tsearch __P((__const void * __key, void **__rootp,
+ __compar_fn_t compar));
+
+extern void *tfind __P((__const void * __key, __const void ** __rootp,
+ __compar_fn_t compar));
+
+extern void *tdelete __P((__const void * __key, void ** __rootp,
+ __compar_fn_t compar));
+
+#ifndef __ACTION_FN_T
+#define __ACTION_FN_T
+/* FYI, the first argument should be a pointer to "key".
+ * Please read the man page for details.
+ */
+typedef void (*__action_fn_t) __P((__const void *__nodep,
+ __const VISIT __value,
+ __const int __level));
+#endif
+
+extern void twalk __P((__const void * __root, __action_fn_t action));
+
+
+extern void * lfind __P((__const void * __key, __const void * __base,
+ size_t * __nmemb, size_t __size,
+ __compar_fn_t __compar));
+
+extern void * lsearch __P((__const void * __key, __const void * __base,
+ size_t * __nmemb, size_t __size,
+ __compar_fn_t __compar));
+
+__END_DECLS
+
+#endif /* search.h */
diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h
new file mode 100644
index 0000000..162743b
--- /dev/null
+++ b/libc/include/setjmp.h
@@ -0,0 +1,30 @@
+
+#ifndef __SETJMP_H
+#define __SETJMP_H
+
+#include <features.h>
+
+/*
+ * I know most systems use an array of ints here, but I prefer this - RDB
+ */
+
+typedef struct
+{
+ unsigned int pc;
+ unsigned int sp;
+ unsigned int bp;
+ unsigned int si;
+ unsigned int di;
+} jmp_buf[1];
+
+int _setjmp __P((jmp_buf env));
+void _longjmp __P((jmp_buf env, int rv));
+
+/* LATER: Seems GNU beat me to it, must be OK then :-)
+ * Humm, what's this about setjmp being a macro !?
+ * Ok, use the BSD names as normal use the ANSI as macros
+ */
+
+#define setjmp(a_env) _setjmp(a_env)
+#define longjmp(a_env, a_rv) _longjmp(a_env, a_rv)
+#endif
diff --git a/libc/include/signal.h b/libc/include/signal.h
new file mode 100644
index 0000000..1d54fc3
--- /dev/null
+++ b/libc/include/signal.h
@@ -0,0 +1,85 @@
+
+#ifndef __SIGNAL_H
+#define __SIGNAL_H
+#include <features.h>
+
+typedef unsigned long sigset_t; /* at least 32 bits */
+
+#define _NSIG 32
+#define NSIG _NSIG
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+/*
+#define SIGLOST 29
+*/
+#define SIGPWR 30
+#define SIGUNUSED 31
+
+/*
+ * sa_flags values: SA_STACK is not currently supported, but will allow the
+ * usage of signal stacks by using the (now obsolete) sa_restorer field in
+ * the sigaction structure as a stack pointer. This is now possible due to
+ * the changes in signal handling. LBT 010493.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ */
+#define SA_NOCLDSTOP 1
+#define SA_STACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_INTERRUPT 0x20000000
+#define SA_NOMASK 0x40000000
+#define SA_ONESHOT 0x80000000
+
+#define SIG_BLOCK 0 /* for blocking signals */
+#define SIG_UNBLOCK 1 /* for unblocking signals */
+#define SIG_SETMASK 2 /* for setting the signal mask */
+
+/* Type of a signal handler. */
+typedef void (*__sighandler_t)(/* int */);
+
+#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
+#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
+#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
+
+struct sigaction {
+ __sighandler_t sa_handler;
+ sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)( /*void*/ );
+};
+
+/* BSDisms */
+extern __const char * __const sys_siglist[];
+#define sig_t __sighandler_t
+
+#endif
diff --git a/libc/include/stdarg.h b/libc/include/stdarg.h
new file mode 100644
index 0000000..321e664
--- /dev/null
+++ b/libc/include/stdarg.h
@@ -0,0 +1,47 @@
+ /*
+ * @(#) stdarg.h 1.2 91/11/30 21:10:39
+ *
+ * Sample stdarg.h file for use with the unproto filter.
+ *
+ * This file serves two purposes.
+ *
+ * 1 - As an include file for use with ANSI-style C source that implements
+ * variadic functions.
+ *
+ * 2 - To configure the unproto filter itself. If the _VA_ALIST_ macro is
+ * defined, its value will appear in the place of the "..." in argument
+ * lists of variadic function *definitions* (not declarations).
+ *
+ * Compilers that pass arguments via the stack can use the default code at the
+ * end of this file (this usually applies for the VAX, MC68k and 80*86
+ * architectures).
+ *
+ * RISC-based systems often need special tricks. An example of the latter is
+ * given for the SPARC architecture. Read your /usr/include/varargs.h for
+ * more information.
+ *
+ * You can use the varargs.c program provided with the unproto package to
+ * verify that the stdarg.h file has been set up correctly.
+ */
+
+#ifndef __STDARG_H
+#define __STDARG_H
+
+#ifdef sparc
+# define _VA_ALIST_ "__builtin_va_alist"
+ typedef char *va_list;
+# define va_start(ap, p) (ap = (char *) &__builtin_va_alist)
+# define va_arg(ap, type) ((type *) __builtin_va_arg_incr((type *) ap))[0]
+# define va_end(ap)
+#else /* vax, mc68k, 80*86 */
+ typedef char *va_list;
+# define va_start(ap, p) (ap = (char *) (&(p)+1))
+# define va_arg(ap, type) ((type *) (ap += sizeof(type)))[-1]
+# define va_end(ap)
+#endif
+
+#endif /* __STDARG_H */
+
+#if __FIRST_ARG_IN_AX__
+#error First arg is in a register, stdarg.h cannot take its address
+#endif
diff --git a/libc/include/stddef.h b/libc/include/stddef.h
new file mode 100644
index 0000000..ce3cf2b
--- /dev/null
+++ b/libc/include/stddef.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+/* We don't care, ignore GCC's __need hackery */
+
+#undef __need_wchar_t
+#undef __need_size_t
+#undef __need_ptrdiff_t
+#undef __need_NULL
+
+/* Fact is these are _normal_ */
+#if 1 /* __BCC__ */ /* Only for Bcc 8086/80386 */
+
+#ifndef __STDDEF_H
+#define __STDDEF_H
+
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned int size_t;
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* __STDDEF_H */
+#endif /* __AS386_16__ */
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
new file mode 100644
index 0000000..98ca38a
--- /dev/null
+++ b/libc/include/stdio.h
@@ -0,0 +1,129 @@
+
+#ifndef __STDIO_H
+#define __STDIO_H
+
+#include <features.h>
+#include <sys/types.h>
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#define _IOFBF 0x00 /* full buffering */
+#define _IOLBF 0x01 /* line buffering */
+#define _IONBF 0x02 /* no buffering */
+#define __MODE_BUF 0x03 /* Modal buffering dependent on isatty */
+
+#define __MODE_FREEBUF 0x04 /* Buffer allocated with malloc, can free */
+#define __MODE_FREEFIL 0x08 /* FILE allocated with malloc, can free */
+
+#define __MODE_READ 0x10 /* Opened in read only */
+#define __MODE_WRITE 0x20 /* Opened in write only */
+#define __MODE_RDWR 0x30 /* Opened in read/write */
+
+#define __MODE_READING 0x40 /* Buffer has pending read data */
+#define __MODE_WRITING 0x80 /* Buffer has pending write data */
+
+#define __MODE_EOF 0x100 /* EOF status */
+#define __MODE_ERR 0x200 /* Error status */
+#define __MODE_UNGOT 0x400 /* Buffer has been polluted by ungetc */
+
+#ifdef __MSDOS__
+#define __MODE_IOTRAN 0x1000 /* MSDOS nl <-> cr,nl translation */
+#else
+#define __MODE_IOTRAN 0
+#endif
+
+/* when you add or change fields here, be sure to change the initialization
+ * in stdio_init and fopen */
+struct __stdio_file {
+ unsigned char *bufpos; /* the next byte to write to or read from */
+ unsigned char *bufread; /* the end of data returned by last read() */
+ unsigned char *bufwrite; /* highest address writable by macro */
+ unsigned char *bufstart; /* the start of the buffer */
+ unsigned char *bufend; /* the end of the buffer; ie the byte after the last
+ malloc()ed byte */
+
+ int fd; /* the file descriptor associated with the stream */
+ int mode;
+
+ char unbuf[8]; /* The buffer for 'unbuffered' streams */
+
+ struct __stdio_file * next;
+};
+
+#define EOF (-1)
+#ifndef NULL
+#define NULL (0)
+#endif
+
+typedef struct __stdio_file FILE;
+
+#ifdef __AS386_16__
+#define BUFSIZ (256)
+#else
+#define BUFSIZ (2048)
+#endif
+
+extern FILE stdin[1];
+extern FILE stdout[1];
+extern FILE stderr[1];
+
+#ifdef __MSDOS__
+#define putc(c, fp) fputc(c, fp)
+#define getc(fp) fgetc(fp)
+#else
+#define putc(c, stream) \
+ (((stream)->bufpos >= (stream)->bufwrite) ? fputc((c), (stream)) \
+ : (unsigned char) (*(stream)->bufpos++ = (c)) )
+
+#define getc(stream) \
+ (((stream)->bufpos >= (stream)->bufread) ? fgetc(stream): \
+ (*(stream)->bufpos++))
+#endif
+
+#define putchar(c) putc((c), stdout)
+#define getchar() getc(stdin)
+
+#define ferror(fp) (((fp)->mode&__MODE_ERR) != 0)
+#define feof(fp) (((fp)->mode&__MODE_EOF) != 0)
+#define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0)
+#define fileno(fp) ((fp)->fd)
+
+/* declare functions; not like it makes much difference without ANSI */
+/* RDB: The return values _are_ important, especially if we ever use
+ 8086 'large' model
+ */
+
+/* These two call malloc */
+#define setlinebuf(__fp) setvbuf((__fp), (char*)0, _IOLBF, 0)
+extern int setvbuf __P((FILE*, char*, int, size_t));
+
+/* These don't */
+#define setbuf(__fp, __buf) setbuffer((__fp), (__buf), BUFSIZ)
+extern void setbuffer __P((FILE*, char*, int));
+
+extern int fgetc __P((FILE*));
+extern int fputc __P((int, FILE*));
+
+extern int fclose __P((FILE*));
+extern int fflush __P((FILE*));
+extern char *fgets __P((char*, size_t, FILE*));
+extern FILE *__fopen __P((char*, int, FILE*, char*));
+
+#define fopen(__file, __mode) __fopen((__file), -1, (FILE*)0, (__mode))
+#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode))
+#define fdopen(__file, __mode) __fopen((char*)0, (__file), (FILE*)0, (__mode))
+
+extern int fputs __P((char*, FILE*));
+extern int puts __P((char*));
+
+extern int printf __P ((__const char*, ...));
+extern int fprintf __P ((FILE*, __const char*, ...));
+extern int sprintf __P ((char*, __const char*, ...));
+
+#define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos)
+
+#endif /* __STDIO_H */
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
new file mode 100644
index 0000000..7831424
--- /dev/null
+++ b/libc/include/stdlib.h
@@ -0,0 +1,46 @@
+/* stdlib.h <ndf@linux.mit.edu> */
+#include <features.h>
+#include <sys/types.h>
+
+#ifndef __STDLIB_H
+#define __STDLIB_H
+
+/* Don't overwrite user definitions of NULL */
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* For program termination */
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+
+extern void * malloc __P ((size_t));
+extern void * calloc __P ((size_t, size_t));
+extern void free __P ((void *));
+extern void * realloc __P ((void *, size_t));
+
+extern int rand __P ((void));
+extern void srand __P ((unsigned int seed));
+
+extern long strtol __P ((const char * nptr, char ** endptr, int base));
+extern unsigned long strtoul __P ((const char * nptr,
+ char ** endptr, int base));
+#ifndef __HAS_NO_FLOATS__
+extern double strtod __P ((const char * nptr, char ** endptr));
+#endif
+
+/* Returned by `div'. */
+typedef struct
+ {
+ int quot; /* Quotient. */
+ int rem; /* Remainder. */
+ } div_t;
+
+/* Returned by `ldiv'. */
+typedef struct
+ {
+ long int quot; /* Quotient. */
+ long int rem; /* Remainder. */
+ } ldiv_t;
+
+#endif /* __STDLIB_H */
diff --git a/libc/include/string.h b/libc/include/string.h
new file mode 100644
index 0000000..2233bf9
--- /dev/null
+++ b/libc/include/string.h
@@ -0,0 +1,53 @@
+
+#ifndef __STRING_H
+#define __STRING_H
+#include <features.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+/* Basic string functions */
+extern size_t strlen __P ((__const char* __str));
+
+extern char * strcat __P ((char*, __const char*));
+extern char * strcpy __P ((char*, __const char*));
+extern int strcmp __P ((__const char*, __const char*));
+
+extern char * strncat __P ((char*, char*, size_t));
+extern char * strncpy __P ((char*, char*, size_t));
+extern int strncmp __P ((__const char*, __const char*, size_t));
+
+extern char * strchr __P ((char*, int));
+extern char * strrchr __P ((char*, int));
+extern char * strdup __P ((char*));
+
+/* Basic mem functions */
+extern void * memcpy __P ((void*, __const void*, size_t));
+extern void * memccpy __P ((void*, void*, int, size_t));
+extern void * memchr __P ((__const void*, __const int, size_t));
+extern void * memset __P ((void*, int, size_t));
+extern int memcmp __P ((__const void*, __const void*, size_t));
+
+extern void * memmove __P ((void*, void*, size_t));
+
+/* Minimal (very!) locale support */
+#define strcoll strcmp
+#define strxfrm strncpy
+
+/* BSDisms */
+#define index strchr
+#define rindex strrchr
+
+/* Other common BSD functions */
+extern int strcasecmp __P ((char*, char*));
+extern int strncasecmp __P ((char*, char*, size_t));
+char *strpbrk __P ((char *, char *));
+char *strsep __P ((char **, char *));
+char *strstr __P ((char *, char *));
+char *strtok __P ((char *, char *));
+size_t strcspn __P ((char *, char *));
+size_t strspn __P ((char *, char *));
+
+/* Linux silly hour */
+char *strfry __P ((char *));
+
+#endif
diff --git a/libc/include/strings.h b/libc/include/strings.h
new file mode 100644
index 0000000..3b2f590
--- /dev/null
+++ b/libc/include/strings.h
@@ -0,0 +1 @@
+#include <string.h>
diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h
new file mode 100644
index 0000000..0afc883
--- /dev/null
+++ b/libc/include/sys/cdefs.h
@@ -0,0 +1,36 @@
+
+#ifndef __SYS_CDEFS_H
+#define __SYS_CDEFS_H
+#include <features.h>
+
+#if defined (__STDC__) && __STDC__
+
+#define __CONCAT(x,y) x ## y
+#define __STRING(x) #x
+
+/* This is not a typedef so `const __ptr_t' does the right thing. */
+#define __ptr_t void *
+typedef long double __long_double_t;
+
+#else
+
+#define __CONCAT(x,y) x/**/y
+#define __STRING(x) "x"
+
+#define __ptr_t char *
+
+#ifndef __HAS_NO_FLOATS__
+typedef double __long_double_t;
+#endif
+
+#endif
+
+/* No C++ */
+#define __BEGIN_DECLS
+#define __END_DECLS
+
+/* GNUish things */
+#define __CONSTVALUE
+#define __CONSTVALUE2
+
+#endif
diff --git a/libc/include/sys/errno.h b/libc/include/sys/errno.h
new file mode 100644
index 0000000..339f4fc
--- /dev/null
+++ b/libc/include/sys/errno.h
@@ -0,0 +1 @@
+#include <errno.h>
diff --git a/libc/include/sys/fcntl.h b/libc/include/sys/fcntl.h
new file mode 100644
index 0000000..cd30455
--- /dev/null
+++ b/libc/include/sys/fcntl.h
@@ -0,0 +1 @@
+#include <fcntl.h>
diff --git a/libc/include/sys/file.h b/libc/include/sys/file.h
new file mode 100644
index 0000000..2401b15
--- /dev/null
+++ b/libc/include/sys/file.h
@@ -0,0 +1,35 @@
+#ifndef _SYS_FILE_H
+#define _SYS_FILE_H
+
+#include <features.h>
+#include <fcntl.h>
+
+#ifndef L_SET
+
+#define L_SET 0 /* absolute offset */
+#define L_INCR 1 /* relative to current offset */
+#define L_XTND 2 /* relative to end of file */
+
+#endif
+
+#ifndef LOCK_SH
+
+/* Operations for the `flock' call. */
+#define LOCK_SH 1 /* Shared lock. */
+#define LOCK_EX 2 /* Exclusive lock. */
+#define LOCK_UN 8 /* Unlock. */
+
+/* Can be OR'd in to one of the above. */
+#define LOCK_NB 4 /* Don't block when locking. */
+
+#endif
+
+__BEGIN_DECLS
+
+/* Apply or remove an advisory lock, according to OPERATION,
+ on the file FD refers to. */
+extern int flock __P ((int __fd, int __operation));
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/sys/ioctl.h b/libc/include/sys/ioctl.h
new file mode 100644
index 0000000..55e5882
--- /dev/null
+++ b/libc/include/sys/ioctl.h
@@ -0,0 +1,9 @@
+
+#ifndef _SYS_IOCTL_H
+#define _SYS_IOCTL_H
+#include <features.h>
+#include <linuxmt/ioctl.h>
+
+extern int ioctl __P((int __fildes, int __cmd, ...));
+
+#endif
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libc/include/sys/mman.h
diff --git a/libc/include/sys/param.h b/libc/include/sys/param.h
new file mode 100644
index 0000000..1a31d1f
--- /dev/null
+++ b/libc/include/sys/param.h
@@ -0,0 +1,18 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#ifndef _PARAM_H
+#define _PARAM_H
+
+#include <limits.h>
+
+#ifndef NR_OPEN
+#define NR_OPEN 32
+#endif
+#ifndef NR_FILE
+#define NR_FILE 32
+#endif
+
+#endif
diff --git a/libc/include/sys/resource.h b/libc/include/sys/resource.h
new file mode 100644
index 0000000..19ed06f
--- /dev/null
+++ b/libc/include/sys/resource.h
@@ -0,0 +1,73 @@
+/*
+ * Resource control/accounting header file for linux-86
+ */
+
+#ifndef _SYS_RESOURCE_H
+#define _SYS_RESOURCE_H
+
+#include <features.h>
+#include <sys/time.h>
+#include <limits.h>
+
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN (-1)
+#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */
+
+struct rusage {
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
+ long ru_maxrss; /* maximum resident set size */
+ long ru_ixrss; /* integral shared memory size */
+ long ru_idrss; /* integral unshared data size */
+ long ru_isrss; /* integral unshared stack size */
+ long ru_minflt; /* page reclaims */
+ long ru_majflt; /* page faults */
+ long ru_nswap; /* swaps */
+ long ru_inblock; /* block input operations */
+ long ru_oublock; /* block output operations */
+ long ru_msgsnd; /* messages sent */
+ long ru_msgrcv; /* messages received */
+ long ru_nsignals; /* signals received */
+ long ru_nvcsw; /* voluntary context switches */
+ long ru_nivcsw; /* involuntary " */
+};
+
+#define RLIM_INFINITY ((long)(~0UL>>1))
+
+struct rlimit {
+ long rlim_cur;
+ long rlim_max;
+};
+
+#define PRIO_MIN (-20)
+#define PRIO_MAX 20
+
+#define PRIO_PROCESS 0
+#define PRIO_PGRP 1
+#define PRIO_USER 2
+
+#define RLIMIT_CPU 0 /* CPU time in ms */
+#define RLIMIT_FSIZE 1 /* Maximum filesize */
+#define RLIMIT_DATA 2 /* max data size */
+#define RLIMIT_STACK 3 /* max stack size */
+#define RLIMIT_CORE 4 /* max core file size */
+#define RLIMIT_RSS 5 /* max resident set size */
+#define RLIMIT_NPROC 6 /* max number of processes */
+#define RLIMIT_NOFILE 7 /* max number of open files */
+#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
+
+#define RLIM_NLIMITS 9
+
+extern int getrlimit __P ((int __resource,
+ struct rlimit *__rlp));
+extern int setrlimit __P ((int __resource,
+ __const struct rlimit *__rlp));
+
+extern int getpriority __P((int __which, int __who));
+extern int setpriority __P((int __which, int __who,
+ int __prio));
+
+extern int __getrusage __P ((int __who, struct rusage *__rusage));
+extern int getrusage __P ((int __who, struct rusage *__rusage));
+
+#endif /* _SYS_RESOURCE_H */
diff --git a/libc/include/sys/signal.h b/libc/include/sys/signal.h
new file mode 100644
index 0000000..2e602da
--- /dev/null
+++ b/libc/include/sys/signal.h
@@ -0,0 +1 @@
+#include <signal.h>
diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h
new file mode 100644
index 0000000..b1cf558
--- /dev/null
+++ b/libc/include/sys/stat.h
@@ -0,0 +1,64 @@
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <linuxmt/stat.h>
+#include <sys/types.h>
+#include <features.h>
+
+#ifdef __AS386_32__
+/* This is for Linux-386, ho hum, I wish BCC could compile the proper one */
+#define mknod __dv32_mknod
+#define stat __dv32_stat
+#define lstat __dv32_lstat
+#define fstat __dv32_fstat
+
+struct stat {
+ dev_t st_dev;
+ unsigned short __pad1;
+ ino_t st_ino;
+ umode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ unsigned short __pad2;
+ off_t st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ time_t st_atime;
+ unsigned long __unused1;
+ time_t st_mtime;
+ unsigned long __unused2;
+ time_t st_ctime;
+ unsigned long __unused3;
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+#endif
+
+#ifdef __AS386_16__
+struct stat
+{
+ dev_t st_dev;
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ off_t st_size;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+};
+#endif
+
+int stat __P((__const char * __path, struct stat * __statbuf));
+int lstat __P((__const char * __path, struct stat * __statbuf));
+int fstat __P((int __fd, struct stat * __statbuf));
+
+/* hysterical raisins */
+#define S_IREAD S_IRUSR /* read permission, owner */
+#define S_IWRITE S_IWUSR /* write permission, owner */
+#define S_IEXEC S_IXUSR /* execute/search permission, owner */
+#endif
diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h
new file mode 100644
index 0000000..91fd187
--- /dev/null
+++ b/libc/include/sys/time.h
@@ -0,0 +1 @@
+#include <time.h>
diff --git a/libc/include/sys/times.h b/libc/include/sys/times.h
new file mode 100644
index 0000000..b6defa8
--- /dev/null
+++ b/libc/include/sys/times.h
@@ -0,0 +1,21 @@
+#ifndef _SYS_TIMES_H
+#define _SYS_TIMES_H
+
+#include <features.h>
+#include <sys/types.h>
+#include <time.h>
+
+struct tms {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+};
+
+__BEGIN_DECLS
+
+extern clock_t times __P ((struct tms * __tp));
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h
new file mode 100644
index 0000000..7b7de09
--- /dev/null
+++ b/libc/include/sys/types.h
@@ -0,0 +1,2 @@
+#include <stddef.h>
+#include <linuxmt/types.h>
diff --git a/libc/include/sys/utsname.h b/libc/include/sys/utsname.h
new file mode 100644
index 0000000..0cbc37f
--- /dev/null
+++ b/libc/include/sys/utsname.h
@@ -0,0 +1,18 @@
+#ifndef __SYS_UTSNAME_H
+#define __SYS_UTSNAME_H
+
+#include <features.h>
+#include <sys/param.h>
+
+struct utsname {
+ char sysname[65];
+ char nodename[65];
+ char release[65];
+ char version[65];
+ char machine[65];
+ char domainname[65];
+};
+
+extern int uname __P ((struct utsname * __utsbuf));
+
+#endif
diff --git a/libc/include/sys/vm86.h b/libc/include/sys/vm86.h
new file mode 100644
index 0000000..851814e
--- /dev/null
+++ b/libc/include/sys/vm86.h
@@ -0,0 +1,125 @@
+#if !__AS386_16__
+
+#ifndef _SYS_VM86_H
+#define _SYS_VM86_H
+
+#include <features.h>
+#ifndef _LINUX_VM86_H
+#define _LINUX_VM86_H
+
+/*
+ * I'm guessing at the VIF/VIP flag usage, but hope that this is how
+ * the Pentium uses them. Linux will return from vm86 mode when both
+ * VIF and VIP is set.
+ *
+ * On a Pentium, we could probably optimize the virtual flags directly
+ * in the eflags register instead of doing it "by hand" in vflags...
+ *
+ * Linus
+ */
+
+#define TF_MASK 0x00000100
+#define IF_MASK 0x00000200
+#define IOPL_MASK 0x00003000
+#define NT_MASK 0x00004000
+#define VM_MASK 0x00020000
+#define AC_MASK 0x00040000
+#define VIF_MASK 0x00080000 /* virtual interrupt flag */
+#define VIP_MASK 0x00100000 /* virtual interrupt pending */
+#define ID_MASK 0x00200000
+
+#define BIOSSEG 0x0f000
+
+#define CPU_086 0
+#define CPU_186 1
+#define CPU_286 2
+#define CPU_386 3
+#define CPU_486 4
+#define CPU_586 5
+
+/*
+ * Return values for the 'vm86()' system call
+ */
+#define VM86_TYPE(retval) ((retval) & 0xff)
+#define VM86_ARG(retval) ((retval) >> 8)
+
+#define VM86_SIGNAL 0 /* return due to signal */
+#define VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
+#define VM86_INTx 2 /* int3/int x instruction (ARG = x) */
+#define VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
+
+/*
+ * This is the stack-layout when we have done a "SAVE_ALL" from vm86
+ * mode - the main change is that the old segment descriptors aren't
+ * useful any more and are forced to be zero by the kernel (and the
+ * hardware when a trap occurs), and the real segment descriptors are
+ * at the end of the structure. Look at ptrace.h to see the "normal"
+ * setup.
+ */
+
+struct vm86_regs {
+/*
+ * normal regs, with special meaning for the segment descriptors..
+ */
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ long __null_ds;
+ long __null_es;
+ long __null_fs;
+ long __null_gs;
+ long orig_eax;
+ long eip;
+ unsigned short cs, __csh;
+ long eflags;
+ long esp;
+ unsigned short ss, __ssh;
+/*
+ * these are specific to v86 mode:
+ */
+ unsigned short es, __esh;
+ unsigned short ds, __dsh;
+ unsigned short fs, __fsh;
+ unsigned short gs, __gsh;
+};
+
+struct revectored_struct {
+ unsigned long __map[8]; /* 256 bits */
+};
+
+struct vm86_struct {
+ struct vm86_regs regs;
+ unsigned long flags;
+ unsigned long screen_bitmap;
+ unsigned long cpu_type;
+ struct revectored_struct int_revectored;
+ struct revectored_struct int21_revectored;
+};
+
+/*
+ * flags masks
+ */
+#define VM86_SCREEN_BITMAP 0x0001
+
+#ifdef __KERNEL__
+
+void handle_vm86_fault(struct vm86_regs *, long);
+void handle_vm86_debug(struct vm86_regs *, long);
+
+#endif
+
+#endif
+
+__BEGIN_DECLS
+
+extern vm86(struct vm86_struct * __info);
+
+__END_DECLS
+
+#endif /*_SYS_VM86_H */
+
+#endif
diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h
new file mode 100644
index 0000000..566aac7
--- /dev/null
+++ b/libc/include/sys/wait.h
@@ -0,0 +1,77 @@
+
+#ifndef _SYS_WAIT_H
+#define _SYS_WAIT_H
+
+#include <features.h>
+
+/* Bits in the third argument to `waitpid'. */
+#define WNOHANG 1 /* Don't block waiting. */
+#define WUNTRACED 2 /* Report status of stopped children. */
+
+/* Everything extant so far uses these same bits. */
+/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
+#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
+
+/* If WIFSIGNALED(STATUS), the terminating signal. */
+#define WTERMSIG(status) ((status) & 0x7f)
+
+/* If WIFSTOPPED(STATUS), the signal that stopped the child. */
+#define WSTOPSIG(status) WEXITSTATUS(status)
+
+/* Nonzero if STATUS indicates normal termination. */
+#define WIFEXITED(status) (((status) & 0xff) == 0)
+
+/* Nonzero if STATUS indicates termination by a signal. */
+#define WIFSIGNALED(status) (((unsigned int)((status)-1) & 0xFFFF) < 0xFF)
+
+/* Nonzero if STATUS indicates the child is stopped. */
+#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+
+/* Nonzero if STATUS indicates the child dumped core. */
+#define WCOREDUMP(status) ((status) & 0200)
+
+/* Macros for constructing status values. */
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
+
+/* Wait for a child to die. When one does, put its status in *STAT_LOC
+ and return its process ID. For errors, return (pid_t) -1. */
+extern pid_t wait __P ((__WAIT_STATUS __stat_loc));
+
+/* Special values for the PID argument to `waitpid' and `wait4'. */
+#define WAIT_ANY (-1) /* Any process. */
+#define WAIT_MYPGRP 0 /* Any process in my process group. */
+
+/* Wait for a child matching PID to die.
+ If PID is greater than 0, match any process whose process ID is PID.
+ If PID is (pid_t) -1, match any process.
+ If PID is (pid_t) 0, match any process with the
+ same process group as the current process.
+ If PID is less than -1, match any process whose
+ process group is the absolute value of PID.
+ If the WNOHANG bit is set in OPTIONS, and that child
+ is not already dead, return (pid_t) 0. If successful,
+ return PID and store the dead child's status in STAT_LOC.
+ Return (pid_t) -1 for errors. If the WUNTRACED bit is
+ set in OPTIONS, return status for stopped children; otherwise don't. */
+
+extern pid_t waitpid __P ((pid_t __pid, int *__stat_loc,
+ int __options));
+
+/* This being here makes the prototypes valid whether or not
+ we have already included <sys/resource.h> to define `struct rusage'. */
+struct rusage;
+
+/* Wait for a child to exit. When one does, put its status in *STAT_LOC and
+ return its process ID. For errors return (pid_t) -1. If USAGE is not
+ nil, store information about the child's resource usage there. If the
+ WUNTRACED bit is set in OPTIONS, return status for stopped children;
+ otherwise don't. */
+extern pid_t wait3 __P ((__WAIT_STATUS __stat_loc,
+ int __options, struct rusage * __usage));
+
+/* PID is like waitpid. Other args are like wait3. */
+extern pid_t wait4 __P ((pid_t __pid, __WAIT_STATUS __stat_loc,
+ int __options, struct rusage *__usage));
+
+#endif /* sys/wait.h */
diff --git a/libc/include/termcap.h b/libc/include/termcap.h
new file mode 100644
index 0000000..a7ae37b
--- /dev/null
+++ b/libc/include/termcap.h
@@ -0,0 +1,21 @@
+
+#ifndef _TERMCAP_H
+#define _TERMCAP_H
+
+#include <features.h>
+#include <sys/types.h>
+
+extern char PC;
+extern char *UP;
+extern char *BC;
+extern int ospeed;
+
+extern int tgetent __P((char *, const char *));
+extern int tgetflag __P((const char *));
+extern int tgetnum __P((const char *));
+extern char *tgetstr __P((const char *, char **));
+
+extern int tputs __P((const char *, int, int (*)(int)));
+extern char *tgoto __P((const char *, int, int));
+
+#endif /* _TERMCAP_H */
diff --git a/libc/include/termio.h b/libc/include/termio.h
new file mode 100644
index 0000000..9e26956
--- /dev/null
+++ b/libc/include/termio.h
@@ -0,0 +1 @@
+#include <termios.h>
diff --git a/libc/include/termios.h b/libc/include/termios.h
new file mode 100644
index 0000000..604e654
--- /dev/null
+++ b/libc/include/termios.h
@@ -0,0 +1,24 @@
+#ifndef __TERMIOS_H
+#define __TERMIOS_H
+
+#include <features.h>
+#include <sys/types.h>
+#include <linuxmt/termios.h>
+
+extern speed_t cfgetispeed __P ((struct termios *__termios_p));
+extern speed_t cfgetospeed __P ((struct termios *__termios_p));
+extern int cfsetispeed __P ((struct termios *__termios_p, speed_t __speed));
+extern int cfsetospeed __P ((struct termios *__termios_p, speed_t __speed));
+
+extern void cfmakeraw __P ((struct termios *__t));
+
+extern int tcsetattr __P ((int __fd, int __opt, struct termios *__termios_p));
+extern int tcgetattr __P ((int __fildes, struct termios *__termios_p));
+extern int tcdrain __P ((int __fildes));
+extern int tcflow __P ((int __fildes, int __action));
+extern int tcflush __P ((int __fildes, int __queue_selector));
+extern int tcsendbreak __P ((int __fildes, int __duration));
+extern pid_t tcgetpgrp __P ((int __fildes));
+extern int tcsetpgrp __P ((int __fildes, pid_t __pgrp_id));
+
+#endif
diff --git a/libc/include/time.h b/libc/include/time.h
new file mode 100644
index 0000000..30ae4bc
--- /dev/null
+++ b/libc/include/time.h
@@ -0,0 +1,68 @@
+#ifndef __TIME_H
+#define __TIME_H
+
+#include <features.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
+#endif
+
+#define CLOCKS_PER_SEC 100
+#define CLK_TCK 100 /* That must be the same as HZ ???? */
+
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+
+struct tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+
+#define __isleap(year) \
+ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+extern char *tzname[2];
+extern int daylight;
+extern long int timezone;
+
+__BEGIN_DECLS
+
+extern int stime __P ((time_t* __tptr));
+
+extern clock_t clock __P ((void));
+extern time_t time __P ((time_t * __tp));
+#ifndef __HAS_NO_FLOATS__
+extern __CONSTVALUE double difftime __P ((time_t __time2,
+ time_t __time1)) __CONSTVALUE2;
+#endif
+extern time_t mktime __P ((struct tm * __tp));
+
+extern char * asctime __P ((__const struct tm * __tp));
+extern char * ctime __P ((__const time_t * __tp));
+extern size_t strftime __P ((char * __s, size_t __smax,
+ __const char * __fmt, __const struct tm * __tp));
+extern void tzset __P ((void));
+
+extern struct tm* gmtime __P ((__const time_t *__tp));
+extern struct tm* localtime __P ((__const time_t * __tp));
+
+__END_DECLS
+
+#endif
diff --git a/libc/include/unistd.h b/libc/include/unistd.h
new file mode 100644
index 0000000..c96f710
--- /dev/null
+++ b/libc/include/unistd.h
@@ -0,0 +1,37 @@
+/* unistd.h <ndf@linux.mit.edu> */
+#include <features.h>
+#include <sys/types.h>
+
+#ifndef __UNISTD_H
+#define __UNISTD_H
+
+#define STDIN_FILENO 0
+#define STDOUT_FILENO 1
+#define STDERR_FILENO 2
+
+extern int close __P ((int));
+extern size_t read __P ((int __fd, char * __buf, size_t __nbytes));
+extern size_t write __P ((int __fd, __const char * __buf, size_t __n));
+extern off_t lseek __P ((int __fd, off_t __n, int __whence));
+extern int pipe __P ((int __pipedes[2]));
+extern unsigned int alarm __P ((unsigned int __seconds));
+extern unsigned int sleep __P ((unsigned int __seconds));
+extern int pause __P ((void));
+extern char* crypt __P((__const char *__key, __const char *__salt));
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#ifndef R_OK
+#define R_OK 4 /* Test for read permission. */
+#define W_OK 2 /* Test for write permission. */
+#define X_OK 1 /* Test for execute permission. */
+#define F_OK 0 /* Test for existence. */
+#endif
+
+#endif /* __UNISTD_H */
+
+
diff --git a/libc/include/utime.h b/libc/include/utime.h
new file mode 100644
index 0000000..7f82b9f
--- /dev/null
+++ b/libc/include/utime.h
@@ -0,0 +1,15 @@
+#ifndef __UTIME_H
+#define __UTIME_H
+
+#include <features.h>
+#include <sys/types.h>
+
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+
+extern int utime __P ((char *__filename, struct utimbuf *__utimebuf));
+
+#endif
+
diff --git a/libc/include/utmp.h b/libc/include/utmp.h
new file mode 100644
index 0000000..9fe0e87
--- /dev/null
+++ b/libc/include/utmp.h
@@ -0,0 +1,52 @@
+/* utmp.h */
+
+#ifndef __UTMP_H
+#define __UTMP_H
+
+#include <features.h>
+#include <sys/types.h>
+#include <paths.h>
+#include <time.h>
+
+#define UT_UNKNOWN 0
+#define UT_LINESIZE 12
+#define UT_NAMESIZE 8
+#define UT_HOSTSIZE 16
+
+#define RUN_LVL 1
+#define BOOT_TIME 2
+#define NEW_TIME 3
+#define OLD_TIME 4
+
+#define INIT_PROCESS 5
+#define LOGIN_PROCESS 6
+#define USER_PROCESS 7
+#define DEAD_PROCESS 8
+
+struct utmp
+{
+ short ut_type; /* type of login */
+ pid_t ut_pid; /* pid of login-process */
+ char ut_line[UT_LINESIZE]; /* devicename of tty -"/dev/", null-term */
+ char ut_id[2]; /* abbrev. ttyname, as 01, s1 etc. */
+ time_t ut_time; /* login time */
+ char ut_user[UT_NAMESIZE]; /* username, not null-term */
+ char ut_host[UT_HOSTSIZE]; /* hostname for remote login... */
+ long ut_addr; /* IP addr of remote host */
+
+};
+
+extern void setutent __P ((void));
+extern void utmpname __P ((__const char *));
+extern struct utmp * getutent __P ((void));
+extern struct utmp * getutid __P ((struct utmp *));
+extern struct utmp * getutline __P ((struct utmp *));
+extern struct utmp * pututline __P ((struct utmp *));
+extern void endutent __P ((void));
+
+#ifdef __LIBC__
+struct utmp * __getutent __P ((int));
+#endif
+
+#endif /* __UTMP_H */
+
diff --git a/libc/include/varargs.h b/libc/include/varargs.h
new file mode 100644
index 0000000..b5c647f
--- /dev/null
+++ b/libc/include/varargs.h
@@ -0,0 +1,12 @@
+
+#ifndef __VARARGS_H
+#define __VARARGS_H
+
+typedef char *va_list;
+
+#define va_dcl va_list va_alist;
+#define va_start(ap) ap = (va_list)&va_alist
+#define va_arg(ap,t) ((t *)(ap += sizeof(t)))[-1]
+#define va_end(ap) ap = NULL
+
+#endif
diff --git a/libc/kinclude/Config b/libc/kinclude/Config
new file mode 100644
index 0000000..f3d064f
--- /dev/null
+++ b/libc/kinclude/Config
@@ -0,0 +1 @@
+kinc: The kernel include files
diff --git a/libc/kinclude/Makefile b/libc/kinclude/Makefile
new file mode 100644
index 0000000..aa4ef72
--- /dev/null
+++ b/libc/kinclude/Makefile
@@ -0,0 +1,21 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+all:
+ @:
+
+transfer:
+ -@rm -f ../include/linuxmt
+ ln -s ../kinclude/linuxmt ../include
+ @touch Used
+
+# This is for use once linuxmt's syscall interface really gets working.
+# beware the arch directory must be removed when you do this.
+real_transfer:
+ -@rm -f ../include/linuxmt
+ cd ../include ; ln -s ../../linuxmt/include/linuxmt .
+
+clean:
+ -@rm -f ../include/linuxmt
+ -@rm -f Used
diff --git a/libc/kinclude/arch/errno.h b/libc/kinclude/arch/errno.h
new file mode 100644
index 0000000..ee3fcab
--- /dev/null
+++ b/libc/kinclude/arch/errno.h
@@ -0,0 +1,127 @@
+#ifndef _I86_ERRNO_H
+#define _I86_ERRNO_H
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Arg list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define EDEADLK 35 /* Resource deadlock would occur */
+#define ENAMETOOLONG 36 /* File name too long */
+#define ENOLCK 37 /* No record locks available */
+#define ENOSYS 38 /* Function not implemented */
+#define ENOTEMPTY 39 /* Directory not empty */
+#define ELOOP 40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define ENOMSG 42 /* No message of desired type */
+#define EIDRM 43 /* Identifier removed */
+#define ECHRNG 44 /* Channel number out of range */
+#define EL2NSYNC 45 /* Level 2 not synchronized */
+#define EL3HLT 46 /* Level 3 halted */
+#define EL3RST 47 /* Level 3 reset */
+#define ELNRNG 48 /* Link number out of range */
+#define EUNATCH 49 /* Protocol driver not attached */
+#define ENOCSI 50 /* No CSI structure available */
+#define EL2HLT 51 /* Level 2 halted */
+#define EBADE 52 /* Invalid exchange */
+#define EBADR 53 /* Invalid request descriptor */
+#define EXFULL 54 /* Exchange full */
+#define ENOANO 55 /* No anode */
+#define EBADRQC 56 /* Invalid request code */
+#define EBADSLT 57 /* Invalid slot */
+#define EDEADLOCK 58 /* File locking deadlock error */
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EMULTIHOP 72 /* Multihop attempted */
+#define EDOTDOT 73 /* RFS specific error */
+#define EBADMSG 74 /* Not a data message */
+#define EOVERFLOW 75 /* Value too large for defined data type */
+#define ENOTUNIQ 76 /* Name not unique on network */
+#define EBADFD 77 /* File descriptor in bad state */
+#define EREMCHG 78 /* Remote address changed */
+#define ELIBACC 79 /* Can not access a needed shared library */
+#define ELIBBAD 80 /* Accessing a corrupted shared library */
+#define ELIBSCN 81 /* .lib section in a.out corrupted */
+#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 83 /* Cannot exec a shared library directly */
+#define EILSEQ 84 /* Illegal byte sequence */
+#define ERESTART 85 /* Interrupted system call should be restarted */
+#define ESTRPIPE 86 /* Streams pipe error */
+#define EUSERS 87 /* Too many users */
+#define ENOTSOCK 88 /* Socket operation on non-socket */
+#define EDESTADDRREQ 89 /* Destination address required */
+#define EMSGSIZE 90 /* Message too long */
+#define EPROTOTYPE 91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 96 /* Protocol family not supported */
+#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
+#define EADDRINUSE 98 /* Address already in use */
+#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
+#define ENETDOWN 100 /* Network is down */
+#define ENETUNREACH 101 /* Network is unreachable */
+#define ENETRESET 102 /* Network dropped connection because of reset */
+#define ECONNABORTED 103 /* Software caused connection abort */
+#define ECONNRESET 104 /* Connection reset by peer */
+#define ENOBUFS 105 /* No buffer space available */
+#define EISCONN 106 /* Transport endpoint is already connected */
+#define ENOTCONN 107 /* Transport endpoint is not connected */
+#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 109 /* Too many references: cannot splice */
+#define ETIMEDOUT 110 /* Connection timed out */
+#define ECONNREFUSED 111 /* Connection refused */
+#define EHOSTDOWN 112 /* Host is down */
+#define EHOSTUNREACH 113 /* No route to host */
+#define EALREADY 114 /* Operation already in progress */
+#define EINPROGRESS 115 /* Operation now in progress */
+#define ESTALE 116 /* Stale NFS file handle */
+#define EUCLEAN 117 /* Structure needs cleaning */
+#define ENOTNAM 118 /* Not a XENIX named type file */
+#define ENAVAIL 119 /* No XENIX semaphores available */
+#define EISNAM 120 /* Is a named type file */
+#define EREMOTEIO 121 /* Remote I/O error */
+#define EDQUOT 122 /* Quota exceeded */
+
+#endif
diff --git a/libc/kinclude/arch/ioctl.h b/libc/kinclude/arch/ioctl.h
new file mode 100644
index 0000000..55b276b
--- /dev/null
+++ b/libc/kinclude/arch/ioctl.h
@@ -0,0 +1,9 @@
+/*
+ * Nothing here yet.
+ */
+
+#ifndef _ASMI86_IOCTL_H
+#define _ASMI86_IOCTL_H
+
+
+#endif /* _ASMI86_IOCTL_H */
diff --git a/libc/kinclude/arch/types.h b/libc/kinclude/arch/types.h
new file mode 100644
index 0000000..00afeed
--- /dev/null
+++ b/libc/kinclude/arch/types.h
@@ -0,0 +1,48 @@
+/* arch/i86/include/asm/types.h - Basic Linux/MT data types. */
+
+#ifndef __LINUXMT_8086_TYPES
+#define __LINUXMT_8086_TYPES
+
+/* First we define all of the __u and __s types...*/
+
+typedef unsigned char __u8;
+typedef unsigned char * __pu8;
+typedef char __s8;
+typedef char * __ps8;
+
+typedef unsigned short __u16;
+typedef unsigned short * __pu16;
+typedef short __s16;
+typedef short * __ps16;
+
+typedef unsigned long __u32;
+typedef unsigned long * __pu32;
+typedef long __s32;
+typedef long * __ps32;
+
+/* __uint == 16bit here */
+
+typedef unsigned int __uint;
+typedef int __sint;
+typedef unsigned int * __puint;
+typedef int * __psint;
+
+/* Then we define registers, etc... */
+
+struct _registers {
+ __u16 ksp, sp, ss, ax, bx, cx, dx, di, si, ds, es, bp, ip, cs, flags;
+};
+
+typedef struct _registers __registers;
+typedef struct _registers * __pregisters;
+
+typedef __u32 __pptr;
+
+struct _mminit {
+ __u16 cs, endcs, ds, endds, ss, endss, lowss;
+};
+
+typedef struct _mminit __arch_mminit;
+typedef struct _mminit * __parch_mminit;
+
+#endif
diff --git a/libc/kinclude/linuxmt/errno.h b/libc/kinclude/linuxmt/errno.h
new file mode 100644
index 0000000..b4c07a3
--- /dev/null
+++ b/libc/kinclude/linuxmt/errno.h
@@ -0,0 +1 @@
+#include "../arch/errno.h"
diff --git a/libc/kinclude/linuxmt/fcntl.h b/libc/kinclude/linuxmt/fcntl.h
new file mode 100644
index 0000000..d9188a1
--- /dev/null
+++ b/libc/kinclude/linuxmt/fcntl.h
@@ -0,0 +1,70 @@
+#ifndef __LINUXMT_FCNTL_H
+#define __LINUXMT_FCNTL_H
+
+/*
+ * Definitions taken from the i386 Linux kernel.
+ */
+
+/* open/fcntl */
+
+#define O_ACCMODE 0003
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDWR 02
+#define O_CREAT 0100 /* not fcntl */
+#define O_EXCL 0200 /* not fcntl */
+#define O_NOCTTY 0400 /* not fcntl */
+#define O_TRUNC 01000 /* not fcntl */
+#define O_APPEND 02000
+#define O_NONBLOCK 04000
+#define O_NDELAY O_NONBLOCK
+#if 0
+#define O_SYNC 010000 /* Not supported */
+#define FASYNC 020000 /* Not supported */
+#endif
+
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get f_flags */
+#define F_SETFD 2 /* set f_flags */
+#define F_GETFL 3 /* more flags (cloexec) */
+#define F_SETFL 4
+#define F_GETLK 5
+#define F_SETLK 6
+#define F_SETLKW 7
+
+#define F_SETOWN 8 /* for sockets. */
+#define F_GETOWN 9 /* for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK 4 /* or 3 */
+#define F_SHLCK 8 /* or 4 */
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* or'd with one of the above to prevent
+ blocking */
+#define LOCK_UN 8 /* remove lock */
+
+#ifdef __KERNEL__
+#define F_POSIX 1
+#define F_FLOCK 2
+#endif /* __KERNEL__ */
+
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
+
+#endif
diff --git a/libc/kinclude/linuxmt/ioctl.h b/libc/kinclude/linuxmt/ioctl.h
new file mode 100644
index 0000000..20f5ac6
--- /dev/null
+++ b/libc/kinclude/linuxmt/ioctl.h
@@ -0,0 +1 @@
+#include "../arch/ioctl.h"
diff --git a/libc/kinclude/linuxmt/stat.h b/libc/kinclude/linuxmt/stat.h
new file mode 100644
index 0000000..9fbd191
--- /dev/null
+++ b/libc/kinclude/linuxmt/stat.h
@@ -0,0 +1,57 @@
+#ifndef __LINUXMT_STAT_H
+#define __LINUXMT_STAT_H
+
+#ifdef __KERNEL__
+
+#include "../arch/stat.h"
+
+#endif
+
+#define S_IFMT 00170000
+#ifdef __LINUXMT_NETWORK__
+#define S_IFSOCK 0140000
+#endif
+#define S_IFLNK 0120000
+#define S_IFREG 0100000
+#define S_IFBLK 0060000
+#define S_IFDIR 0040000
+#define S_IFCHR 0020000
+#define S_IFIFO 0010000
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+#ifdef __LINUXMT_NETWORK__
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#endif
+
+#define S_IRWXU 00700
+#define S_IRUSR 00400
+#define S_IWUSR 00200
+#define S_IXUSR 00100
+
+#define S_IRWXG 00070
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+
+#define S_IRWXO 00007
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+
+#ifdef __KERNEL__
+#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
+#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
+#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
+#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
+#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+#endif
+
+#endif
diff --git a/libc/kinclude/linuxmt/termios.h b/libc/kinclude/linuxmt/termios.h
new file mode 100644
index 0000000..2aff58a
--- /dev/null
+++ b/libc/kinclude/linuxmt/termios.h
@@ -0,0 +1,260 @@
+#ifndef __LINUXMT_TERMIOS_H
+#define __LINUXMT_TERMIOS_H
+#include <linuxmt/types.h>
+
+/* This is just a magic number to make these relatively unique ('T') */
+#define __TERMIOS_MAJ ('T'<<8)
+
+#define TCGETS (__TERMIOS_MAJ+0x01)
+#define TCSETS (__TERMIOS_MAJ+0x02)
+#define TCSETSW (__TERMIOS_MAJ+0x03)
+#define TCSETSF (__TERMIOS_MAJ+0x04)
+#define TCGETA (__TERMIOS_MAJ+0x05)
+#define TCSETA (__TERMIOS_MAJ+0x06)
+#define TCSETAW (__TERMIOS_MAJ+0x07)
+#define TCSETAF (__TERMIOS_MAJ+0x08)
+#define TCSBRK (__TERMIOS_MAJ+0x09)
+#define TCXONC (__TERMIOS_MAJ+0x0A)
+#define TCFLSH (__TERMIOS_MAJ+0x0B)
+#define TIOCEXCL (__TERMIOS_MAJ+0x0C)
+#define TIOCNXCL (__TERMIOS_MAJ+0x0D)
+#define TIOCSCTTY (__TERMIOS_MAJ+0x0E)
+#define TIOCGPGRP (__TERMIOS_MAJ+0x0F)
+#define TIOCSPGRP (__TERMIOS_MAJ+0x10)
+#define TIOCOUTQ (__TERMIOS_MAJ+0x11)
+#define TIOCSTI (__TERMIOS_MAJ+0x12)
+#define TIOCGWINSZ (__TERMIOS_MAJ+0x13)
+#define TIOCSWINSZ (__TERMIOS_MAJ+0x14)
+#define TIOCMGET (__TERMIOS_MAJ+0x15)
+#define TIOCMBIS (__TERMIOS_MAJ+0x16)
+#define TIOCMBIC (__TERMIOS_MAJ+0x17)
+#define TIOCMSET (__TERMIOS_MAJ+0x18)
+#define TIOCGSOFTCAR (__TERMIOS_MAJ+0x19)
+#define TIOCSSOFTCAR (__TERMIOS_MAJ+0x1A)
+#define FIONREAD (__TERMIOS_MAJ+0x1B)
+#define TIOCINQ FIONREAD
+#define TIOCLINUX (__TERMIOS_MAJ+0x1C)
+#define TIOCCONS (__TERMIOS_MAJ+0x1D)
+#define TIOCGSERIAL (__TERMIOS_MAJ+0x1E)
+#define TIOCSSERIAL (__TERMIOS_MAJ+0x1F)
+#define TIOCPKT (__TERMIOS_MAJ+0x20)
+#define FIONBIO (__TERMIOS_MAJ+0x21)
+#define TIOCNOTTY (__TERMIOS_MAJ+0x22)
+#define TIOCSETD (__TERMIOS_MAJ+0x23)
+#define TIOCGETD (__TERMIOS_MAJ+0x24)
+#define TCSBRKP (__TERMIOS_MAJ+0x25) /* Needed for POSIX tcsendbreak */
+#define TIOCTTYGSTRUCT (__TERMIOS_MAJ+0x26) /* For debugging only */
+#define FIONCLEX (__TERMIOS_MAJ+0x50) /* these numbers need to be adjusted. */
+#define FIOCLEX (__TERMIOS_MAJ+0x51)
+#define FIOASYNC (__TERMIOS_MAJ+0x52)
+#define TIOCSERCONFIG (__TERMIOS_MAJ+0x53)
+#define TIOCSERGWILD (__TERMIOS_MAJ+0x54)
+#define TIOCSERSWILD (__TERMIOS_MAJ+0x55)
+#define TIOCGLCKTRMIOS (__TERMIOS_MAJ+0x56)
+#define TIOCSLCKTRMIOS (__TERMIOS_MAJ+0x57)
+#define TIOCSERGSTRUCT (__TERMIOS_MAJ+0x58) /* For debugging only */
+#define TIOCSERGETLSR (__TERMIOS_MAJ+0x59) /* Get line status register */
+#define TIOCSERGETMULTI (__TERMIOS_MAJ+0x5A) /* Get multiport config */
+#define TIOCSERSETMULTI (__TERMIOS_MAJ+0x5B) /* Set multiport config */
+
+/* Used for packet mode */
+#define TIOCPKT_DATA 0
+#define TIOCPKT_FLUSHREAD 1
+#define TIOCPKT_FLUSHWRITE 2
+#define TIOCPKT_STOP 4
+#define TIOCPKT_START 8
+#define TIOCPKT_NOSTOP 16
+#define TIOCPKT_DOSTOP 32
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+#define NCCS 19
+struct termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK 0000020
+#define ISTRIP 0000040
+#define INLCR 0000100
+#define IGNCR 0000200
+#define ICRNL 0000400
+#define IUCLC 0001000
+#define IXON 0002000
+#define IXANY 0004000
+#define IXOFF 0010000
+#define IMAXBEL 0020000
+
+/* c_oflag bits */
+#define OPOST 0000001
+#define OLCUC 0000002
+#define ONLCR 0000004
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#define NLDLY 0000400
+#define NL0 0000000
+#define NL1 0000400
+#define CRDLY 0003000
+#define CR0 0000000
+#define CR1 0001000
+#define CR2 0002000
+#define CR3 0003000
+#define TABDLY 0014000
+#define TAB0 0000000
+#define TAB1 0004000
+#define TAB2 0010000
+#define TAB3 0014000
+#define XTABS 0014000
+#define BSDLY 0020000
+#define BS0 0000000
+#define BS1 0020000
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+#define FFDLY 0100000
+#define FF0 0000000
+#define FF1 0100000
+
+/* c_cflag bit meaning */
+#define CBAUD 0010017
+#define B0 0000000 /* hang up */
+#define B50 0000001
+#define B75 0000002
+#define B110 0000003
+#define B134 0000004
+#define B150 0000005
+#define B200 0000006
+#define B300 0000007
+#define B600 0000010
+#define B1200 0000011
+#define B1800 0000012
+#define B2400 0000013
+#define B4800 0000014
+#define B9600 0000015
+#define B19200 0000016
+#define B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE 0000060
+#define CS5 0000000
+#define CS6 0000020
+#define CS7 0000040
+#define CS8 0000060
+#define CSTOPB 0000100
+#define CREAD 0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL 0002000
+#define CLOCAL 0004000
+#define CBAUDEX 0010000
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* modem lines */
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+
+
+/* tcflow() and TCXONC use these */
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+/* line disciplines */
+#define N_TTY 0
+#define N_SLIP 1
+#define N_MOUSE 2
+#define N_PPP 3
+
+#define _POSIX_VDISABLE '\0'
+
+#endif /* __LINUXMT_TERMIOS_H */
diff --git a/libc/kinclude/linuxmt/types.h b/libc/kinclude/linuxmt/types.h
new file mode 100644
index 0000000..8e5236a
--- /dev/null
+++ b/libc/kinclude/linuxmt/types.h
@@ -0,0 +1,34 @@
+#ifndef __LINUXMT_TYPES_H
+#define __LINUXMT_TYPES_H
+
+#include "../arch/types.h"
+
+/* Throw away _FUNCTION parameters - the syntax is ripped off of Minix's
+ _PROTOTYPE. Considering Borland did the same thing to MFC on a bigger
+ scale, I don't think PH will mind :) */
+
+/* Yes, this should be in arch/types.h too */
+
+#define _FUNCTION(function, params) function()
+#define _VFUNCTION(functiom, params) (*function) ()
+
+typedef __u32 off_t;
+typedef __u16 pid_t;
+typedef __u16 uid_t;
+typedef __u16 gid_t;
+typedef __u32 time_t;
+typedef __u16 umode_t;
+typedef __u16 nlink_t;
+typedef __u16 mode_t;
+typedef __u32 loff_t;
+typedef __u32 speed_t;
+
+typedef __u16 dev_t;
+typedef __uint ino_t;
+typedef __u32 tcflag_t;
+typedef __u8 cc_t;
+
+typedef int ptrdiff_t;
+
+#endif
+
diff --git a/libc/malloc1/Config b/libc/malloc1/Config
new file mode 100644
index 0000000..4404398
--- /dev/null
+++ b/libc/malloc1/Config
@@ -0,0 +1 @@
+malloc: Robert's malloc routines
diff --git a/libc/malloc1/Makefile b/libc/malloc1/Makefile
new file mode 100644
index 0000000..a4107b8
--- /dev/null
+++ b/libc/malloc1/Makefile
@@ -0,0 +1,23 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+ASRC=malloc.c
+AOBJ=malloc.o alloca.o free.o calloc.o realloc.o
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)($(AOBJ))
+ @:
+
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+clean:
+ rm -f *.o libc.a
+
+transfer:
+ -@rm ../include/malloc.h
+ cp -p malloc.h ../include/.
diff --git a/libc/malloc1/README b/libc/malloc1/README
new file mode 100644
index 0000000..95f5928
--- /dev/null
+++ b/libc/malloc1/README
@@ -0,0 +1,9 @@
+Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+This file is part of the Linux-8086 C library and is distributed
+under the GNU Library General Public License.
+
+This is a combined alloca/malloc package. It uses a classic algorithm
+and so may be seen to be quite slow compared to more modern routines
+with 'nasty' distributions of allocation.
+
+-Robert
diff --git a/libc/malloc1/malloc.c b/libc/malloc1/malloc.c
new file mode 100644
index 0000000..86ffd42
--- /dev/null
+++ b/libc/malloc1/malloc.c
@@ -0,0 +1,546 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/*
+ * This is a combined alloca/malloc package. It uses a classic algorithm
+ * and so may be seen to be quite slow compared to more modern routines
+ * with 'nasty' distributions.
+ */
+
+#include <malloc.h>
+#include <errno.h>
+
+#define MCHUNK 2048 /* Allocation unit in 'mem' elements */
+#define XLAZY_FREE /* If set frees can be infinitly defered */
+#define XMINALLOC 32 /* Smallest chunk to alloc in 'mem's */
+#define XVERBOSE /* Lots of noise, debuging ? */
+
+#undef malloc
+#define MAX_INT ((int)(((unsigned)-1)>>1))
+
+#ifdef VERBOSE
+#define noise __noise
+#else
+#define noise(y,x)
+#endif
+
+typedef union mem_cell
+{
+ union mem_cell *next; /* A pointer to the next mem */
+ unsigned int size; /* An int >= sizeof pointer */
+ char *depth; /* For the alloca hack */
+}
+mem;
+
+#define m_size(p) ((p) [0].size) /* For malloc */
+#define m_next(p) ((p) [1].next) /* For malloc and alloca */
+#define m_deep(p) ((p) [0].depth) /* For alloca */
+
+extern void *__mini_malloc __P ((size_t));
+extern void *(*__alloca_alloc) __P ((size_t));
+extern mem *__freed_list;
+
+#ifdef L_free
+/* Start the alloca with just the dumb version of malloc */
+
+void *(*__alloca_alloc) __P ((size_t)) = __mini_malloc;
+mem *__freed_list = 0;
+
+#ifdef VERBOSE
+/* NB: Careful here, stdio may use malloc - so we can't */
+static
+phex(val)
+{
+ static char hex[] = "0123456789ABCDEF";
+ int i;
+ for (i = sizeof(int)*8-4; i >= 0; i -= 4)
+ write(2, hex + ((val >> i) & 0xF), 1);
+}
+
+noise(y, x)
+char *y;
+mem *x;
+{
+ write(2, "Malloc ", 7);
+ phex(x);
+ write(2, " sz ", 4);
+ if(x) phex(m_size(x)); else phex(0);
+ write(2, " nxt ", 5);
+ if(x) phex(m_next(x)); else phex(0);
+ write(2, " is ", 4);
+ write(2, y, strlen(y));
+ write(2, "\n", 1);
+}
+#endif
+
+#endif
+
+#ifdef L_alloca
+static mem *alloca_stack = 0;
+
+void *
+alloca(size)
+size_t size;
+{
+ auto char probe; /* Probes stack depth: */
+ register mem *hp;
+
+ /*
+ * Reclaim garbage, defined as all alloca'd storage that was allocated
+ * from deeper in the stack than currently.
+ */
+
+ for (hp = alloca_stack; hp != 0;)
+ if (m_deep(hp) < &probe)
+ {
+ register mem *np = m_next(hp);
+ free((void *) hp); /* Collect garbage. */
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ alloca_stack = hp; /* -> last valid storage. */
+ if (size == 0)
+ return 0; /* No allocation required. */
+
+ hp = (mem *) (*__alloca_alloc) (sizeof(mem)*2 + size);
+ if (hp == 0)
+ return hp;
+
+ m_next(hp) = alloca_stack;
+ m_deep(hp) = &probe;
+ alloca_stack = hp;
+
+ /* User storage begins just after header. */
+ return (void *) (hp + 2);
+}
+#endif /* L_alloca */
+
+#ifdef L_free
+void
+free(ptr)
+void *ptr;
+{
+ register mem *top;
+ register mem *chk = (mem *) ptr;
+
+ if (chk == 0)
+ return; /* free(NULL) - be nice */
+ chk--;
+
+ try_this:;
+ top = (mem *) sbrk(0);
+ if (chk + m_size(chk) == top)
+ {
+ noise("FREE brk", chk);
+ brk(top-m_size(chk));
+ /*
+ * Adding this code allow free to release blocks in any order; they
+ * can still only be allocated from the top of the heap tho.
+ */
+#ifdef __MINI_MALLOC__
+ if (__alloca_alloc == __mini_malloc && __freed_list)
+ {
+ mem *prev, *curr;
+ chk = __freed_list;
+ __freed_list = m_next(__freed_list);
+ goto try_this;
+ }
+#endif
+ }
+ else
+ { /* Nope, not sure where this goes, leave
+ * it for malloc to deal with */
+#ifdef __MINI_MALLOC__
+ if( __freed_list || chk > __freed_list )
+ { m_next(chk) = __freed_list; __freed_list = chk; }
+ else
+ {
+ register mem *prev;
+ prev=__freed_list;
+ for(top=__freed_list; top && top > chk; prev=top, top=m_next(top))
+ ;
+ m_next(chk) = top;
+ m_next(prev) = chk;
+ }
+#else
+ m_next(chk) = __freed_list;
+ __freed_list = chk;
+#endif
+ noise("ADD LIST", chk);
+ }
+}
+
+void *
+__mini_malloc(size)
+size_t size;
+{
+ register mem *ptr;
+ register unsigned int sz;
+
+ /* First time round this _might_ be odd, But we won't do that! */
+ sz = (unsigned int) sbrk(0);
+ if (sz & (sizeof(mem) - 1))
+ sbrk(4 - (sz & (sizeof(mem) - 1)));
+
+ if (size <= 0)
+ return 0;
+ /* Minor oops here, sbrk has a signed argument */
+ if( size > (((unsigned)-1)>>1)-sizeof(mem)*3 )
+ {
+ errno = ENOMEM;
+ return 0;
+ }
+
+ size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */
+ size /= sizeof(mem);
+
+ ptr = (mem *) sbrk(size * sizeof(mem));
+ if ((int) ptr == -1)
+ return 0;
+
+ m_size(ptr) = size;
+ noise("CREATE", ptr);
+ return ptr + 1;
+}
+#endif /* L_free */
+
+#ifdef L_malloc
+
+/*
+ * The chunk_list pointer is either NULL or points to a chunk in a
+ * circular list of all the free blocks in memory
+ */
+
+#define Static static
+
+static mem *chunk_list = 0;
+Static void __insert_chunk();
+Static mem *__search_chunk();
+
+void *
+malloc(size)
+size_t size;
+{
+ register mem *ptr = 0;
+ register unsigned int sz;
+
+ if (size == 0)
+ return 0; /* ANSI STD */
+
+ sz = size + sizeof(mem) * 2 - 1;
+ sz /= sizeof(mem);
+
+#ifdef MINALLOC
+ if (sz < MINALLOC)
+ sz = MINALLOC;
+#endif
+
+#ifdef VERBOSE
+ {
+ static mem arr[2];
+ m_size(arr) = sz;
+ noise("WANTED", arr);
+ }
+#endif
+
+ __alloca_alloc = malloc; /* We'll be messing with the heap now TVM */
+
+#ifdef LAZY_FREE
+ ptr = __search_chunk(sz);
+ if (ptr == 0)
+ {
+#endif
+
+ /* First deal with the freed list */
+ if (__freed_list)
+ {
+ while (__freed_list)
+ {
+ ptr = __freed_list;
+ __freed_list = m_next(__freed_list);
+
+ if (m_size(ptr) == sz) /* Oh! Well that's lucky ain't it
+ * :-) */
+ {
+ noise("LUCKY MALLOC", ptr);
+ return ptr + 1;
+ }
+
+ __insert_chunk(ptr);
+ }
+ ptr = m_next(chunk_list);
+ if (ptr + m_size(ptr) == (void *) sbrk(0))
+ {
+ /* Time to free for real */
+ m_next(chunk_list) = m_next(ptr);
+ if (ptr == m_next(ptr))
+ chunk_list = 0;
+ free(ptr + 1);
+ }
+#ifdef LAZY_FREE
+ ptr = __search_chunk(sz);
+#endif
+ }
+#ifndef LAZY_FREE
+ ptr = __search_chunk(sz);
+#endif
+ if (ptr == 0)
+ {
+#ifdef MCHUNK
+ unsigned int alloc;
+ alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1);
+ ptr = __mini_malloc(alloc);
+ if (ptr)
+ __insert_chunk(ptr - 1);
+ else /* Oooo, near end of RAM */
+ {
+ unsigned int needed = alloc;
+ for(alloc/=2; alloc>256 && needed; )
+ {
+ ptr = __mini_malloc(alloc);
+ if (ptr)
+ {
+ if( alloc > needed ) needed = 0; else needed -= alloc;
+ __insert_chunk(ptr - 1);
+ }
+ else alloc/=2;
+ }
+ }
+ ptr = __search_chunk(sz);
+ if (ptr == 0)
+#endif
+ {
+#ifndef MCHUNK
+ ptr = __mini_malloc(size);
+#endif
+#ifdef VERBOSE
+ if( ptr == 0 )
+ noise("MALLOC FAIL", 0);
+ else
+ noise("MALLOC NOW", ptr - 1);
+#endif
+ return ptr;
+ }
+ }
+#ifdef LAZY_FREE
+ }
+#endif
+
+#ifdef VERBOSE
+ ptr[1].size = 0x55555555;
+#endif
+ noise("MALLOC RET", ptr);
+ return ptr + 1;
+}
+
+/*
+ * This function takes a pointer to a block of memory and inserts it into
+ * the chain of memory chunks
+ */
+
+Static void
+__insert_chunk(mem_chunk)
+mem *mem_chunk;
+{
+ register mem *p1, *p2;
+ if (chunk_list == 0) /* Simple case first */
+ {
+ m_next(mem_chunk) = chunk_list = mem_chunk;
+ noise("FIRST CHUNK", mem_chunk);
+ return;
+ }
+ p1 = mem_chunk;
+ p2 = chunk_list;
+
+ do
+ {
+ if (p1 > p2)
+ {
+ if (m_next(p2) <= p2)
+ { /* We're at the top of the chain, p1 is
+ * higher */
+
+ if (p2 + m_size(p2) == p1)
+ { /* Good, stick 'em together */
+ noise("INSERT CHUNK", mem_chunk);
+ m_size(p2) += m_size(p1);
+ noise("JOIN 1", p2);
+ }
+ else
+ {
+ m_next(p1) = m_next(p2);
+ m_next(p2) = p1;
+ noise("INSERT CHUNK", mem_chunk);
+ noise("FROM", p2);
+ }
+ return;
+ }
+ if (m_next(p2) > p1)
+ {
+ /* In chain, p1 between p2 and next */
+
+ m_next(p1) = m_next(p2);
+ m_next(p2) = p1;
+ noise("INSERT CHUNK", mem_chunk);
+ noise("FROM", p2);
+
+ /* Try to join above */
+ if (p1 + m_size(p1) == m_next(p1))
+ {
+ m_size(p1) += m_size(m_next(p1));
+ m_next(p1) = m_next(m_next(p1));
+ noise("JOIN 2", p1);
+ }
+ /* Try to join below */
+ if (p2 + m_size(p2) == p1)
+ {
+ m_size(p2) += m_size(p1);
+ m_next(p2) = m_next(p1);
+ noise("JOIN 3", p2);
+ }
+ chunk_list = p2; /* Make sure it's valid */
+ return;
+ }
+ }
+ else if (p1 < p2)
+ {
+ if (m_next(p2) <= p2 && p1 < m_next(p2))
+ {
+ /* At top of chain, next is bottom of chain, p1 is below next */
+
+ m_next(p1) = m_next(p2);
+ m_next(p2) = p1;
+ noise("INSERT CHUNK", mem_chunk);
+ noise("FROM", p2);
+ chunk_list = p2;
+
+ if (p1 + m_size(p1) == m_next(p1))
+ {
+ if (p2 == m_next(p1))
+ chunk_list = p1;
+ m_size(p1) += m_size(m_next(p1));
+ m_next(p1) = m_next(m_next(p1));
+ noise("JOIN 4", p1);
+ }
+ return;
+ }
+ }
+ chunk_list = p2; /* Save for search */
+ p2 = m_next(p2);
+ }
+ while (p2 != chunk_list);
+
+ /* If we get here we have a problem, ignore it, maybe it'll go away */
+ noise("DROPPED CHUNK", mem_chunk);
+}
+
+/*
+ * This function will search for a chunk in memory of at least 'mem_size'
+ * when found, if the chunk is too big it'll be split, and pointer to the
+ * chunk returned. If none is found NULL is returned.
+ */
+
+Static mem *
+__search_chunk(mem_size)
+unsigned int mem_size;
+{
+ register mem *p1, *p2;
+ if (chunk_list == 0) /* Simple case first */
+ return 0;
+
+ /* Search for a block >= the size we want */
+ p1 = m_next(chunk_list);
+ p2 = chunk_list;
+ do
+ {
+ noise("CHECKED", p1);
+ if (m_size(p1) >= mem_size)
+ break;
+
+ p2 = p1;
+ p1 = m_next(p1);
+ }
+ while (p2 != chunk_list);
+
+ /* None found, exit */
+ if (m_size(p1) < mem_size)
+ return 0;
+
+ /* If it's exactly right remove it */
+ if (m_size(p1) < mem_size + 2)
+ {
+ noise("FOUND RIGHT", p1);
+ chunk_list = m_next(p2) = m_next(p1);
+ if (chunk_list == p1)
+ chunk_list = 0;
+ return p1;
+ }
+
+ noise("SPLIT", p1);
+ /* Otherwise split it */
+ m_next(p2) = p1 + mem_size;
+ chunk_list = p2;
+
+ p2 = m_next(p2);
+ m_size(p2) = m_size(p1) - mem_size;
+ m_next(p2) = m_next(p1);
+ m_size(p1) = mem_size;
+ if (chunk_list == p1)
+ chunk_list = p2;
+#ifdef VERBOSE
+ p1[1].size = 0xAAAAAAAA;
+#endif
+ noise("INSERT CHUNK", p2);
+ noise("FOUND CHUNK", p1);
+ noise("LIST IS", chunk_list);
+ return p1;
+}
+
+#endif /* L_malloc */
+
+#ifdef L_calloc
+void *
+calloc(elm, sz)
+unsigned int elm, sz;
+{
+ register unsigned int v;
+ register void *ptr;
+ ptr = malloc(v = elm * sz);
+ if (ptr)
+ memset(ptr, 0, v);
+ return ptr;
+}
+#endif /* L_calloc */
+
+#ifdef L_realloc
+void *
+realloc(ptr, size)
+void *ptr;
+size_t size;
+{
+ void *nptr;
+ unsigned int osize;
+ if (ptr == 0)
+ return malloc(size);
+
+ osize = (m_size(((mem *) ptr) - 1) - 1) * sizeof(mem);
+ if (size <= osize)
+ {
+ return ptr;
+ }
+
+ nptr = malloc(size);
+
+ if (nptr == 0)
+ return 0;
+
+ memcpy(nptr, ptr, osize);
+ free(ptr);
+
+ return nptr;
+}
+#endif /* L_realloc */
diff --git a/libc/malloc1/malloc.h b/libc/malloc1/malloc.h
new file mode 100644
index 0000000..e8fdb0a
--- /dev/null
+++ b/libc/malloc1/malloc.h
@@ -0,0 +1,30 @@
+
+#ifndef __MALLOC_H
+#define __MALLOC_H
+#include <features.h>
+#include <sys/types.h>
+
+/*
+ * Mini malloc allows you to use a less efficient but smaller malloc the
+ * cost is about 100 bytes of code in free but malloc (700bytes) doesn't
+ * have to be linked. Unfortunatly memory can only be reused if everything
+ * above it has been freed
+ *
+ */
+
+extern void free __P((void *));
+extern void *malloc __P((size_t));
+extern void *realloc __P((void *, size_t));
+extern void *alloca __P((size_t));
+
+extern void *(*__alloca_alloc) __P((size_t));
+
+#ifdef __LIBC__
+#define __MINI_MALLOC__
+#endif
+
+#ifdef __MINI_MALLOC__
+#define malloc(x) ((*__alloca_alloc)(x))
+#endif
+
+#endif
diff --git a/libc/malloc2/Config b/libc/malloc2/Config
new file mode 100644
index 0000000..11c476d
--- /dev/null
+++ b/libc/malloc2/Config
@@ -0,0 +1 @@
+malloc: Joel's malloc functions
diff --git a/libc/malloc2/Makefile b/libc/malloc2/Makefile
new file mode 100644
index 0000000..ea944db
--- /dev/null
+++ b/libc/malloc2/Makefile
@@ -0,0 +1,13 @@
+
+OBJ=malloc.o stack.o
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)($(OBJ))
+ @:
+clean:
+ rm -f *.o libc.a
+
+transfer:
+ -@rm ../include/malloc.h
+ cp -p malloc.h ../include/.
diff --git a/libc/malloc2/README b/libc/malloc2/README
new file mode 100644
index 0000000..ecf3fd2
--- /dev/null
+++ b/libc/malloc2/README
@@ -0,0 +1,19 @@
+This is just the malloc for libc. It is untested; it won't even compile
+right now. In particular, __malloc_init needs some bug fixing!
+
+Apparently, there is another malloc that Robert Debath wrote which probably
+works by now. However, I honestly think that my malloc may be just as
+good when it's finished.
+
+In about six months, you'll probably see something like this:
+
+
+Linux/less-than-32-bit installation program
+Do you want
+ 1. Chad Page's kernel
+ 2. Alan Cox's kernel
+Enter your chioce --> 2
+Do you want
+ 1. Robert Debath's malloc
+ 2. Joel Weber's malloc
+[more choices for compilers, filetools, etc]
diff --git a/libc/malloc2/malloc.c b/libc/malloc2/malloc.c
new file mode 100644
index 0000000..2e1cc04
--- /dev/null
+++ b/libc/malloc2/malloc.c
@@ -0,0 +1,126 @@
+/* simplified linux malloc.h
+ Copyright (C) 1995 Joel N. Weber II
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <malloc.h>
+
+typedef struct __malloc_struct malloc_struct;
+
+typedef union __malloc_union
+{
+ char *c;
+ malloc_struct *m;
+} malloc_union;
+
+
+struct __malloc_struct
+{
+ unsigned char status;
+#define ALLOC 0x53
+#define FREE 0x55
+#define END_OF_WORLD 0x57
+ malloc_union next;
+} *malloc_start;
+
+extern int __STACKSIZE;
+
+/* WARNING: this init will only work if there is a hard limit on the
+ amount of RAM that can be allocated.
+ */
+
+#ifdef __AS386_16__
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .word _malloc_init ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+malloc_init()
+{
+ extern unsigned int sbrk();
+
+ unsigned int ptr, sz, count;
+
+ malloc_start = (malloc_struct*) ((sbrk(16)+1)&~1);
+ malloc_start->status = FREE;
+
+ count=254;
+ for(sz=16384; sz>64; )
+ {
+ ptr= sbrk(sz);
+ if( ptr == (unsigned)-1 ) sz>>=1;
+ else count+=sz;
+ }
+ if( __STACKSIZE > count || __STACKSIZE <= 0 ) __STACKSIZE = ((count>>1)&-2);
+ ptr = sbrk(-__STACKSIZE);
+
+ malloc_start->next.m = ((malloc_struct*)ptr) - 1;
+
+ malloc_start->next.m->status = END_OF_WORLD;
+}
+
+char *malloc(size)
+size_t size;
+{
+ register malloc_union tmp, tmp2;
+
+ /* Make sure we don't lose the alignment */
+ size = (size+sizeof(malloc_struct)-1)/sizeof(malloc_struct);
+
+ tmp.m = malloc_start;
+ while ( ( tmp.m->next.m - tmp.m - 2 ) < size
+ || ( tmp.m->status == ALLOC ))
+ tmp.m = tmp.m->next.m;
+
+ if (tmp.m->status == FREE){
+ tmp2.m = size + tmp.m + 1;
+ tmp2.m->status = FREE;
+ tmp2.m->next.c = tmp.m->next.c;
+ tmp.m->status = ALLOC;
+ tmp.m->next.c = tmp2.c;
+ }
+ else return 0;
+ tmp.m++;
+ return tmp.c;
+}
+
+__malloc_cleanup() /* finds consecutive free blocks and joins them */
+{
+ malloc_struct *tmp;
+
+ tmp = malloc_start;
+ while ((tmp->status != END_OF_WORLD)&&(tmp->next.m->status != END_OF_WORLD)){
+ if ((tmp->status==FREE)&&(tmp->next.m->status==FREE))
+ tmp->next.m = tmp->next.m->next.m;
+ else tmp = tmp->next.m;
+ }
+}
+
+free(what)
+char *what;
+{
+ malloc_union tmp;
+
+ tmp.c = what; tmp.m--;
+ if( tmp.m->status == ALLOC )
+ {
+ tmp.m->status = FREE;
+ __malloc_cleanup;
+ }
+}
diff --git a/libc/malloc2/malloc.h b/libc/malloc2/malloc.h
new file mode 100644
index 0000000..ffcb3a4
--- /dev/null
+++ b/libc/malloc2/malloc.h
@@ -0,0 +1,21 @@
+/* simplified linux malloc.h
+ Copyright (C) 1995 Joel N. Weber II
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+char *malloc(size);
+void free(what);
+char *realloc(what, size);
diff --git a/libc/malloc2/stack.c b/libc/malloc2/stack.c
new file mode 100644
index 0000000..5f33e21
--- /dev/null
+++ b/libc/malloc2/stack.c
@@ -0,0 +1,10 @@
+
+/*
+ * Under Linux 8086 the stack and heap areas are at the top and bottom
+ * of the same area of memory, this version of malloc requires that the
+ * malloc area is of a fixed size this means that there must also be a
+ * specific amount of stack space reserved outside of this. The number
+ * of bytes to be reserved is specified below.
+ */
+
+int __STACKSIZE = 2048;
diff --git a/libc/misc/Config b/libc/misc/Config
new file mode 100644
index 0000000..9ede0c2
--- /dev/null
+++ b/libc/misc/Config
@@ -0,0 +1 @@
+misc: Various unix lib functions
diff --git a/libc/misc/Makefile b/libc/misc/Makefile
new file mode 100644
index 0000000..9bb579c
--- /dev/null
+++ b/libc/misc/Makefile
@@ -0,0 +1,62 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+MSRC=aliases.c
+MOBJ=abs.o raise.o bcopy.o bzero.o bcmp.o index.o rindex.o remove.o creat.o
+
+ESRC=atexit.c
+EOBJ=on_exit.o atexit.o __do_exit.o
+
+GOBJ=atoi.o atol.o ltoa.o ltostr.o \
+ ctype.o qsort.o bsearch.o rand.o lsearch.o getopt.o \
+ itoa.o cputype.o strtol.o crypt.o
+
+UOBJ=getenv.o putenv.o popen.o system.o setenv.o getcwd.o
+
+
+ifeq ($(LIB_OS),ELKS)
+OBJ=$(MOBJ) $(EOBJ) $(GOBJ) $(UOBJ)
+else
+OBJ=$(MOBJ) $(EOBJ) $(GOBJ)
+endif
+
+# No ELKS strtod() until BCC does 16 bit FP...
+ifneq ($(LIB_CPU),i86)
+OBJ+=strtod.o
+endif
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(MOBJ)): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(EOBJ)): $(ESRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+clean:
+ rm -f *.o libc.a
+
+$(LIBC)(strtol.o): strtol.c
+ $(CC) -c -ansi $(ARCH) $(CCFLAGS) $(DEFS) $*.c
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)(strtod.o): strtod.c
+ $(CC) -c -ansi $(ARCH) $(CCFLAGS) $(DEFS) $*.c
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)(crypt.o): crypt.c
+ $(CC) -c -ansi $(ARCH) $(CCFLAGS) $(DEFS) $*.c
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
diff --git a/libc/misc/aliases.c b/libc/misc/aliases.c
new file mode 100644
index 0000000..d23ea65
--- /dev/null
+++ b/libc/misc/aliases.c
@@ -0,0 +1,110 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef L_abs
+int
+abs(arg1)
+int arg1;
+{
+ return arg1>0?arg1:-arg1;
+}
+#endif
+
+#ifdef L_raise
+int
+raise(signo)
+int signo;
+{
+ return kill(getpid(), signo);
+}
+#endif
+
+#ifdef L_bcopy
+#undef bcopy
+void
+bcopy(src, dest, len)
+__const void * src;
+void *dest;
+int len;
+{
+ (void) memcpy(dest, src, len);
+}
+#endif
+
+#ifdef L_bzero
+#undef bzero
+void
+bzero(dest, len)
+void *dest;
+int len;
+{
+ (void) memset(dest, '\0', len);
+}
+#endif
+
+#ifdef L_bcmp
+#undef bcmp
+int
+bcmp(dest, src, len)
+__const void * src, *dest;
+int len;
+{
+ return memcmp(dest, src, len);
+}
+#endif
+
+#ifdef L_index
+#undef index
+char *
+index(src, chr)
+__const char *src;
+int chr;
+{
+ return strchr(src, chr);
+}
+#endif
+
+#ifdef L_rindex
+#undef rindex
+char *
+rindex(src, chr)
+__const char *src;
+int chr;
+{
+ return strrchr(src, chr);
+}
+#endif
+
+#ifdef L_remove
+#include <errno.h>
+
+int
+remove(src)
+__const char *src;
+{
+ extern int errno;
+ int er = errno;
+ int rv = unlink(src);
+ if( rv < 0 && errno == EISDIR )
+ rv = rmdir(src);
+ if( rv >= 0 ) errno = er;
+ return rv;
+}
+#endif
+
+#ifdef L_creat
+#include <fcntl.h>
+
+int
+creat(file, mode)
+__const char * file;
+mode_t mode;
+{
+ return open(file, O_TRUNC|O_CREAT|O_WRONLY, mode);
+}
+#endif
+
diff --git a/libc/misc/atexit.c b/libc/misc/atexit.c
new file mode 100644
index 0000000..6e8e45b
--- /dev/null
+++ b/libc/misc/atexit.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/*
+ * This deals with both the atexit and on_exit function calls
+ *
+ * Note calls installed with atexit are called with the same args as on_exit
+ * fuctions; the void* is given the NULL value.
+ *
+ */
+
+#include <errno.h>
+
+/* ATEXIT.H */
+#define MAXONEXIT 20 /* AIUI Posix requires 10 */
+
+typedef void (*vfuncp) ();
+
+extern vfuncp __cleanup;
+extern void __do_exit();
+
+extern struct exit_table
+{
+ vfuncp called;
+ void *argument;
+}
+__on_exit_table[MAXONEXIT];
+
+extern int __on_exit_count;
+
+/* End ATEXIT.H */
+
+#ifdef L_atexit
+int
+atexit(ptr)
+vfuncp ptr;
+{
+ if( __on_exit_count < 0 || __on_exit_count >= MAXONEXIT)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ __cleanup = __do_exit;
+ if( ptr )
+ {
+ __on_exit_table[__on_exit_count].called = ptr;
+ __on_exit_table[__on_exit_count].argument = 0;
+ __on_exit_count++;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef L_on_exit
+int
+on_exit(ptr, arg)
+vfuncp ptr;
+void *arg;
+{
+ if( __on_exit_count < 0 || __on_exit_count >= MAXONEXIT)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ __cleanup = __do_exit;
+ if( ptr )
+ {
+ __on_exit_table[__on_exit_count].called = ptr;
+ __on_exit_table[__on_exit_count].argument = arg;
+ __on_exit_count++;
+ }
+ return 0;
+}
+
+#endif
+
+#ifdef L___do_exit
+
+int __on_exit_count = 0;
+struct exit_table __on_exit_table[MAXONEXIT];
+
+void
+__do_exit(rv)
+int rv;
+{
+ register int count = __on_exit_count-1;
+ register vfuncp ptr;
+ __on_exit_count = -1; /* ensure no more will be added */
+ __cleanup = 0; /* Calling exit won't re-do this */
+
+ /* In reverse order */
+ for (; count >= 0; count--)
+ {
+ ptr = __on_exit_table[count].called;
+ (*ptr) (rv, __on_exit_table[count].argument);
+ }
+}
+
+#endif
diff --git a/libc/misc/atoi.c b/libc/misc/atoi.c
new file mode 100644
index 0000000..5272646
--- /dev/null
+++ b/libc/misc/atoi.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+int
+atoi(number)
+register char *number;
+{
+ register int n = 0, neg = 0;
+
+ while (*number <= ' ' && *number > 0)
+ ++number;
+ if (*number == '-')
+ {
+ neg = 1;
+ ++number;
+ }
+ else if (*number == '+')
+ ++number;
+ while (*number>='0' && *number<='9')
+ n = (n * 10) + ((*number++) - '0');
+ return (neg ? -n : n);
+}
diff --git a/libc/misc/atol.c b/libc/misc/atol.c
new file mode 100644
index 0000000..901dfe2
--- /dev/null
+++ b/libc/misc/atol.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+long
+atol(number)
+register char *number;
+{
+ register long n = 0, neg = 0;
+
+ while (*number <= ' ' && *number > 0)
+ ++number;
+ if (*number == '-')
+ {
+ neg = 1;
+ ++number;
+ }
+ else if (*number == '+')
+ ++number;
+ while (*number>='0' && *number<='9')
+ n = (n * 10) + ((*number++) - '0');
+ return (neg ? -n : n);
+}
diff --git a/libc/misc/bsearch.c b/libc/misc/bsearch.c
new file mode 100644
index 0000000..9898667
--- /dev/null
+++ b/libc/misc/bsearch.c
@@ -0,0 +1,46 @@
+
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST (RdeBath)
+ *
+ *
+ * Dale Schumacher 399 Beacon Ave.
+ * (alias: Dalnefre') St. Paul, MN 55104
+ * dal@syntel.UUCP United States of America
+ * "It's not reality that's important, but how you perceive things."
+ */
+#include <stdio.h>
+
+static int _bsearch; /* index of element found, or where to
+ * insert */
+
+char *
+bsearch(key, base, num, size, cmp)
+register char *key; /* item to search for */
+register char *base; /* base address */
+int num; /* number of elements */
+register int size; /* element size in bytes */
+register int (*cmp) (); /* comparison function */
+{
+ register int a, b, c, dir;
+
+ a = 0;
+ b = num - 1;
+ while (a <= b)
+ {
+ c = (a + b) >> 1; /* == ((a + b) / 2) */
+ if (dir = (*cmp) ((base + (c * size)), key))
+ {
+ if (dir > 0)
+ b = c - 1;
+ else /* (dir < 0) */
+ a = c + 1;
+ }
+ else
+ {
+ _bsearch = c;
+ return (base + (c * size));
+ }
+ }
+ _bsearch = b;
+ return (NULL);
+}
diff --git a/libc/misc/cputype.c b/libc/misc/cputype.c
new file mode 100644
index 0000000..8417514
--- /dev/null
+++ b/libc/misc/cputype.c
@@ -0,0 +1,357 @@
+/*
+ * This does a determination of the cpu type that is actually being used.
+ * It can determine the CPU on anything upto and including a 386 accuratly
+ * whatever mode the CPU is in (This is 16 bit code)
+ *
+ * For Post 386 interpretation the argument must be set to 1, if this is done
+ * an attempt to determine the CPU type will be made using MSDOS calls and
+ * potentially Illegal instructions.
+ *
+ * If STANDALONE is defined this will decode and print the output from cputype
+ *
+ * $ cputype # Call cputype(0) and interpret
+ * $ cputype + # Call cputype(1) get a SIGILL (or perhaps interpret)
+ *
+ * NOTE: This code is COPYRIGHT and not under the GNU Lib copyright, this
+ * may be distributed freely as source or as a standalone binary
+ * compiled from this unmodified source.
+ *
+ * You may use the cputype() function in your own personal code.
+ * You may distribute a binary version of code containing the
+ * cputype() function if either you distribute this source with
+ * the binary version or distribute a clear reference to a freely
+ * available copy of this source code and the source code to the
+ * rest of your package with the binary version of the package.
+ *
+ * (C) Copyright R de Bath 1989-1996
+ */
+
+#ifdef STANDALONE
+#define cputype cpu
+
+#include <stdio.h>
+#ifndef __MSDOS__
+#include <signal.h>
+#endif
+
+char * name_808x[] = {
+"8088", "8086", "80C88", "80C86", "NEC V20", "NEC V30", "808x Clone"
+};
+
+char * name_8018x[] = {
+"80188", "80186", "8018x Clone"
+};
+
+void
+main(argc, argv)
+int argc; char **argv;
+{
+ int c, major, flg, fpu;
+#ifdef SIGFPE
+ signal(SIGFPE, SIG_IGN);
+#endif
+
+ printf("Cpu identifier - (C) R de Bath <rdebath@cix.compulink.co.uk>\n");
+
+ c = cputype(argc!=1);
+ fpu = (c<0); major = ((c>>8)&0x1F); c &= 0xFF;
+
+ if( major == 0 )
+ {
+ if( c > 6 ) c = 6;
+ printf("Cpu is an %s\n", name_808x[c]);
+ }
+ else if( major == 1 )
+ {
+ if( c > 3 ) c = 3;
+ printf("Cpu is an %s\n", name_8018x[c]);
+ }
+ else
+ {
+ printf("Cpu is an 80%x86%s", major&0xF, major>15?"+":"");
+ if(c&0x01) printf( " in protected mode");
+ printf(" MSW= ");
+ if( c&0x10 ) printf("ET,"); else printf("--,");
+ if( c&0x08 ) printf("TS,"); else printf("--,");
+ if( c&0x04 ) printf("EM,"); else printf("--,");
+ if( c&0x02 ) printf("MP,"); else printf("--,");
+ if( c&0x01 ) printf("PE\n"); else printf("--\n");
+
+ if( !fpu && ( c&0x06) )
+ printf("An FPU appears to exist but it is unavailable\n");
+ else
+ {
+ if( c&0x02 ) printf("Math processor requires WAIT\n");
+ if( c&0x04 ) printf("Emulated math present\n");
+ if( c&0x08 ) printf("Math processor belongs to a different process\n");
+ /* if( c&0x10 ) printf("Humm\n"); */
+ }
+ }
+ if( fpu ) printf("FPU available for use\n");
+
+ exit(0);
+}
+#endif
+
+/*
+ * The assembler for CPU determination.
+ *
+ * Improvements and additional CPUs are solicited.
+ */
+
+#ifdef __AS386_16__
+#asm
+ .text
+#ifdef STANDALONE
+export _cpu
+_cpu:
+#else
+export _cputype
+_cputype:
+#endif
+ ; First save everything ...
+ push bp
+ mov bp,sp
+ push ds
+ push es
+ push bx
+ push cx
+ push dx
+ pushf
+#if __FIRST_ARG_IN_AX__
+ mov cx, ax ; Collect the flag
+#else
+ mov cx, [bp+4] ; Collect the flag
+#endif
+
+ ; Tiny mode code ...
+ mov ax, cs
+ mov es, ax
+ mov ds, ax
+ mov bx, #0 ; Init to 8086
+
+ ; First easy check is it a 286 or better ...
+ push sp
+ pop ax
+ cmp ax, sp
+ jz ge286
+ br pre286
+
+ ; Come here when we`re done (286+)
+cpu_prot:
+ ; .286P
+ smsw ax ; Fetch 5 LSB of MSW (PE,MP,EP,...)
+ and al,#31
+ mov bl,al
+
+ ; Check for FPU
+ fninit
+ xor ax,ax
+ push ax
+ mov bp,sp
+ fnstcw word ptr [bp]
+ pop ax
+ cmp ah,#3
+ jne cpuend
+ or bh,#$80
+
+ ; Another check for FPU *BUT* I think this only get`s 287+
+; finit
+; fstsw ax
+; or al,al
+; jnz cpuend
+; or bh,#$80
+
+ ; .8086
+cpuend:
+ mov ax, bx
+ popf
+ pop dx
+ pop cx
+ pop bx
+ pop es
+ pop ds
+ pop bp
+ ret
+
+ge286: ; .286P
+ ; Does the caller want the exact CPU
+ cmp cx,#0
+ jne try_486
+
+; Simple test for a 286 ...
+
+ mov bh,#2 ; Major CPU type >= 80286
+ ; What`s the contents of the GDT pointer
+ sub sp,#6
+ mov bp,sp
+ sgdt [bp]
+ add sp,#4
+ pop ax ; For 286, ah can only be 0xFF
+ inc ah
+ jz cpu_prot
+ mov bh,#$13 ; Major CPU type >= 80386
+
+#ifdef __MSDOS__
+ smsw ax ; If we`re in MSDOS and running in real mode
+ ror ax,#1 ; we can do the int 6 detection.
+ jnc try_486
+#endif
+
+ jmp cpu_prot ; Assume 486 test will NOT work in prot mode
+
+ ; This is an alternate way of finding a 386 ...
+ ; But it *can* be hidden by V86 mode.
+; pushf
+; mov ax,#$7000
+; push ax
+; popf
+; pushf
+; pop ax
+; popf
+; and ax,#$7000
+; jz is_a_286
+
+try_486:
+ ; This trys to trap undefined instructions
+ ; it may not work if the CPU is in protected mode
+ ; Note: This code works for anything 286+
+ cli
+ push bp
+ mov bp, sp
+ mov ax,#$3506
+ int #$21 ; WARNING - DOS DOS DOS DOS DOS !!!!!
+ mov [vector+2], es
+ mov [vector], bx
+ mov ax,#$2506
+ lea dx, [int6]
+ int #$21
+ mov bh,#2 ; 286
+
+ ; .486
+test386:
+ mov ebx,#$00040300 ; 386 or 486
+test486:
+ bswap ebx ; Byte twiddle now 486
+
+ mov ax,#1
+do_cpuid:
+ db $0F ; CPUID instruction
+ db $A2
+
+ mov ax,#1 ; And again cause of Nasty EMM386s
+ db $0F ; CPUID instruction
+ db $A2
+
+ and ah,#15 ; Select family number
+ mov bh,ah ; put it where we want it
+
+ ; .286P
+fail386:
+ mov ax, #$2506
+ mov dx, [vector]
+ mov ds, [vector+2]
+ int #$21
+ pop bp
+ sti
+ br cpu_prot
+
+
+ ; Tests for processors before the 80286 ...
+ ; .8086
+pre286:
+ ; Is it an 8018x ? These mask shifts to less that 32 bits
+ mov cl,#32
+ mov ax, #$0100
+ shl ax,cl
+ mov bx, ax
+ jnz test8
+
+ ; Try for an NEC V20/30
+ mov ax, #$0208
+ db $D5
+ db 16 ; Only the 8088 actually checks the arg to AAD
+ cmp al, #$28 ; as intel ran out of microcode space
+ jz cmos
+ mov bx,#4 ; NEC V20
+ jmp test8
+
+ ; The CMOS 8088/6 had the bug with rep lods repaired.
+cmos: push si
+ sti
+ mov cx, #$FFFF
+ rep
+ lodsb
+ pop si
+ or cx,cx
+ jne test8
+ mov bx,#2 ; Intel 80C88
+
+ ; This tests the prefetch of the CPU, 8 bit ones have 4 bytes
+ ; 16 bit cpus have a queue of 6 bytes.
+test8: push di
+ push bx
+ mov dx,#0
+ mov bx,#4
+ std
+ mov al,#$90
+
+retest: lea di,[_nop]
+ cli
+ mov cx,#3
+ rep
+ stosb
+ nop
+ nop
+ nop
+ nop
+_inc: inc dx
+ nop
+_nop: nop
+ sti
+ mov byte ptr [_inc], #$42
+ dec bx
+ jnz retest
+ pop bx
+ cmp dx,#0
+ jz done8
+ inc bx
+done8: pop di
+ cld
+
+ br cpuend
+
+
+ ; Function called by the illegal instruction trap
+int6:
+ mov sp, bp
+ jmp fail386
+
+; This was the old way, didn`t always work tho.
+; push bp
+; mov bp, sp
+; push ax
+; mov ax,cs
+; cmp 4[bp],ax
+; pop ax
+; jnz pass
+; cmp bh,#2
+; je move23
+; cmp bh,#3
+; je move34
+; add [bp+2], #(fail386 - do_cpuid)
+; jmp return
+;move34: add [bp+2], #(fail386 - test486)
+; jmp return
+;move23: add [bp+2], #(fail386 - test386)
+;return: pop bp
+; iret
+;
+;pass: pop bp
+; jmp [vector]
+
+vector: dd 0
+
+#endasm
+
+#endif
diff --git a/libc/misc/crypt.c b/libc/misc/crypt.c
new file mode 100644
index 0000000..906dea2
--- /dev/null
+++ b/libc/misc/crypt.c
@@ -0,0 +1,50 @@
+#include <features.h>
+#include <stdlib.h>
+/* TEA based crypt(), version 0.0 <ndf@linux.mit.edu>
+ * It looks like there are problems with key bits carrying through
+ * to the encryted data, and I want to get rid of that libc call..
+ * This is just so rob could see it ;) */
+char *
+crypt(const char * key, const char * salt)
+{
+ /* n is the number of rounds, delta is a golden # derivative,
+ k is the key, v is the data to be encrypted. */
+ unsigned long v[2], sum=0, delta=0x9e3779b9, n=64, k[4];
+ static char rkey[16];
+ unsigned char i;
+
+ /* Our constant string will be a string of zeros .. */
+ v[0]=v[1]=k[0]=k[1]=k[2]=k[3]=0;
+ for(i=0;i<16;i++) rkey[i]=0;
+ rkey[0]=*salt;
+ rkey[1]=salt[1];
+ for (i=0;key[i];i++) rkey[i+1]=key[i];
+ memcpy(k, rkey, 4*sizeof(long));
+
+ while (n-->0) {
+ sum += delta;
+ v[0] += (v[1]<<4)+k[0] ^ v[1]+sum ^ (v[1]>>5)+k[1];
+ v[1] += (v[0]<<4)+k[2] ^ v[0]+sum ^ (v[0]>>5)+k[3];
+ }
+
+ *rkey=*salt; rkey[1]=salt[1];
+
+ /* Now we need to unpack the bits and map it to "A-Za-z0-9./" for printing
+ in /etc/passwd */
+ for (i=2;i<13;i++)
+ {
+ /* This unpacks the 6 bit data, each cluster into its own byte */
+ if (i==8) v[0]|=v[1]>>28;
+ rkey[i]=v[(i-2)/6]&0x3F;
+ v[(i-2)/6]>>=6;
+
+ /* Now we map to the proper chars */
+ if (rkey[i]>=0 && rkey[i]<12) rkey[i]+=46;
+ else if (rkey[i]>11 && rkey[i]<38) rkey[i]+=53;
+ else if (rkey[i]>37 && rkey[i]<64) rkey[i]+=59;
+ else return NULL;
+ }
+
+ rkey[13]='\0';
+ return rkey;
+}
diff --git a/libc/misc/ctype.c b/libc/misc/ctype.c
new file mode 100644
index 0000000..6b6cd3d
--- /dev/null
+++ b/libc/misc/ctype.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/*
+ * CTYPE.C Character classification and conversion
+ */
+
+#include <ctype.h>
+
+#undef toupper
+#undef tolower
+
+unsigned char __ctype[128] =
+{
+ __CT_c, __CT_c, __CT_c, __CT_c, /* 0x00..0x03 */
+ __CT_c, __CT_c, __CT_c, __CT_c, /* 0x04..0x07 */
+ __CT_c, __CT_c|__CT_s, __CT_c|__CT_s, __CT_c|__CT_s, /* 0x08..0x0B */
+ __CT_c|__CT_s, __CT_c|__CT_s, __CT_c, __CT_c, /* 0x0C..0x0F */
+
+ __CT_c, __CT_c, __CT_c, __CT_c, /* 0x10..0x13 */
+ __CT_c, __CT_c, __CT_c, __CT_c, /* 0x14..0x17 */
+ __CT_c, __CT_c, __CT_c, __CT_c, /* 0x18..0x1B */
+ __CT_c, __CT_c, __CT_c, __CT_c, /* 0x1C..0x1F */
+
+ __CT_s, __CT_p, __CT_p, __CT_p, /* 0x20..0x23 */
+ __CT_p, __CT_p, __CT_p, __CT_p, /* 0x24..0x27 */
+ __CT_p, __CT_p, __CT_p, __CT_p, /* 0x28..0x2B */
+ __CT_p, __CT_p, __CT_p, __CT_p, /* 0x2C..0x2F */
+
+ __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x,/* 0x30..0x33 */
+ __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x, __CT_d|__CT_x,/* 0x34..0x37 */
+ __CT_d|__CT_x, __CT_d|__CT_x, __CT_p, __CT_p, /* 0x38..0x3B */
+ __CT_p, __CT_p, __CT_p, __CT_p, /* 0x3C..0x3F */
+
+ __CT_p, __CT_u|__CT_x, __CT_u|__CT_x, __CT_u|__CT_x, /* 0x40..0x43 */
+ __CT_u|__CT_x, __CT_u|__CT_x, __CT_u|__CT_x, __CT_u, /* 0x44..0x47 */
+ __CT_u, __CT_u, __CT_u, __CT_u, /* 0x48..0x4B */
+ __CT_u, __CT_u, __CT_u, __CT_u, /* 0x4C..0x4F */
+
+ __CT_u, __CT_u, __CT_u, __CT_u, /* 0x50..0x53 */
+ __CT_u, __CT_u, __CT_u, __CT_u, /* 0x54..0x57 */
+ __CT_u, __CT_u, __CT_u, __CT_p, /* 0x58..0x5B */
+ __CT_p, __CT_p, __CT_p, __CT_p, /* 0x5C..0x5F */
+
+ __CT_p, __CT_l|__CT_x, __CT_l|__CT_x, __CT_l|__CT_x, /* 0x60..0x63 */
+ __CT_l|__CT_x, __CT_l|__CT_x, __CT_l|__CT_x, __CT_l, /* 0x64..0x67 */
+ __CT_l, __CT_l, __CT_l, __CT_l, /* 0x68..0x6B */
+ __CT_l, __CT_l, __CT_l, __CT_l, /* 0x6C..0x6F */
+
+ __CT_l, __CT_l, __CT_l, __CT_l, /* 0x70..0x73 */
+ __CT_l, __CT_l, __CT_l, __CT_l, /* 0x74..0x77 */
+ __CT_l, __CT_l, __CT_l, __CT_p, /* 0x78..0x7B */
+ __CT_p, __CT_p, __CT_p, __CT_c /* 0x7C..0x7F */
+};
+
+int toupper(c)
+int c;
+{
+ return(islower(c) ? (c ^ 0x20) : (c));
+}
+
+int tolower(c)
+int c;
+{
+ return(isupper(c) ? (c ^ 0x20) : (c));
+}
diff --git a/libc/misc/getcwd.c b/libc/misc/getcwd.c
new file mode 100644
index 0000000..351214c
--- /dev/null
+++ b/libc/misc/getcwd.c
@@ -0,0 +1,109 @@
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <string.h>
+/*
+ * These functions find the absolute path to the current working directory.
+ *
+ * They don't use malloc or large amounts of stack space.
+ */
+
+static char * recurser(); /* Routine to go up tree */
+static char * search_dir(); /* Routine to find the step back down */
+static char * path_buf;
+static int path_size;
+
+static dev_t root_dev;
+static ino_t root_ino;
+
+static struct stat st;
+
+char *
+getcwd(buf, size)
+char * buf;
+int size;
+{
+ path_buf = buf;
+ path_size = size;
+
+ if( size < 3 ) { errno = ERANGE; return 0; }
+ strcpy(path_buf, ".");
+
+ if( stat("/", &st) < 0 ) return 0;
+
+ root_dev = st.st_dev;
+ root_ino = st.st_ino;
+
+ return recurser();
+}
+
+static char *
+recurser()
+{
+ dev_t this_dev;
+ ino_t this_ino;
+ if( stat(path_buf, &st) < 0 ) return 0;
+ this_dev = st.st_dev;
+ this_ino = st.st_ino;
+ if( this_dev == root_dev && this_ino == root_ino )
+ {
+ strcpy(path_buf, "/");
+ return path_buf;
+ }
+ if( strlen(path_buf) + 4 > path_size ) { errno = ERANGE; return 0; }
+ strcat(path_buf, "/..");
+ if( recurser() == 0 ) return 0;
+
+ return search_dir(this_dev, this_ino);
+}
+
+static char *
+search_dir(this_dev, this_ino)
+dev_t this_dev;
+ino_t this_ino;
+{
+ DIR * dp;
+ struct dirent * d;
+ char * ptr;
+ int slen;
+ /* The test is for ELKS lib 0.0.9, this should be fixed in the real kernel*/
+ int slow_search = (sizeof(ino_t) != sizeof(d->d_ino));
+
+ if( stat(path_buf, &st) < 0 ) return 0;
+ if( this_dev != st.st_dev ) slow_search = 1;
+
+ slen = strlen(path_buf);
+ ptr = path_buf + slen -1;
+ if( *ptr != '/' )
+ {
+ if( slen + 2 > path_size ) { errno = ERANGE; return 0; }
+ strcpy(++ptr, "/");
+ slen++;
+ }
+ slen++;
+
+ dp = opendir(path_buf);
+ if( dp == 0 ) return 0;
+
+ while( (d=readdir(dp)) != 0 )
+ {
+ if( slow_search || this_ino == d->d_ino )
+ {
+ if( slen + strlen(d->d_name) > path_size )
+ { errno = ERANGE; return 0; }
+ strcpy(ptr+1, d->d_name);
+ if( stat(path_buf, &st) < 0 )
+ continue;
+ if( st.st_ino == this_ino && st.st_dev == this_dev )
+ {
+ closedir(dp);
+ return path_buf;
+ }
+ }
+ }
+
+ closedir(dp);
+ errno = ENOENT;
+ return 0;
+}
diff --git a/libc/misc/getenv.c b/libc/misc/getenv.c
new file mode 100644
index 0000000..45d072e
--- /dev/null
+++ b/libc/misc/getenv.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+extern char ** environ;
+
+char *
+getenv(name)
+char * name;
+{
+ register int l;
+ register char ** ep = environ;
+ l = strlen(name);
+
+ if( ep == 0 || l == 0 ) return 0;
+
+ while(*ep)
+ {
+ if( **ep == *name && memcmp(name, *ep, l) == 0 && (*ep)[l] == '=' )
+ return *ep+l+1;
+ ep++;
+ }
+ return 0;
+}
+
diff --git a/libc/misc/getopt.c b/libc/misc/getopt.c
new file mode 100644
index 0000000..d951214
--- /dev/null
+++ b/libc/misc/getopt.c
@@ -0,0 +1,122 @@
+
+/*
+ * From: gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) Newsgroups: net.sources
+ * Subject: getopt library routine Date: 30 Mar 85 04:45:33 GMT
+ */
+/*
+ * getopt -- public domain version of standard System V routine
+ *
+ * Strictly enforces the System V Command Syntax Standard; provided by D A
+ * Gwyn of BRL for generic ANSI C implementations
+ *
+ * #define STRICT to prevent acceptance of clustered options with arguments
+ * and ommision of whitespace between option and arg.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+int opterr = 1; /* error => print message */
+int optind = 1; /* next argv[] index */
+char *optarg = NULL; /* option parameter if any */
+
+static int
+Err(name, mess, c) /* returns '?' */
+char *name; /* program name argv[0] */
+char *mess; /* specific message */
+int c; /* defective option letter */
+{
+ if (opterr)
+ {
+ (void) fprintf(stderr,
+ "%s: %s -- %c\n",
+ name, mess, c
+ );
+ }
+
+ return '?'; /* erroneous-option marker */
+}
+
+int
+getopt(argc, argv, optstring) /* returns letter, '?', EOF */
+int argc; /* argument count from main */
+char *argv[]; /* argument vector from main */
+char *optstring; /* allowed args, e.g. "ab:c" */
+{
+ static int sp = 1; /* position within argument */
+ register int osp; /* saved `sp' for param test */
+#ifndef STRICT
+ register int oind; /* saved `optind' for param test */
+#endif
+ register int c; /* option letter */
+ register char *cp; /* -> option in `optstring' */
+
+ optarg = NULL;
+
+ if (sp == 1) /* fresh argument */
+ if (optind >= argc /* no more arguments */
+ || argv[optind][0] != '-' /* no more options */
+ || argv[optind][1] == '\0' /* not option; stdin */
+ )
+ return EOF;
+ else if (strcmp(argv[optind], "--") == 0)
+ {
+ ++optind; /* skip over "--" */
+ return EOF; /* "--" marks end of options */
+ }
+
+ c = argv[optind][sp]; /* option letter */
+ osp = sp++; /* get ready for next letter */
+
+#ifndef STRICT
+ oind = optind; /* save optind for param test */
+#endif
+ if (argv[optind][sp] == '\0')/* end of argument */
+ {
+ ++optind; /* get ready for next try */
+ sp = 1; /* beginning of next argument */
+ }
+
+ if (c == ':' || c == '?' /* optstring syntax conflict */
+ || (cp = strchr(optstring, c)) == NULL /* not found */
+ )
+ return Err(argv[0], "illegal option", c);
+
+ if (cp[1] == ':') /* option takes parameter */
+ {
+#ifdef STRICT
+ if (osp != 1)
+ return Err(argv[0],
+ "option must not be clustered",
+ c
+ );
+
+ if (sp != 1) /* reset by end of argument */
+ return Err(argv[0],
+ "option must be followed by white space",
+ c
+ );
+
+#else
+ if (oind == optind) /* argument w/o whitespace */
+ {
+ optarg = &argv[optind][sp];
+ sp = 1; /* beginning of next argument */
+ }
+
+ else
+#endif
+ if (optind >= argc)
+ return Err(argv[0],
+ "option requires an argument",
+ c
+ );
+
+ else /* argument w/ whitespace */
+ optarg = argv[optind];
+
+ ++optind; /* skip over parameter */
+ }
+
+ return c;
+}
diff --git a/libc/misc/itoa.c b/libc/misc/itoa.c
new file mode 100644
index 0000000..0822cfc
--- /dev/null
+++ b/libc/misc/itoa.c
@@ -0,0 +1,24 @@
+/* itoa.c <ndf@linux.mit.edu> */
+#define __MAX_INT_CHARS 7
+
+char *
+itoa(i)
+int i;
+{
+ static char a[__MAX_INT_CHARS];
+ char *b = a + sizeof(a) - 1;
+ int sign = (i < 0);
+
+ if (sign)
+ i = -i;
+ *b = 0;
+ do
+ {
+ *--b = '0' + (i % 10);
+ i /= 10;
+ }
+ while (i);
+ if (sign)
+ *--b = '-';
+ return b;
+}
diff --git a/libc/misc/lsearch.c b/libc/misc/lsearch.c
new file mode 100644
index 0000000..f3253e9
--- /dev/null
+++ b/libc/misc/lsearch.c
@@ -0,0 +1,47 @@
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST (RdeBath)
+ *
+ *
+ * Dale Schumacher 399 Beacon Ave.
+ * (alias: Dalnefre') St. Paul, MN 55104
+ * dal@syntel.UUCP United States of America
+ * "It's not reality that's important, but how you perceive things."
+ */
+
+#include <stdio.h>
+
+char *
+lfind(key, base, num, size, cmp)
+register char *key, *base;
+unsigned int *num;
+register unsigned int size;
+register int (*cmp) ();
+{
+ register int n = *num;
+
+ while (n--)
+ {
+ if ((*cmp) (base, key) == 0)
+ return (base);
+ base += size;
+ }
+ return (NULL);
+}
+
+char *
+lsearch(key, base, num, size, cmp)
+char *key, *base;
+register unsigned int *num;
+register unsigned int size;
+int (*cmp) ();
+{
+ register char *p;
+ char *memcpy();
+
+ if ((p = lfind(key, base, num, size, cmp)) == NULL)
+ {
+ p = memcpy((base + (size * (*num))), key, size);
+ ++(*num);
+ }
+ return (p);
+}
diff --git a/libc/misc/ltoa.c b/libc/misc/ltoa.c
new file mode 100644
index 0000000..be1c7e2
--- /dev/null
+++ b/libc/misc/ltoa.c
@@ -0,0 +1,37 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+static char buf[12];
+
+extern char * ultoa();
+
+char * ltoa(val)
+long val;
+{
+ char *p;
+ int flg = 0;
+ if( val < 0 ) { flg++; val= -val; }
+ p = ultoa(val);
+ if(flg) *--p = '-';
+ return p;
+}
+
+char * ultoa(val)
+unsigned long val;
+{
+ char *p;
+
+ p = buf+sizeof(buf);
+ *--p = '\0';
+
+ do
+ {
+ *--p = '0' + val%10;
+ val/=10;
+ }
+ while(val);
+ return p;
+}
+
diff --git a/libc/misc/ltostr.c b/libc/misc/ltostr.c
new file mode 100644
index 0000000..c8966d9
--- /dev/null
+++ b/libc/misc/ltostr.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+static char buf[34];
+
+extern char * ultostr();
+
+char * ltostr(val, radix)
+long val;
+int radix;
+{
+ char *p;
+ int flg = 0;
+ if( val < 0 ) { flg++; val= -val; }
+ p = ultostr(val, radix);
+ if(p && flg) *--p = '-';
+ return p;
+}
+
+char * ultostr(val, radix)
+unsigned long val;
+int radix;
+{
+ register char *p;
+ register int c;
+
+ if( radix > 36 || radix < 2 ) return 0;
+
+ p = buf+sizeof(buf);
+ *--p = '\0';
+
+ do
+ {
+ c = val%radix;
+ val/=radix;
+ if( c > 9 ) *--p = 'a'-10+c; else *--p = '0'+c;
+ }
+ while(val);
+ return p;
+}
+
diff --git a/libc/misc/popen.c b/libc/misc/popen.c
new file mode 100644
index 0000000..c848ca4
--- /dev/null
+++ b/libc/misc/popen.c
@@ -0,0 +1,42 @@
+
+#include <stdio.h>
+
+
+FILE * popen(command, rw)
+char * command;
+char * rw;
+{
+ int pipe_fd[2];
+ int pid, reading;
+
+ if( pipe(pipe_fd) < 0 ) return NULL;
+ reading = (rw[0] == 'r');
+
+ pid = vfork();
+ if( pid < 0 ) { close(pipe_fd[0]); close(pipe_fd[1]); return NULL; }
+ if( pid == 0 )
+ {
+ close(pipe_fd[!reading]);
+ close(reading);
+ if( pipe_fd[reading] != reading )
+ {
+ dup2(pipe_fd[reading], reading);
+ close(pipe_fd[reading]);
+ }
+
+ execl("/bin/sh", "sh", "-c", command, (char*)0);
+ _exit(255);
+ }
+
+ close(pipe_fd[reading]);
+ return fdopen(pipe_fd[!reading], rw);
+}
+
+int pclose(fd)
+FILE *fd;
+{
+ int waitstat;
+ if( fclose(fd) != 0 ) return EOF;
+ wait(&waitstat);
+}
+
diff --git a/libc/misc/putenv.c b/libc/misc/putenv.c
new file mode 100644
index 0000000..09a68d6
--- /dev/null
+++ b/libc/misc/putenv.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+extern char ** environ;
+#define ADD_NUM 4
+
+int
+putenv(var)
+char * var;
+{
+static char ** mall_env = 0;
+static int extras = 0;
+ char **p, **d;
+ char * r;
+ int len;
+
+ r = strchr(var, '=');
+ if( r == 0 ) len = strlen(var);
+ else len = r-var;
+
+ for(p=environ; *p; p++)
+ {
+ if( memcmp(var, *p, len) == 0 && (*p)[len] == '=' )
+ {
+ while( p[0] = p[1] ) p++;
+ extras++;
+ break;
+ }
+ }
+ if( r == 0 ) return 0;
+ if( extras <= 0 ) /* Need more space */
+ {
+ d = malloc((p-environ+1+ADD_NUM)*sizeof(char*));
+ if( d == 0 ) return -1;
+
+ memcpy((void*) d, (void*) environ, (p-environ+1)*sizeof(char*));
+ p = d + (p-environ);
+ extras=ADD_NUM;
+
+ if( mall_env ) free(mall_env);
+ environ = d;
+ mall_env = d;
+ }
+ *p++ = var;
+ *p = '\0';
+ extras--;
+
+ return 0;
+}
+
+
diff --git a/libc/misc/qsort.c b/libc/misc/qsort.c
new file mode 100644
index 0000000..cee53c3
--- /dev/null
+++ b/libc/misc/qsort.c
@@ -0,0 +1,166 @@
+/*
+ * This file lifted in toto from 'Dlibs' on the atari ST (RdeBath)
+ *
+ *
+ * Dale Schumacher 399 Beacon Ave.
+ * (alias: Dalnefre') St. Paul, MN 55104
+ * dal@syntel.UUCP United States of America
+ * "It's not reality that's important, but how you perceive things."
+ */
+#include <string.h>
+
+char *_qbuf = 0; /* pointer to storage for qsort() */
+
+#define PIVOT ((i+j)>>1)
+#define moveitem(dst,src,size) if(dst != src) memcpy(dst, src, size)
+
+static
+_wqsort(base, lo, hi, cmp)
+register int *base;
+register int lo;
+register int hi;
+register int (*cmp) ();
+{
+ int k;
+ register int i, j, t;
+ register int *p = &k;
+
+ while (hi > lo)
+ {
+ i = lo;
+ j = hi;
+ t = PIVOT;
+ *p = base[t];
+ base[t] = base[i];
+ base[i] = *p;
+ while (i < j)
+ {
+ while (((*cmp) ((base + j), p)) > 0)
+ --j;
+ base[i] = base[j];
+ while ((i < j) && (((*cmp) ((base + i), p)) <= 0))
+ ++i;
+ base[j] = base[i];
+ }
+ base[i] = *p;
+ if ((i - lo) < (hi - i))
+ {
+ _wqsort(base, lo, (i - 1), cmp);
+ lo = i + 1;
+ }
+ else
+ {
+ _wqsort(base, (i + 1), hi, cmp);
+ hi = i - 1;
+ }
+ }
+}
+
+static
+_lqsort(base, lo, hi, cmp)
+register long *base;
+register int lo;
+register int hi;
+register int (*cmp) ();
+{
+ long k;
+ register int i, j, t;
+ register long *p = &k;
+
+ while (hi > lo)
+ {
+ i = lo;
+ j = hi;
+ t = PIVOT;
+ *p = base[t];
+ base[t] = base[i];
+ base[i] = *p;
+ while (i < j)
+ {
+ while (((*cmp) ((base + j), p)) > 0)
+ --j;
+ base[i] = base[j];
+ while ((i < j) && (((*cmp) ((base + i), p)) <= 0))
+ ++i;
+ base[j] = base[i];
+ }
+ base[i] = *p;
+ if ((i - lo) < (hi - i))
+ {
+ _lqsort(base, lo, (i - 1), cmp);
+ lo = i + 1;
+ }
+ else
+ {
+ _lqsort(base, (i + 1), hi, cmp);
+ hi = i - 1;
+ }
+ }
+}
+
+static
+_nqsort(base, lo, hi, size, cmp)
+register char *base;
+register int lo;
+register int hi;
+register int size;
+register int (*cmp) ();
+{
+ register int i, j;
+ register char *p = _qbuf;
+
+ while (hi > lo)
+ {
+ i = lo;
+ j = hi;
+ p = (base + size * PIVOT);
+ moveitem(_qbuf, p, size);
+ moveitem(p, (base + size * i), size);
+ moveitem((base + size * i), _qbuf, size);
+ p = _qbuf;
+ while (i < j)
+ {
+ while (((*cmp) ((base + size * j), p)) > 0)
+ --j;
+ moveitem((base + size * i), (base + size * j), size);
+ while ((i < j) && (((*cmp) ((base + size * i), p)) <= 0))
+ ++i;
+ moveitem((base + size * j), (base + size * i), size);
+ }
+ moveitem((base + size * i), p, size);
+ if ((i - lo) < (hi - i))
+ {
+ _nqsort(base, lo, (i - 1), size, cmp);
+ lo = i + 1;
+ }
+ else
+ {
+ _nqsort(base, (i + 1), hi, size, cmp);
+ hi = i - 1;
+ }
+ }
+}
+
+qsort(base, num, size, cmp)
+char *base;
+int num;
+int size;
+int (*cmp) ();
+{
+ char _qtemp[128];
+
+ if (_qbuf == 0)
+ {
+ if (size > sizeof(_qtemp))/* records too large! */
+ return;
+ _qbuf = _qtemp;
+ }
+ if (size == 2)
+ _wqsort(base, 0, num - 1, cmp);
+ else if (size == 4)
+ _lqsort(base, 0, num - 1, cmp);
+ else
+ _nqsort(base, 0, num - 1, size, cmp);
+ if (_qbuf == _qtemp)
+ _qbuf = 0;
+}
diff --git a/libc/misc/rand.c b/libc/misc/rand.c
new file mode 100644
index 0000000..4eb0789
--- /dev/null
+++ b/libc/misc/rand.c
@@ -0,0 +1,61 @@
+#ifdef ZX81_RNG
+/*
+ * This is my favorite tiny RNG, If you had a ZX81 you may recognise it :-)
+ * (RdeBath)
+ */
+
+#include <stdlib.h>
+
+#define MAXINT (((unsigned)-1)>>1)
+
+static unsigned int sseed = 0;
+
+int rand()
+{
+ return ( sseed = (((sseed+1L)*75L)%65537L)-1 ) & MAXINT;
+}
+
+void srand(seed)
+unsigned int seed;
+{
+ sseed=seed;
+}
+
+#else
+
+/*
+ * This generator is a combination of three linear congruential generators
+ * with periods or 2^15-405, 2^15-1041 and 2^15-1111. It has a period that
+ * is the product of these three numbers.
+ */
+
+static int seed1 = 1;
+static int seed2 = 1;
+static int seed3 = 1;
+#define MAXINT (((unsigned)-1)>>1)
+
+#define CRANK(a,b,c,m,s) \
+ q = s/a; \
+ s = b*(s-a*q) - c*q; \
+ if(s<0) s+=m;
+
+int rand()
+{
+ register int q, z;
+ CRANK(206, 157, 31, 32363, seed1);
+ CRANK(217, 146, 45, 31727, seed2);
+ CRANK(222, 142, 133, 31657, seed3);
+
+ return seed1^seed2^seed3;
+}
+
+void srand(seed)
+unsigned int seed;
+{
+ seed &= MAXINT;
+ seed1= seed%32362 + 1;
+ seed2= seed%31726 + 1;
+ seed3= seed%31656 + 1;
+}
+
+#endif
diff --git a/libc/misc/setenv.c b/libc/misc/setenv.c
new file mode 100644
index 0000000..10b32d2
--- /dev/null
+++ b/libc/misc/setenv.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 1992, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+extern char ** environ;
+
+int
+setenv(name, value, replace)
+__const char *name;
+__const char *value;
+int replace;
+{
+ register char **ep;
+ register size_t size;
+ __const size_t namelen = strlen (name);
+ __const size_t vallen = strlen (value);
+ int result = 0;
+
+ size = 0;
+ for (ep = environ; *ep != NULL; ++ep)
+ if (!memcmp (*ep, name, namelen) && (*ep)[namelen] == '=')
+ break;
+ else
+ ++size;
+
+ if (*ep == NULL)
+ {
+ static char **last_environ = NULL;
+ char **new_environ = (char **) malloc((size + 2) * sizeof(char *));
+ if (new_environ == NULL)
+ {
+ result = -1;
+ goto do_return;
+ }
+ (void) memcpy((void*) new_environ, (void*) environ, size * sizeof(char *));
+
+ new_environ[size] = malloc (namelen + 1 + vallen + 1);
+ if (new_environ[size] == NULL)
+ {
+ free (new_environ);
+ errno = ENOMEM;
+ result = -1;
+ goto do_return;
+ }
+ memcpy (new_environ[size], name, namelen);
+ new_environ[size][namelen] = '=';
+ memcpy (&new_environ[size][namelen + 1], value, vallen + 1);
+
+ new_environ[size + 1] = NULL;
+
+ if (last_environ != NULL)
+ free ((void*) last_environ);
+ last_environ = new_environ;
+ environ = new_environ;
+ }
+ else if (replace)
+ {
+ size_t len = strlen (*ep);
+ if (len < namelen + 1 + vallen)
+ {
+ char *new = malloc (namelen + 1 + vallen + 1);
+ if (new == NULL)
+ {
+ result = -1;
+ goto do_return;
+ }
+ *ep = new;
+ }
+ memcpy (*ep, name, namelen);
+ (*ep)[namelen] = '=';
+ memcpy (&(*ep)[namelen + 1], value, vallen + 1);
+ }
+
+do_return:
+ return result;
+}
+
+void
+unsetenv(name)
+__const char *name;
+{
+ register char **ep;
+ register char **dp;
+ __const size_t namelen = strlen (name);
+
+ for (dp = ep = environ; *ep != NULL; ++ep)
+ if (memcmp (*ep, name, namelen) || (*ep)[namelen] != '=')
+ {
+ *dp = *ep;
+ ++dp;
+ }
+ *dp = NULL;
+}
diff --git a/libc/misc/strtod.c b/libc/misc/strtod.c
new file mode 100644
index 0000000..cef9d9f
--- /dev/null
+++ b/libc/misc/strtod.c
@@ -0,0 +1,100 @@
+/*
+ * strtod.c - This file is part of the libc-8086 package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifndef __AS386_16__
+/* BCC-16 has broken FP code */
+
+double
+strtod(const char *nptr, char ** endptr)
+{
+ unsigned short negative;
+ double number;
+ double fp_part;
+ int exponent;
+ unsigned short exp_negative;
+
+ /* advance beyond any leading whitespace */
+ while (isspace(*nptr))
+ nptr++;
+
+ /* check for optional '+' or '-' */
+ negative=0;
+ if (*nptr=='-')
+ {
+ negative=1;
+ nptr++;
+ }
+ else
+ if (*nptr=='+')
+ nptr++;
+
+ number=0;
+ while (isdigit(*nptr))
+ {
+ number=number*10+(*nptr-'0');
+ nptr++;
+ }
+
+ if (*nptr=='.')
+ {
+ nptr++;
+ fp_part=0;
+ while (isdigit(*nptr))
+ {
+ fp_part=fp_part/10.0 + (*nptr-'0')/10.0;
+ nptr++;
+ }
+ number+=fp_part;
+ }
+
+ if (*nptr=='e' || *nptr=='E')
+ {
+ nptr++;
+ exp_negative=0;
+ if (*nptr=='-')
+ {
+ exp_negative=1;
+ nptr++;
+ }
+ else
+ if (*nptr=='+')
+ nptr++;
+
+ exponent=0;
+ while (isdigit(*nptr))
+ {
+ exponent=exponent*10+(*nptr-'0');
+ exponent++;
+ }
+ }
+
+ while (exponent)
+ {
+ if (exp_negative)
+ number/=10;
+ else
+ number*=10;
+ exponent--;
+ }
+ return (negative ? -number:number);
+}
+#endif
diff --git a/libc/misc/strtol.c b/libc/misc/strtol.c
new file mode 100644
index 0000000..bcd3334
--- /dev/null
+++ b/libc/misc/strtol.c
@@ -0,0 +1,106 @@
+/*
+ * strtol.c - This file is part of the libc-8086 package for ELKS,
+ * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+
+long int
+strtol(const char *nptr, char **endptr, int base)
+{
+ const char * ptr;
+ unsigned short negative;
+ long int number;
+
+ ptr=nptr;
+
+ while (isspace(*ptr))
+ ptr++;
+
+ negative=0;
+ if (*ptr=='-')
+ negative=1;
+
+ number=(long int)strtoul(nptr, endptr, base);
+
+ return (negative ? -number:number);
+}
+
+unsigned long int
+strtoul(const char *nptr, char **endptr, int base)
+{
+ unsigned long int number;
+
+ /* Sanity check the arguments */
+ if (base==1 || base>36 || base<0)
+ base=0;
+
+ /* advance beyond any leading whitespace */
+ while (isspace(*nptr))
+ nptr++;
+
+ /* check for optional '+' or '-' */
+ if (*nptr=='-')
+ nptr++;
+ else
+ if (*nptr=='+')
+ nptr++;
+
+ /* If base==0 and the string begins with "0x" then we're supposed
+ to assume that it's hexadecimal (base 16). */
+ else
+ if (base==0 && *nptr=='0')
+ if (toupper(*(nptr+1))=='X')
+ {
+ base=16;
+ nptr+=2;
+ }
+ /* If base==0 and the string begins with "0" but not "0x",
+ then we're supposed to assume that it's octal (base 8). */
+ else
+ {
+ base=8;
+ nptr++;
+ }
+
+
+ /* If base is still 0 (it was 0 to begin with and the string didn't begin
+ with "0"), then we are supposed to assume that it's base 10 */
+ if (base==0)
+ base=10;
+
+ number=0;
+ while (isalnum(*nptr))
+ {
+ number= (number*base)+((isalpha(*nptr) ? toupper(*nptr) : *nptr)
+ - (isdigit(*nptr) ? '0' : 'A' + 9));
+ nptr++;
+ if (*nptr>'0'+base)
+ break;
+ }
+
+ /* Some code is simply _impossible_ to write with -Wcast-qual .. :-\ */
+ if (endptr!=NULL)
+ *endptr=(char *)nptr;
+
+ /* All done */
+ return number;
+}
+
+
diff --git a/libc/misc/system.c b/libc/misc/system.c
new file mode 100644
index 0000000..f48f68d
--- /dev/null
+++ b/libc/misc/system.c
@@ -0,0 +1,49 @@
+
+#include <stddef.h>
+#include <signal.h>
+
+int
+system(command)
+char * command;
+{
+ int wait_val, wait_ret, pid;
+ __sighandler_t save_quit;
+ __sighandler_t save_int;
+
+ if( command == 0 ) return 1;
+
+ save_quit = signal(SIGQUIT, SIG_IGN);
+ save_int = signal(SIGINT, SIG_IGN);
+
+ if( (pid=vfork()) < 0 )
+ {
+ signal(SIGQUIT, save_quit);
+ signal(SIGINT, save_int);
+ return -1;
+ }
+ if( pid == 0 )
+ {
+ signal(SIGQUIT, SIG_DFL);
+ signal(SIGINT, SIG_DFL);
+
+ execl("/bin/sh", "sh", "-c", command, (char*)0);
+ _exit(127);
+ }
+ /* Signals are not absolutly guarenteed with vfork */
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+
+ do
+ {
+ if( (wait_ret = wait(&wait_val)) == -1 )
+ {
+ wait_val = -1;
+ break;
+ }
+ }
+ while( wait_ret != pid );
+
+ signal(SIGQUIT, save_quit);
+ signal(SIGINT, save_int);
+ return wait_val;
+}
diff --git a/libc/msdos/Config b/libc/msdos/Config
new file mode 100644
index 0000000..ec28084
--- /dev/null
+++ b/libc/msdos/Config
@@ -0,0 +1 @@
+msdos: Msdos system calls
diff --git a/libc/msdos/Makefile b/libc/msdos/Makefile
new file mode 100644
index 0000000..7a5eaa6
--- /dev/null
+++ b/libc/msdos/Makefile
@@ -0,0 +1,45 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+ASRC=msdos.c
+AOBJ= dos_start.o __mkargv.o __mkenvp.o dos__fconv.o dos_read.o \
+ dos_write.o dos_open.o dos_close.o dos_unlink.o dos_lseek.o \
+ dos_segalloc.o dos_segfree.o dos_setvect.o dos_getvect.o \
+ dos_isatty.o dos_getmod.o dos_stat.o
+
+BSRC=i86.c
+BOBJ= __seg_regs.o __peek_es.o __poke_es.o __deek_es.o __doke_es.o \
+ __strchr_es.o
+
+ifeq ($(LIB_CPU),i86)
+ifeq ($(LIB_OS),DOS)
+OBJ=$(AOBJ) $(BOBJ) time.o
+else
+OBJ=$(BOBJ)
+endif
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(BOBJ)): $(BSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
+
diff --git a/libc/msdos/Notes b/libc/msdos/Notes
new file mode 100644
index 0000000..b775dff
--- /dev/null
+++ b/libc/msdos/Notes
@@ -0,0 +1,8 @@
+This is currently a very cutdown version of the syslib.
+
+This also currently does nothing about the difference between 'TEXT' and
+'BINARY' modes but I think that this level of operation should be pure
+binary, the 'TEXT' mode is more suited to stdio where an "fopen(f, "rb")"
+is more reasonable and probably won't break on other OSs.
+
+-Robert.
diff --git a/libc/msdos/i86.c b/libc/msdos/i86.c
new file mode 100644
index 0000000..44de3e3
--- /dev/null
+++ b/libc/msdos/i86.c
@@ -0,0 +1,193 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+/*
+ * These functions will not normally be useful for Linux-8086. But they
+ * can be used and may be useful in the kernel.
+ */
+
+#ifdef __AS386_16__
+
+#ifdef L___seg_regs
+unsigned int
+__get_cs()
+{
+#asm
+ mov ax,cs
+#endasm
+}
+
+unsigned int
+__get_ds()
+{
+#asm
+ mov ax,ds
+#endasm
+}
+
+unsigned int
+__get_es()
+{
+#asm
+ mov ax,es
+#endasm
+}
+
+void
+__set_es(seg)
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov es,ax
+#else
+ mov bx,sp
+ mov es,[bx+2]
+#endif
+#endasm
+}
+#endif
+
+#ifdef L___peek_es
+int
+__peek_es(off)
+unsigned int off;
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov bx,ax
+#else
+ mov bx,sp
+ mov bx,[bx+2]
+#endif
+ seg es
+ mov al,[bx]
+ xor ah,ah
+#endasm
+}
+#endif
+
+#ifdef L___poke_es
+int
+__poke_es(off, value)
+unsigned int off;
+int value;
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov bx,sp
+ mov bx,[bx+2]
+ xchg ax,bx
+#else
+ mov bx,sp
+ mov ax,[bx+4]
+ mov bx,[bx+2]
+#endif
+ seg es
+ mov [bx],al
+ xor ah,ah
+#endasm
+}
+#endif
+
+#ifdef L___deek_es
+int
+__deek_es(off)
+unsigned int off;
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov bx,ax
+#else
+ mov bx,sp
+ mov bx,[bx+2]
+#endif
+ seg es
+ mov ax,[bx]
+#endasm
+}
+#endif
+
+#ifdef L___doke_es
+int
+__doke_es(off, value)
+unsigned int off;
+int value;
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov bx,sp
+ mov bx,[bx+2]
+ xchg ax,bx
+#else
+ mov bx,sp
+ mov ax,[bx+4]
+ mov bx,[bx+2]
+#endif
+ seg es
+ mov [bx],ax
+#endasm
+}
+#endif
+
+#ifdef L___strchr_es
+char *
+__strchr_es(s, c)
+char * s;
+int c;
+{
+#asm
+ mov bx,sp
+ push si
+#if __FIRST_ARG_IN_AX__
+ mov bx,[bx+2]
+ mov si,ax
+#else
+ mov si,[bx+2]
+ mov bx,[bx+4]
+#endif
+ xor ax,ax
+
+#ifdef PARANOID
+ cld
+#endif
+ push ds
+ push es
+ pop ds
+
+in_loop:
+ lodsb
+ cmp al,bl
+ jz got_it
+ or al,al
+ jnz in_loop
+ pop ds
+ pop si
+ ret
+got_it:
+ lea ax,[si-1]
+ pop ds
+ pop si
+
+#endasm
+}
+#endif
+
+#ifdef L___strchr_es
+char *
+__strnget_es(d, s, c)
+char *d, *s;
+int c;
+{
+ int ds, es;
+ char *p = __strchr_es(s, '\0');
+ if(p != 0 && p-s < c)
+ c = p-s+1;
+ ds = __get_ds();
+ es = __get_es();
+
+ __movedata(es, s, ds, d, c);
+}
+#endif
+
+#endif /* __AS386_16__ */
diff --git a/libc/msdos/msdos.c b/libc/msdos/msdos.c
new file mode 100644
index 0000000..2d23374
--- /dev/null
+++ b/libc/msdos/msdos.c
@@ -0,0 +1,646 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#if !__FIRST_ARG_IN_AX__
+#ifdef __AS386_16__
+#ifdef __MSDOS__
+
+#include <dos.h>
+#include <fcntl.h>
+#include <errno.h>
+int errno;
+
+#ifdef L_dos_start
+
+static char * defarg[2] = { "C" };
+static char ** def_environ =defarg+1;
+void (*__cleanup)() = 0;
+
+#asm
+ .data
+export ___envseg
+___envseg:
+ .word 0
+
+export ___psp
+___psp:
+ .word 0
+
+ .text
+
+export _exit
+export __exit
+_exit: ! exit(rv) function
+ mov bx,sp
+ push [bx+2] ! Copy the `rv` for the exit fuctions.
+ mov bx,[___cleanup] ! Call exit, normally this is `__do_exit`
+ test bx,bx
+ je no_clean ! But it`s default is null
+ call bx
+no_clean:
+ inc sp
+ inc sp
+__exit: ! _exit(rv)
+ mov bx,sp
+ mov ax,[bx+2]
+ mov ah,#$4c
+ int #$21
+dos_1_exit:
+ int #$20
+
+ .text
+export ___cstartup ! Crt0 startup
+___cstartup:
+ mov ax,#$3000 ! Get DOS version
+ int $21
+ cmp al,#2 ! DOS 2+ is Ok
+ jb dos_1_exit
+
+ mov dx,cs ! Current CS
+ add dx,#__segoff ! This var generated by the linker
+ mov ds,dx ! Correct DS
+
+ mov [___psp],es ! PSP segment
+ seg es
+ mov ax,[$2c]
+ mov [___envseg],ax ! Enviroment Segment
+
+ ! Now need to free some RAM
+ seg es
+ mov bx,[2] ! Top of Ram
+ mov ax,ds
+ add ax,#4096 ! Top of 64k data seg
+ jc use_tor ! Oops, wrapped
+ cmp ax,bx
+ jnc use_tor ! Bigger than tor
+ mov bx,ax
+use_tor:
+ mov ax,cs ! Work out how big the memseg is needed
+ sub bx,ax
+ mov ah,#$4A ! Set it
+ int $21
+ jnc set_stack ! Good.
+ ! Ooops, problem..
+ ! BX is now how big it can be so set that.
+ ! FIXME should check for BSS v Stack overlap
+ mov ah,#$4A
+ int $21
+
+set_stack: ! Now set SS to the same as DS
+ sub bx,#__segoff ! And SP to the top of available memory.
+ mov cl,#4
+ shl bx,cl
+ sub bx,#2
+ mov ss,dx
+ mov sp,bx
+
+zap_bss: ! Clear the BSS
+ mov es,dx ! ES now data seg
+ mov di,#__edata
+ mov cx,#__end
+ sub cx,di
+ xor ax,ax
+ cld
+ rep
+ stosb
+
+ push [_def_environ] ! Defaults for when nothing is used.
+ mov ax,#_defarg
+ push ax
+ mov ax,#1
+ push ax
+
+ mov si,#auto_start ! Pointer to first autostart function
+auto_run:
+ mov bx,[si]
+ test bx,bx
+ jz no_entry
+ call bx ! Call the function
+no_entry:
+ inc si ! SI at next
+ inc si
+ jmp auto_run ! And round for the next.
+
+call_exit: ! Last item called by above.
+ pop bx ! Be tidy.
+ push ax ! At the end the last called was main() push it`s
+ call _exit ! return val and call exit();
+bad_exit:
+ jmp bad_exit ! Exit returned !!
+
+ loc 2
+ .word _main ! Segment 2 is the trailing pointers, main and the
+ .word call_exit ! routine to call exit.
+data_start:
+
+ .text
+
+#endasm
+
+__E_nosys()
+{
+#asm
+ .text
+
+export sys_call5
+export sys_call4
+export sys_call3
+export sys_call2
+export sys_call1
+export sys_call0
+sys_call5: ! Trap the unemulated Linux86 syscalls
+sys_call4:
+sys_call3:
+sys_call2:
+sys_call1:
+sys_call0:
+
+#endasm
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifdef L___mkargv
+
+#ifdef __AS386_16__
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .word ___mkargv ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+__mkargv(__argc, __argv)
+int __argc;
+char ** __argv;
+{
+ int length, i, argc=1, s=0;
+ char *ptr, *p;
+ __set_es(__psp); /* Pointer to the args */
+ length = __peek_es(0x80); /* Length of cmd line */
+ if( length > 0 )
+ {
+ ptr = (char*) sbrk(length+1); /* Allocate some space */
+
+ for(i=0; i<length; i++) /* Copy it in. */
+ {
+ ptr[i] = __peek_es(0x81+i);
+ if( ptr[i] != ' ' && s == 0 ) { argc++; s=1; }
+ if( ptr[i] == ' ' && s == 1 ) s=0;
+ }
+ ptr[length]=0;
+
+ p= __argv[0];
+ __argv = (char**) sbrk((argc+1)*sizeof(char*));
+ __argv[0] = p; /* FIXME: The real command can be found */
+ __argc=argc;
+
+ argc=1; s=0;
+ for(i=0; i<length; i++)
+ {
+ if( ptr[i] != ' ' && s == 0 ) { __argv[argc++] = ptr+i; s=1; }
+ if( ptr[i] == ' ' && s == 1 ) { ptr[i] = '\0'; s=0; }
+ }
+ __argv[argc] = 0;
+ }
+}
+#endif
+
+#ifdef L___mkenvp
+
+#ifdef __AS386_16__
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .word ___mkenvp ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+char ** environ = 0;
+
+__mkenvp(__argc, __argv, __envp)
+int __argc;
+char ** __argv;
+char ** __envp;
+{
+ /* FIXME !!! */
+}
+#endif
+
+#ifdef L_dos__fconv
+/* This function converts filenames from unix like to DOS. */
+char *
+__fconv(fname)
+char * fname;
+{
+static char buf1[66], buf2[66], *str = 0;
+ register char *p, ch;
+ int dot = 0;
+
+ if( strcmp("/dev/tty", fname) == 0 ) return "CON:";
+
+ if( str == buf1 ) str = buf2; else str = buf1;
+
+ p = str;
+ if( strncmp("/mnt/", fname, 5) == 0 )
+ {
+ strcpy(p, "A:"); p+=2; fname+=4;
+ }
+ /*
+ * POSS:
+ * open("/name/*", ...); looks for an environ var PATH_name=c:\x\y\z
+ */
+
+ while((ch = *fname++) && p < str+65)
+ {
+ if( ( ch >= 'a' && ch <= 'z' )
+ || ( ch >= '0' && ch <= '9' )
+ || ch == ':' || ch == '%' || ch == '-' || ch == '$' )
+ ;
+ else if( ch >= 'A' && ch <= 'Z' )
+ ch = ch-'A'+'a';
+ else if( ch == '.' && dot == 0 )
+ dot = 1;
+ else if( ch == '/' || ch == '\\' )
+ {
+ dot = 0; ch = '\\';
+ }
+ else ch = '_';
+
+ *p++ = ch;
+ }
+ *p++ = '\0';
+ return str;
+}
+#endif
+
+#ifdef L_dos_read
+int
+read(fd, ptr, len)
+int fd;
+char *ptr;
+unsigned len;
+{
+#asm
+ mov bx,sp
+ mov cx,[bx+6]
+ mov dx,[bx+4]
+ mov bx,[bx+2]
+ mov ah,#$3f
+ int #$21
+ jnc readok
+ mov ax,#-1
+readok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_write
+int
+write(fd, ptr, len)
+int fd;
+char *ptr;
+unsigned len;
+{
+#asm
+ mov bx,sp
+ mov cx,[bx+6]
+ mov dx,[bx+4]
+ mov bx,[bx+2]
+ mov ah,#$40
+ int #$21
+ jnc writeok
+ mov ax,#-1
+writeok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_open
+int
+open(fname, type, cmode)
+char * fname;
+int type;
+int cmode;
+{
+ register char * nname = __fconv(fname);
+ int creat_mode = 0;
+ int rv;
+
+ if( (cmode & 0222) == 0 ) creat_mode = 1;
+
+ /* BzzzT. Assume these flags both mean the merge of them */
+ /* BzzzT. Also ignore O_EXCL */
+ if( type & (O_TRUNC|O_CREAT) )
+ rv = __dos_creat(nname, creat_mode);
+
+ else
+ /* Warn, this assumes the standard vals for O_RDWR, O_RDONLY, O_WRONLY */
+ rv = __dos_open(nname, type&O_ACCMODE);
+ if( rv < 0 ) errno=ENOENT;
+ return rv;
+}
+
+__dos_open(fname, mode)
+{
+#asm
+ mov bx,sp
+ mov dx,[bx+2] ;ds:dx points to source string
+ mov al,[bx+4] ;access code
+ mov ah,#$3d ;ask for a open
+ int #$21
+ jnc openok ;return handle if no error
+ mov ax,#-1 ;return -1 if error
+openok:
+#endasm
+}
+
+__dos_creat(fname)
+char * fname;
+{
+#asm
+ mov bx,sp
+ mov dx,[bx+2] ;ds:dx points to source string
+ xor cx,cx ;normal attributes
+ mov ah,#$3c ;ask for a create
+ int #$21
+ jnc creok ;return handle if no error
+ mov ax,#-1 ;return -1 if error
+creok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_close
+close(fd)
+{
+#asm
+ mov bx,sp
+ mov bx,[bx+2] ;file handle
+ mov ah,#$3e ;ask for a close
+ int #$21
+ mov ax,0 ;return 0 if no error
+ jnc closeok
+ mov ax,#-1 ;return -1 if error
+closeok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_unlink
+unlink(fname)
+char * fname;
+{
+#asm
+ mov bx,sp
+ push [bx+2]
+ call ___fconv
+ inc sp
+ inc sp
+ mov dx,ax ;ds:dx points to source string
+ mov ah,#$41 ;ask for a unlink
+ int #$21
+ mov ax,0 ;assume no errors
+ jnc unlok
+ mov ax,#-1 ;return -1 if error
+unlok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_lseek
+long
+lseek(fd, offset, mode)
+int fd, mode;
+long offset;
+{
+#asm
+ mov bx,sp
+ mov al,[bx+8] ;mode of seek (0 to 2)
+ mov dx,[bx+4] ;cx:dx is long offset
+ mov cx,[bx+6]
+ mov bx,[bx+2] ;file handle
+ mov ah,#$42
+ int #$21 ;do the lseek
+ jnc seekok
+ mov ax,#-1 ;return -1 if error
+ mov dx,ax
+seekok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_segalloc
+unsigned int
+__segalloc(paracount)
+unsigned int paracount;
+{
+#asm
+ mov bx,sp
+ mov bx,[bx+2]
+ mov ah,#$48
+ int $21
+ jnc ok
+ mov ax,#0
+ok:
+#endasm
+}
+#endif
+
+#ifdef L_dos_segfree
+unsigned int
+__segfree(segno)
+unsigned int segno;
+{
+#asm
+ push es
+ mov bx,sp
+ mov es,[bx+4]
+ mov ah,#$49
+ int $21
+ jc err
+ mov ax,#0
+err:
+ pop es
+#endasm
+}
+#endif
+
+#ifdef L_dos_setvect
+void
+__setvect(i,j)
+int i;
+long j;
+{
+#asm
+ mov bx,sp
+ mov ax,[bx+2]
+ mov dx,[bx+4]
+ mov bx,[bx+6]
+ push ds
+ test bx,bx
+ jnz got_seg
+ mov bx,cs
+got_seg:
+ mov ds,bx
+ mov ah,#$25
+ int $21
+ pop ds
+#endasm
+}
+#endif
+
+#ifdef L_dos_getvect
+long
+__getvect(vecno)
+int vecno;
+{
+#asm
+ mov bx,sp
+ mov ax,[bx+2]
+ mov ah,#$35
+ push es
+ int #$21
+ mov dx,es
+ mov ax,bx
+ pop es
+#endasm
+}
+#endif
+
+#ifdef L_dos_getmod
+int
+__dos_getmod(fname)
+{
+#asm
+#if __FIRST_ARG_IN_AX__
+ mov dx,ax
+#else
+ mov bx,sp
+ mov dx,[bx+2]
+#endif
+ mov ax,#$4300
+ int #$21
+ jnc statok
+ mov cx,#-1
+statok:
+ mov ax,cx
+#endasm
+}
+#endif
+
+#ifdef L_dos_stat
+int
+__dos_stat(fname, dtaptr)
+{
+#asm
+ mov bx,sp
+#if __FIRST_ARG_IN_AX__
+ mov cx,ax
+ mov dx,[bx+2]
+#else
+ mov dx,[bx+4]
+#endif
+ mov ah,#$1A ; Set DTA to requested
+ int #$21
+#if __FIRST_ARG_IN_AX__
+ mov ax,cx
+#else
+ mov dx,[bx+2]
+#endif
+ mov ax,#$4300 ; Locate the file
+ int #$21
+ jc nonesuch
+ mov ax,#$4e00 ; Get all the available information.
+ int #$21
+ jc nonesuch
+ xor ax,ax
+ ret
+nonesuch:
+ mov ax,#2
+ mov _errno,ax
+ mov ax,#-1
+#endasm
+}
+#endif
+
+#ifdef L_dos_isatty
+isatty(fd)
+int fd;
+{
+#asm
+ mov bx,sp
+ mov bx,[bx+2]
+ mov ah,#$44
+ mov al,#0
+ int #$21
+ xor ax,ax
+ test dx,#$80
+ jz not_tty
+ inc ax
+not_tty:
+#endasm
+}
+#endif
+
+#endif /* __MSDOS__ */
+#endif /* __AS386_16__ */
+#endif /* !__FIRST_ARG_IN_AX__ */
+
+/*
+# Name No Args Flag, comment
+CHDIR 12 1
+TIME 13 1 * No long return val, arg _must_ exist.
+MKNOD 14 3
+CHMOD 15 2
+CHOWN 16 3
+BRK 17 1 * This is only to tell the system
+STAT 18 2
+GETPID 20 1 * This gets both pid & ppid
+MOUNT 21 3 * Need more args & no ELKS
+UMOUNT 22 1 . No ELKS
+SETUID 23 1
+GETUID 24 1 * This gets both uid and euid
+STIME 25 2 . No ELKS should be 1 LONG arg
+PTRACE 26 X +
+ALARM 27 2 ? No unused return.
+FSTAT 28 2
+PAUSE 29 0
+UTIME 30 2
+STTY 31 2 . ELKS ain't got this and it'll probably change
+GTTY 32 2 . ELKS ain't got this and it'll probably change
+ACCESS 33 2
+NICE 34 1
+FTIME 35 1 . ELKS ain't got this.
+SYNC 36 0
+KILL 37 2
+RENAME 38 2
+MKDIR 39 2
+RMDIR 40 1
+DUP 41 X - Using nasty fcntl function
+PIPE 42 1
+TIMES 43 1
+PROF 44 X +
+SETGID 46 1
+GETGID 47 1 * This gets both gid and egid
+SIGNAL 48 2 +
+ACCT 51 X +
+PLOCK 53 X +
+IOCTL 54 3
+FCNTL 55 3
+EXEC 59 2 ?
+UMASK 60 1
+CHROOT 61 1
+SIGACTION 71 X
+SIGSUSPEND 72 X
+SIGPENDING 73 X
+SIGPROCMASK 74 X
+SIGRETURN 75 X
+REBOOT 76 3 . No ELKS and the magic number will be diff.
+*/
+
diff --git a/libc/msdos/time.c b/libc/msdos/time.c
new file mode 100644
index 0000000..0a66da8
--- /dev/null
+++ b/libc/msdos/time.c
@@ -0,0 +1,63 @@
+
+#include <time.h>
+
+static int mdays[13] = { 0,31,31+28,31+28+31,31+28+31+30,
+ 31+28+31+30+31,31+28+31+30+31+30,31+28+31+30+31+30+31,
+ 31+28+31+30+31+30+31+31,31+28+31+30+31+30+31+31+30,
+ 31+28+31+30+31+30+31+31+30+31,31+28+31+30+31+30+31+31+30+31+30,
+ 365 };
+
+#define SECSPERHOUR (60*60)
+#define SECSPERDAY (SECSPERHOUR*24L)
+
+/****************************************
+ * Return the number of seconds that have elapsed since the start
+ * of 1970.
+ * Input:
+ * timer pointer to where to store result (or NULL)
+ * Output:
+ * *timer = result (unless timer == NULL)
+ * Returns:
+ * time
+ */
+
+static long get_time(ah)
+{
+#asm
+#if !__FIST_ARG_IN_AX__
+ mov bx,sp
+ mov ax,[bx+2]
+#endif
+ mov ah,al
+ int $21
+ mov ax,dx
+ mov dx,cx
+#endasm
+}
+
+time_t time(timer)
+time_t *timer;
+{
+ unsigned day,month,year;
+ long rv;
+ time_t t;
+
+ rv = get_time(0x2C);
+ rv >>= 8; t = (rv & 0xFF);
+ rv >>= 8; t += (rv & 0xFF)*60;
+ rv >>= 8; t += (rv & 0xFF)*3600;
+
+ rv = get_time(0x2A);
+ day = (rv & 0xFF);
+ rv >>= 8; month = (rv & 0xFF) -1;
+ rv >>= 8; year = (rv & 0xFFFF) - 1970;
+
+ if (month <= 1 || year & 3) /* if before Feb or not a leap year */
+ day--; /* don't add day for leap year */
+ day += mdays[month]; /* day in year */
+ day += (year + 3) >> 2; /* add a day for each leap year */
+ t += ((year * 365L) + day) * SECSPERDAY;
+ if (timer)
+ *timer = t;
+ return t;
+}
diff --git a/libc/regexp/Config b/libc/regexp/Config
new file mode 100644
index 0000000..bd644a6
--- /dev/null
+++ b/libc/regexp/Config
@@ -0,0 +1 @@
+regexp: Regular expression lib
diff --git a/libc/regexp/Makefile b/libc/regexp/Makefile
new file mode 100644
index 0000000..0276aba
--- /dev/null
+++ b/libc/regexp/Makefile
@@ -0,0 +1,27 @@
+
+OBJ=regexp.o regsub.o
+LSRC=regexp.c regsub.c regerror.c
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+transfer:
+ -@rm -f ../include/regexp.h ../include/regmagic.h
+ cp -p regexp.h regmagic.h ../include/.
+
+$(LIBC)(regexp.o): regexp.c regexp.h regmagic.h
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)(regsub.o): regsub.c regexp.h regmagic.h
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+clean:
+ rm -f libc.a *.o core mon.out timer.t.h dMakefile dtr try timer
diff --git a/libc/regexp/Makefile.org b/libc/regexp/Makefile.org
new file mode 100644
index 0000000..a8be06e
--- /dev/null
+++ b/libc/regexp/Makefile.org
@@ -0,0 +1,63 @@
+# Things you might want to put in ENV and LENV:
+# -Dvoid=int compilers that don't do void
+# -DCHARBITS=0377 compilers that don't do unsigned char
+# -DSTATIC=extern compilers that don't like "static foo();" as forward decl
+# -DSTRCSPN library does not have strcspn()
+# -Dstrchr=index library does not have strchr()
+# -DERRAVAIL have utzoo-compatible error() function and friends
+# ENV=-DCHARBITS=0377
+# LENV=-DCHARBITS=0377
+
+# Things you might want to put in TEST:
+# -DDEBUG debugging hooks
+# -I. regexp.h from current directory, not /usr/include
+TEST=-I.
+
+# Things you might want to put in PROF:
+# -Dstatic='/* */' make everything global so profiler can see it.
+# -p profiler
+PROF=
+
+CFLAGS=-O $(ENV) $(TEST) $(PROF)
+LINTFLAGS=$(LENV) $(TEST) -ha
+LDFLAGS=-i
+
+OBJ=regexp.o regsub.o
+LSRC=regexp.c regsub.c regerror.c
+DTR=README dMakefile regexp.3 regexp.h regexp.c regsub.c regerror.c \
+ regmagic.h try.c timer.c tests
+
+try: try.o $(OBJ)
+ cc $(LDFLAGS) try.o $(OBJ) -o try
+
+# Making timer will probably require putting stuff in $(PROF) and then
+# recompiling everything; the following is just the final stage.
+timer: timer.o $(OBJ)
+ cc $(LDFLAGS) $(PROF) timer.o $(OBJ) -o timer
+
+timer.o: timer.c timer.t.h
+
+timer.t.h: tests
+ sed 's/ /","/g;s/\\/&&/g;s/.*/{"&"},/' tests >timer.t.h
+
+# Regression test.
+r: try tests
+ @echo 'No news is good news...'
+ try <tests
+
+lint: timer.t.h
+ @echo 'Complaints about multiply-declared regerror() are legit.'
+ lint $(LINTFLAGS) $(LSRC) try.c
+ lint $(LINTFLAGS) $(LSRC) timer.c
+
+regexp.o: regexp.c regexp.h regmagic.h
+regsub.o: regsub.c regexp.h regmagic.h
+
+clean:
+ rm -f *.o core mon.out timer.t.h dMakefile dtr try timer
+
+dtr: r makedtr $(DTR)
+ makedtr $(DTR) >dtr
+
+dMakefile: Makefile
+ sed '/^L*ENV=/s/ *-DERRAVAIL//' Makefile >dMakefile
diff --git a/libc/regexp/README b/libc/regexp/README
new file mode 100644
index 0000000..37d6f51
--- /dev/null
+++ b/libc/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/libc/regexp/README.rdb b/libc/regexp/README.rdb
new file mode 100644
index 0000000..1c3bba6
--- /dev/null
+++ b/libc/regexp/README.rdb
@@ -0,0 +1,6 @@
+
+I've applied the four bugfix patches I've found and made a couple of
+very small changes (added malloc.h) and put in a new Makefile.
+Otherwise this is as it was posted on by Henry Spencer to mod.sources.
+
+-Robert
diff --git a/libc/regexp/patch.1 b/libc/regexp/patch.1
new file mode 100644
index 0000000..6126592
--- /dev/null
+++ b/libc/regexp/patch.1
@@ -0,0 +1,32 @@
+Subject: bug in regexp(3), and fix
+Newsgroups: mod.sources
+Approved: jpn@panda.UUCP
+
+Mod.sources: Volume 3, Issue 105
+Submitted by: genrad!decvax!utzoo!henry
+
+Drat! Chris Siebenmann at CSRI just found a bug in my regexp(3) routines.
+The problem is that the code for character classes does not check properly
+for the possibility that it might be looking at the end of the string. By
+simple bad luck none of my test cases hit this. To fix it, make the
+following two changes to regexp.c:
+
+848c848
+< if (strchr(OPERAND(scan), *reginput) == NULL)
+---
+> if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
+853c853
+< if (strchr(OPERAND(scan), *reginput) != NULL)
+---
+> if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
+
+and recompile. Also, add the following line to the "tests" file:
+
+[k] ab n - -
+
+My thanks to Chris for finding this.
+
+ Henry Spencer @ U of Toronto Zoology
+ {allegra,ihnp4,linus,decvax}!utzoo!henry
+
+
diff --git a/libc/regexp/patch.2 b/libc/regexp/patch.2
new file mode 100644
index 0000000..fcf4778
--- /dev/null
+++ b/libc/regexp/patch.2
@@ -0,0 +1,27 @@
+Subject: 2nd bug fix for regexp(3), in regsub()
+Newsgroups: mod.sources
+Approved: jpn@panda.UUCP
+
+Mod.sources: Volume 4, Issue 33
+Submitted by: genrad!decvax!utzoo!henry
+
+I cringe with embarrassment! Another bug in regexp! In regsub.c, the
+following line (line 72 in the original distribution):
+
+ if (*(dst-1) == '\0') { /* strncpy hit NUL. */
+
+should read
+
+ if (len != 0 && *(dst-1) == '\0') { /* strncpy hit NUL. */
+
+This shows up as an occasional spurious complaint from regsub about
+"damaged match string"... *if* the program invoking it, and the compiler
+compiling it, happen to interact just right. It didn't show in any of
+my tests because mine don't.
+
+My thanks to H}vard Eidnes for finding this.
+
+ Henry Spencer @ U of Toronto Zoology
+ {allegra,ihnp4,linus,decvax}!utzoo!henry
+
+
diff --git a/libc/regexp/patch.3 b/libc/regexp/patch.3
new file mode 100644
index 0000000..36bafd4
--- /dev/null
+++ b/libc/regexp/patch.3
@@ -0,0 +1,46 @@
+Subject: regexp(3) improvement
+Newsgroups: mod.sources
+Approved: jpn@panda.UUCP
+
+Mod.sources: Volume 4, Issue 49
+Submitted by: utzoo!henry (Henry Spencer)
+
+One flaw of my regexp(3) as distributed is that there is no way to get
+a literal `&' or '\n' (n a digit) past regsub(). The V8 manual page
+made no mention of an escape convention. It turns out that this is a
+deficiency in the documentation rather than the software. Accordingly,
+the following update should be applied to my regexp(3) to preserve full
+compatibility and to add this useful facility.
+
+In regsub.c, change the following (line numbers approximate only):
+
+67,69c67,71
+< if (no < 0) /* Ordinary character. */
+< *dst++ = c;
+< else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+---
+> if (no < 0) { /* Ordinary character. */
+> if (c == '\\' && (*src == '\\' || *src == '&'))
+> c = *src++;
+> *dst++ = c;
+> } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) {
+
+In regexp.3, add the following sentence to the end of the paragraph
+describing regsub:
+
+To get a literal `&' or `\e\fIn\fR' into \fIdest\fR, prefix it with `\e';
+to get a literal `\e' preceding `&' or `\e\fIn\fR', prefix it with
+another `\e'.
+
+And add the following two lines to the "tests" file:
+
+abcd abcd y &-\&-\\& abcd-&-\abcd
+a(bc)d abcd y \1-\\1-\\\1 bc-\1-\bc
+
+My thanks to Mike Lutz at Rochester Institute of Technology for noticing
+this issue and alerting me to it.
+
+ Henry Spencer @ U of Toronto Zoology
+ {allegra,ihnp4,decvax,pyramid}!utzoo!henry
+
+
diff --git a/libc/regexp/patch.4 b/libc/regexp/patch.4
new file mode 100644
index 0000000..4d8ea3a
--- /dev/null
+++ b/libc/regexp/patch.4
@@ -0,0 +1,65 @@
+Path: uunet!rs
+From: rs@uunet.UU.NET (Rich Salz)
+Newsgroups: comp.sources.unix
+Subject: v10i097: Bug-fix for regexp() library
+Message-ID: <789@uunet.UU.NET>
+Date: 7 Aug 87 11:20:15 GMT
+Organization: UUNET Communications Services, Arlington, VA
+Lines: 46
+Approved: rs@uunet.UU.NET
+
+Submitted-by: seismo!ai.toronto.edu!utzoo!henry
+Posting-number: Volume 10, Issue 97
+Archive-name: regexp.pch
+
+FURTHER NOTE by Rich $alz on Tue Apr 26 20:02:59 EDT 1988:
+ This is a patch for Henry's regexp posting that appeared in
+ volume 3 (first patch was volume3/regexp2; the naming
+ convention used by my predecessor). There is another
+ regexp library in volume 7 -- they're unreleated.
+
+ The "fastgrep" posting appeards in volume 9. It also includes
+ Henry's volume3 posting and both sets of patches.
+
+[ Regexp was published by itself in volume 6, and also as part of the
+ "fastest grep around" earlier in this volume. --r$ ]
+
+Jeff Mc Carrell at Berkeley has found (gasp! choke! the horror! the horror!)
+another bug in my regexp functions. One thing my test set did not include
+was very large regular expressions. The bug is in the NEXT macro, which
+digs out the offset to the next node of the regexp: a parenthesization
+botch makes trouble if the offset is ever larger than 255. How humiliating.
+Here is the fix to regexp.c:
+
+116c116
+< #define NEXT(p) (((*((p)+1)&0377)<<8) + *((p)+2)&0377)
+---
+> #define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+
+and here are some more lines for the "tests" file:
+
+[ -~]* abc y & abc
+[ -~ -~]* abc y & abc
+[ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~ -~ -~ -~]* abc y & abc
+
+
+Just to let people know: there is some prospect of me coming out with
+a second edition of my regexp stuff, including a number of improvements
+that various people have suggested/contributed. However, it will not be
+soon, because I'm very busy right now. I can't spare the time to sort
+it all out, decide what belongs and what doesn't, write the missing bits
+of code, and integrate it all. Sometime later this year, maybe.
+
+ Henry Spencer @ U of Toronto Zoology
+ {allegra,ihnp4,decvax,pyramid}!utzoo!henry
+
+
+--
+
+Rich $alz "Anger is an energy"
+Cronus Project, BBN Labs rsalz@bbn.com
+Moderator, comp.sources.unix sources@uunet.uu.net
diff --git a/libc/regexp/regerror.c b/libc/regexp/regerror.c
new file mode 100644
index 0000000..63864c7
--- /dev/null
+++ b/libc/regexp/regerror.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+void
+regerror(s)
+char *s;
+{
+#ifdef ERRAVAIL
+ error("regexp: %s", s);
+#else
+ fprintf(stderr, "regexp(3): %s", s);
+ exit(1);
+#endif
+ /* NOTREACHED */
+}
diff --git a/libc/regexp/regexp.3 b/libc/regexp/regexp.3
new file mode 100644
index 0000000..c0e29ea
--- /dev/null
+++ b/libc/regexp/regexp.3
@@ -0,0 +1,176 @@
+.TH REGEXP 3 local
+.DA 30 Nov 1985
+.SH NAME
+regcomp, regexec, regsub, regerror \- regular expression handler
+.SH SYNOPSIS
+.ft B
+.nf
+#include <regexp.h>
+
+regexp *regcomp(exp)
+char *exp;
+
+int regexec(prog, string)
+regexp *prog;
+char *string;
+
+regsub(prog, source, dest)
+regexp *prog;
+char *source;
+char *dest;
+
+regerror(msg)
+char *msg;
+.SH DESCRIPTION
+These functions implement
+.IR egrep (1)-style
+regular expressions and supporting facilities.
+.PP
+.I Regcomp
+compiles a regular expression into a structure of type
+.IR regexp ,
+and returns a pointer to it.
+The space has been allocated using
+.IR malloc (3)
+and may be released by
+.IR free .
+.PP
+.I Regexec
+matches a NUL-terminated \fIstring\fR against the compiled regular expression
+in \fIprog\fR.
+It returns 1 for success and 0 for failure, and adjusts the contents of
+\fIprog\fR's \fIstartp\fR and \fIendp\fR (see below) accordingly.
+.PP
+The members of a
+.I regexp
+structure include at least the following (not necessarily in order):
+.PP
+.RS
+char *startp[NSUBEXP];
+.br
+char *endp[NSUBEXP];
+.RE
+.PP
+where
+.I NSUBEXP
+is defined (as 10) in the header file.
+Once a successful \fIregexec\fR has been done using the \fIregexp\fR,
+each \fIstartp\fR-\fIendp\fR pair describes one substring
+within the \fIstring\fR,
+with the \fIstartp\fR pointing to the first character of the substring and
+the \fIendp\fR pointing to the first character following the substring.
+The 0th substring is the substring of \fIstring\fR 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
+.I Regsub
+copies \fIsource\fR to \fIdest\fR, making substitutions according to the
+most recent \fIregexec\fR performed using \fIprog\fR.
+Each instance of `&' in \fIsource\fR is replaced by the substring
+indicated by \fIstartp\fR[\fI0\fR] and
+\fIendp\fR[\fI0\fR].
+Each instance of `\e\fIn\fR', where \fIn\fR is a digit, is replaced by
+the substring indicated by
+\fIstartp\fR[\fIn\fR] and
+\fIendp\fR[\fIn\fR].
+.PP
+.I Regerror
+is called whenever an error is detected in \fIregcomp\fR, \fIregexec\fR,
+or \fIregsub\fR.
+The default \fIregerror\fR writes the string \fImsg\fR,
+with a suitable indicator of origin,
+on the standard
+error output
+and invokes \fIexit\fR(2).
+.I Regerror
+can be replaced by the user if other actions are desirable.
+.SH "REGULAR EXPRESSION SYNTAX"
+A regular expression is zero or more \fIbranches\fR, separated by `|'.
+It matches anything that matches one of the branches.
+.PP
+A branch is zero or more \fIpieces\fR, concatenated.
+It matches a match for the first, followed by a match for the second, etc.
+.PP
+A piece is an \fIatom\fR 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 \fIrange\fR (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 \fIrange\fR 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 \fInot\fR from the rest of the sequence.
+If two characters in the sequence are separated by `\-', this is shorthand
+for the full list of 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, `(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 `ab*', presented with `xabbbby', will match `abbbb'.
+Note that if `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 SEE ALSO
+egrep(1), expr(1)
+.SH DIAGNOSTICS
+\fIRegcomp\fR returns NULL for a failure
+(\fIregerror\fR permitting),
+where failures are syntax errors, exceeding implementation limits,
+or applying `+' or `*' to a possibly-null operand.
+.SH HISTORY
+Both code and manual page were
+written at U of T.
+They are intended to be compatible with the Bell V8 \fIregexp\fR(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 \fIegrep\fR's newline-separated branches;
+neither does the V8 \fIregexp\fR(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/libc/regexp/regexp.c b/libc/regexp/regexp.c
new file mode 100644
index 0000000..860b485
--- /dev/null
+++ b/libc/regexp/regexp.c
@@ -0,0 +1,1213 @@
+/*
+ * 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.
+ *
+ * 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 <stdio.h>
+#include <regexp.h>
+#include <malloc.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 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) == '?')
+#define META "^$.[()|?+*\\"
+
+/*
+ * 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)
+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. */
+ regparse = 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 = 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++;
+ 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 != ')') {
+ 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++) {
+ 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 ')':
+ FAIL("internal urp"); /* Supposed to be caught earlier. */
+ break;
+ case '?':
+ case '+':
+ case '*':
+ FAIL("?+* follows nothing");
+ break;
+ case '\\':
+ if (*regparse == '\0')
+ FAIL("trailing \\");
+ ret = regnode(EXACTLY);
+ regc(*regparse++);
+ regc('\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ default: {
+ register int len;
+ register char ender;
+
+ regparse--;
+ len = strcspn(regparse, META);
+ if (len <= 0)
+ FAIL("internal disaster");
+ ender = *(regparse+len);
+ if (len > 1 && ISMULT(ender))
+ len--; /* Back off clear of ?+* operand. */
+ *flagp |= HASWIDTH;
+ if (len == 1)
+ *flagp |= SIMPLE;
+ ret = regnode(EXACTLY);
+ while (len > 0) {
+ regc(*regparse++);
+ len--;
+ }
+ regc('\0');
+ }
+ 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 regexp *prog;
+register char *string;
+{
+ register char *s;
+
+ /* 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 = 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 = string;
+
+ /* Simplest case: anchored match need be tried only once. */
+ if (prog->reganch)
+ return(regtry(prog, string));
+
+ /* Messy cases: unanchored match. */
+ s = 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 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;
+ 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/libc/regexp/regexp.h b/libc/regexp/regexp.h
new file mode 100644
index 0000000..73d6bf4
--- /dev/null
+++ b/libc/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/libc/regexp/regmagic.h b/libc/regexp/regmagic.h
new file mode 100644
index 0000000..5acf447
--- /dev/null
+++ b/libc/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/libc/regexp/regsub.c b/libc/regexp/regsub.c
new file mode 100644
index 0000000..5ca5676
--- /dev/null
+++ b/libc/regexp/regsub.c
@@ -0,0 +1,82 @@
+/*
+ * 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 <stdio.h>
+#include <regexp.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)
+regexp *prog;
+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 = 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/libc/regexp/tests b/libc/regexp/tests
new file mode 100644
index 0000000..e5bc16d
--- /dev/null
+++ b/libc/regexp/tests
@@ -0,0 +1,127 @@
+abc abc y & abc
+abc xbc n - -
+abc axc n - -
+abc abx n - -
+abc xabcy y & abc
+abc ababc y & abc
+ab*c abc y & abc
+ab*bc abc y & abc
+ab*bc abbc y & abbc
+ab*bc abbbbc y & abbbbc
+ab+bc abbc y & abbc
+ab+bc abc n - -
+ab+bc abq n - -
+ab+bc abbbbc y & abbbbc
+ab?bc abbc y & abbc
+ab?bc abc y & abc
+ab?bc abbbbc n - -
+ab?c abc y & abc
+^abc$ abc y & abc
+^abc$ abcc n - -
+^abc abcc y & abc
+^abc$ aabc n - -
+abc$ aabc y & abc
+^ abc y &
+$ abc y &
+a.c abc y & abc
+a.c axc y & axc
+a.*c axyzc y & axyzc
+a.*c axyzd n - -
+a[bc]d abc n - -
+a[bc]d abd y & abd
+a[b-d]e abd n - -
+a[b-d]e ace y & ace
+a[b-d] aac y & ac
+a[-b] a- y & a-
+a[b-] a- y & a-
+a[b-a] - c - -
+a[]b - c - -
+a[ - c - -
+a] a] y & a]
+a[]]b a]b y & a]b
+a[^bc]d aed y & aed
+a[^bc]d abd n - -
+a[^-b]c adc y & adc
+a[^-b]c a-c n - -
+a[^]b]c a]c n - -
+a[^]b]c adc y & adc
+ab|cd abc y & ab
+ab|cd abcd y & ab
+()ef def y &-\1 ef-
+()* - c - -
+*a - c - -
+^* - c - -
+$* - c - -
+(*)b - c - -
+$b b n - -
+a\ - c - -
+a\(b a(b y &-\1 a(b-
+a\(*b ab y & ab
+a\(*b a((b y & a((b
+a\\b a\b y & a\b
+abc) - c - -
+(abc - c - -
+((a)) abc y &-\1-\2 a-a-a
+(a)b(c) abc y &-\1-\2 abc-a-c
+a+b+c aabbabc y & abc
+a** - c - -
+a*? - c - -
+(a*)* - c - -
+(a*)+ - c - -
+(a|)* - c - -
+(a*|b)* - c - -
+(a+|b)* ab y &-\1 ab-b
+(a+|b)+ ab y &-\1 ab-b
+(a+|b)? ab y &-\1 a-a
+[^ab]* cde y & cde
+(^)* - c - -
+(ab|)* - c - -
+)( - c - -
+ abc y &
+abc n - -
+a* y &
+([abc])*d abbbcd y &-\1 abbbcd-c
+([abc])*bcd abcd y &-\1 abcd-a
+a|b|c|d|e e y & e
+(a|b|c|d|e)f ef y &-\1 ef-e
+((a*|b))* - c - -
+abcd*efg abcdefg y & abcdefg
+ab* xabyabbbz y & ab
+ab* xayabbbz y & a
+(ab|cd)e abcde y &-\1 cde-cd
+[abhgefdc]ij hij y & hij
+^(ab|cd)e abcde n x\1y xy
+(abc|)ef abcdef y &-\1 ef-
+(a|b)c*d abcd y &-\1 bcd-b
+(ab|ab*)bc abc y &-\1 abc-a
+a([bc]*)c* abc y &-\1 abc-bc
+a([bc]*)(c*d) abcd y &-\1-\2 abcd-bc-d
+a([bc]+)(c*d) abcd y &-\1-\2 abcd-bc-d
+a([bc]*)(c+d) abcd y &-\1-\2 abcd-b-cd
+a[bcd]*dcdcde adcdcde y & adcdcde
+a[bcd]+dcdcde adcdcde n - -
+(ab|a)b*c abc y &-\1 abc-ab
+((a)(b)c)(d) abcd y \1-\2-\3-\4 abc-a-b-d
+[a-zA-Z_][a-zA-Z0-9_]* alpha y & alpha
+^a(bc+|b[eh])g|.h$ abh y &-\1 bh-
+(bc+d$|ef*g.|h?i(j|k)) effgz y &-\1-\2 effgz-effgz-
+(bc+d$|ef*g.|h?i(j|k)) ij y &-\1-\2 ij-ij-j
+(bc+d$|ef*g.|h?i(j|k)) effg n - -
+(bc+d$|ef*g.|h?i(j|k)) bcdd n - -
+(bc+d$|ef*g.|h?i(j|k)) reffgz y &-\1-\2 effgz-effgz-
+((((((((((a)))))))))) - c - -
+(((((((((a))))))))) a y & a
+multiple words of text uh-uh n - -
+multiple words multiple words, yeah y & multiple words
+(.*)c(.*) abcde y &-\1-\2 abcde-ab-de
+\((.*), (.*)\) (a, b) y (\2, \1) (b, a)
+[k] ab n - -
+abcd abcd y &-\&-\\& abcd-&-\abcd
+a(bc)d abcd y \1-\\1-\\\1 bc-\1-\bc
+[ -~]* abc y & abc
+[ -~ -~]* abc y & abc
+[ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~ -~ -~]* abc y & abc
+[ -~ -~ -~ -~ -~ -~ -~]* abc y & abc
diff --git a/libc/regexp/timer.c b/libc/regexp/timer.c
new file mode 100644
index 0000000..2d84a12
--- /dev/null
+++ b/libc/regexp/timer.c
@@ -0,0 +1,182 @@
+/*
+ * Simple timing program for regcomp().
+ *
+ * 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.
+ *
+ * Usage: timer ncomp nexec nsub
+ * or
+ * timer ncomp nexec nsub regexp string [ answer [ sub ] ]
+ *
+ * The second form is for timing repetitions of a single test case.
+ * The first form's test data is a compiled-in copy of the "tests" file.
+ * Ncomp, nexec, nsub are how many times to do each regcomp, regexec,
+ * and regsub. The way to time an operation individually is to do something
+ * like "timer 1 50 1".
+ */
+#include <stdio.h>
+
+struct try {
+ char *re, *str, *ans, *src, *dst;
+} tests[] = {
+#include "timer.t.h"
+{ NULL, NULL, NULL, NULL, NULL }
+};
+
+#include <regexp.h>
+
+int errreport = 0; /* Report errors via errseen? */
+char *errseen = NULL; /* Error message. */
+
+char *progname;
+
+/* ARGSUSED */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int ncomp, nexec, nsub;
+ struct try one;
+ char dummy[512];
+
+ if (argc < 4) {
+ ncomp = 1;
+ nexec = 1;
+ nsub = 1;
+ } else {
+ ncomp = atoi(argv[1]);
+ nexec = atoi(argv[2]);
+ nsub = atoi(argv[3]);
+ }
+
+ progname = argv[0];
+ if (argc > 5) {
+ one.re = argv[4];
+ one.str = argv[5];
+ if (argc > 6)
+ one.ans = argv[6];
+ else
+ one.ans = "y";
+ if (argc > 7) {
+ one.src = argv[7];
+ one.dst = "xxx";
+ } else {
+ one.src = "x";
+ one.dst = "x";
+ }
+ errreport = 1;
+ try(one, ncomp, nexec, nsub);
+ } else
+ multiple(ncomp, nexec, nsub);
+ exit(0);
+}
+
+void
+regerror(s)
+char *s;
+{
+ if (errreport)
+ errseen = s;
+ else
+ error(s, "");
+}
+
+#ifndef ERRAVAIL
+error(s1, s2)
+char *s1;
+char *s2;
+{
+ fprintf(stderr, "regexp: ");
+ fprintf(stderr, s1, s2);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+#endif
+
+int lineno = 0;
+
+multiple(ncomp, nexec, nsub)
+int ncomp, nexec, nsub;
+{
+ register int i;
+ extern char *strchr();
+
+ errreport = 1;
+ for (i = 0; tests[i].re != NULL; i++) {
+ lineno++;
+ try(tests[i], ncomp, nexec, nsub);
+ }
+}
+
+try(fields, ncomp, nexec, nsub)
+struct try fields;
+int ncomp, nexec, nsub;
+{
+ regexp *r;
+ char dbuf[BUFSIZ];
+ register int i;
+
+ errseen = NULL;
+ r = regcomp(fields.re);
+ if (r == NULL) {
+ if (*fields.ans != 'c')
+ complain("regcomp failure in `%s'", fields.re);
+ return;
+ }
+ if (*fields.ans == 'c') {
+ complain("unexpected regcomp success in `%s'", fields.re);
+ free((char *)r);
+ return;
+ }
+ for (i = ncomp-1; i > 0; i--) {
+ free((char *)r);
+ r = regcomp(fields.re);
+ }
+ if (!regexec(r, fields.str)) {
+ if (*fields.ans != 'n')
+ complain("regexec failure in `%s'", "");
+ free((char *)r);
+ return;
+ }
+ if (*fields.ans == 'n') {
+ complain("unexpected regexec success", "");
+ free((char *)r);
+ return;
+ }
+ for (i = nexec-1; i > 0; i--)
+ (void) regexec(r, fields.str);
+ errseen = NULL;
+ for (i = nsub; i > 0; i--)
+ regsub(r, fields.src, dbuf);
+ if (errseen != NULL) {
+ complain("regsub complaint", "");
+ free((char *)r);
+ return;
+ }
+ if (strcmp(dbuf, fields.dst) != 0)
+ complain("regsub result `%s' wrong", dbuf);
+ free((char *)r);
+}
+
+complain(s1, s2)
+char *s1;
+char *s2;
+{
+ fprintf(stderr, "try: %d: ", lineno);
+ fprintf(stderr, s1, s2);
+ fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : "");
+}
diff --git a/libc/regexp/try.c b/libc/regexp/try.c
new file mode 100644
index 0000000..71620c2
--- /dev/null
+++ b/libc/regexp/try.c
@@ -0,0 +1,238 @@
+/*
+ * Simple test program for regexp(3) stuff. Knows about debugging hooks.
+ *
+ * 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.
+ *
+ * Usage: try re [string [output [-]]]
+ * The re is compiled and dumped, regexeced against the string, the result
+ * is applied to output using regsub(). The - triggers a running narrative
+ * from regexec(). Dumping and narrative don't happen unless DEBUG.
+ *
+ * If there are no arguments, stdin is assumed to be a stream of lines with
+ * five fields: a r.e., a string to match it against, a result code, a
+ * source string for regsub, and the proper result. Result codes are 'c'
+ * for compile failure, 'y' for match success, 'n' for match failure.
+ * Field separator is tab.
+ */
+#include <stdio.h>
+#include <regexp.h>
+
+#ifdef ERRAVAIL
+char *progname;
+extern char *mkprogname();
+#endif
+
+#ifdef DEBUG
+extern int regnarrate;
+#endif
+
+char buf[BUFSIZ];
+
+int errreport = 0; /* Report errors via errseen? */
+char *errseen = NULL; /* Error message. */
+int status = 0; /* Exit status. */
+
+/* ARGSUSED */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ regexp *r;
+ int i;
+
+#ifdef ERRAVAIL
+ progname = mkprogname(argv[0]);
+#endif
+
+ if (argc == 1) {
+ multiple();
+ exit(status);
+ }
+
+ r = regcomp(argv[1]);
+ if (r == NULL)
+ error("regcomp failure", "");
+#ifdef DEBUG
+ regdump(r);
+ if (argc > 4)
+ regnarrate++;
+#endif
+ if (argc > 2) {
+ i = regexec(r, argv[2]);
+ printf("%d", i);
+ for (i = 1; i < NSUBEXP; i++)
+ if (r->startp[i] != NULL && r->endp[i] != NULL)
+ printf(" \\%d", i);
+ printf("\n");
+ }
+ if (argc > 3) {
+ regsub(r, argv[3], buf);
+ printf("%s\n", buf);
+ }
+ exit(status);
+}
+
+void
+regerror(s)
+char *s;
+{
+ if (errreport)
+ errseen = s;
+ else
+ error(s, "");
+}
+
+#ifndef ERRAVAIL
+error(s1, s2)
+char *s1;
+char *s2;
+{
+ fprintf(stderr, "regexp: ");
+ fprintf(stderr, s1, s2);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+#endif
+
+int lineno;
+
+regexp badregexp; /* Implicit init to 0. */
+
+multiple()
+{
+ char rbuf[BUFSIZ];
+ char *field[5];
+ char *scan;
+ int i;
+ regexp *r;
+ extern char *strchr();
+
+ errreport = 1;
+ lineno = 0;
+ while (fgets(rbuf, sizeof(rbuf), stdin) != NULL) {
+ rbuf[strlen(rbuf)-1] = '\0'; /* Dispense with \n. */
+ lineno++;
+ scan = rbuf;
+ for (i = 0; i < 5; i++) {
+ field[i] = scan;
+ if (field[i] == NULL) {
+ complain("bad testfile format", "");
+ exit(1);
+ }
+ scan = strchr(scan, '\t');
+ if (scan != NULL)
+ *scan++ = '\0';
+ }
+ try(field);
+ }
+
+ /* And finish up with some internal testing... */
+ lineno = 9990;
+ errseen = NULL;
+ if (regcomp((char *)NULL) != NULL || errseen == NULL)
+ complain("regcomp(NULL) doesn't complain", "");
+ lineno = 9991;
+ errseen = NULL;
+ if (regexec((regexp *)NULL, "foo") || errseen == NULL)
+ complain("regexec(NULL, ...) doesn't complain", "");
+ lineno = 9992;
+ r = regcomp("foo");
+ if (r == NULL) {
+ complain("regcomp(\"foo\") fails", "");
+ return;
+ }
+ lineno = 9993;
+ errseen = NULL;
+ if (regexec(r, (char *)NULL) || errseen == NULL)
+ complain("regexec(..., NULL) doesn't complain", "");
+ lineno = 9994;
+ errseen = NULL;
+ regsub((regexp *)NULL, "foo", rbuf);
+ if (errseen == NULL)
+ complain("regsub(NULL, ..., ...) doesn't complain", "");
+ lineno = 9995;
+ errseen = NULL;
+ regsub(r, (char *)NULL, rbuf);
+ if (errseen == NULL)
+ complain("regsub(..., NULL, ...) doesn't complain", "");
+ lineno = 9996;
+ errseen = NULL;
+ regsub(r, "foo", (char *)NULL);
+ if (errseen == NULL)
+ complain("regsub(..., ..., NULL) doesn't complain", "");
+ lineno = 9997;
+ errseen = NULL;
+ if (regexec(&badregexp, "foo") || errseen == NULL)
+ complain("regexec(nonsense, ...) doesn't complain", "");
+ lineno = 9998;
+ errseen = NULL;
+ regsub(&badregexp, "foo", rbuf);
+ if (errseen == NULL)
+ complain("regsub(nonsense, ..., ...) doesn't complain", "");
+}
+
+try(fields)
+char **fields;
+{
+ regexp *r;
+ char dbuf[BUFSIZ];
+
+ errseen = NULL;
+ r = regcomp(fields[0]);
+ if (r == NULL) {
+ if (*fields[2] != 'c')
+ complain("regcomp failure in `%s'", fields[0]);
+ return;
+ }
+ if (*fields[2] == 'c') {
+ complain("unexpected regcomp success in `%s'", fields[0]);
+ free((char *)r);
+ return;
+ }
+ if (!regexec(r, fields[1])) {
+ if (*fields[2] != 'n')
+ complain("regexec failure in `%s'", "");
+ free((char *)r);
+ return;
+ }
+ if (*fields[2] == 'n') {
+ complain("unexpected regexec success", "");
+ free((char *)r);
+ return;
+ }
+ errseen = NULL;
+ regsub(r, fields[3], dbuf);
+ if (errseen != NULL) {
+ complain("regsub complaint", "");
+ free((char *)r);
+ return;
+ }
+ if (strcmp(dbuf, fields[4]) != 0)
+ complain("regsub result `%s' wrong", dbuf);
+ free((char *)r);
+}
+
+complain(s1, s2)
+char *s1;
+char *s2;
+{
+ fprintf(stderr, "try: %d: ", lineno);
+ fprintf(stderr, s1, s2);
+ fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : "");
+ status = 1;
+}
diff --git a/libc/stdio2/Config b/libc/stdio2/Config
new file mode 100644
index 0000000..665045f
--- /dev/null
+++ b/libc/stdio2/Config
@@ -0,0 +1,4 @@
+#
+
+stdio: Robert's stdio package
+
diff --git a/libc/stdio2/Makefile b/libc/stdio2/Makefile
new file mode 100644
index 0000000..80f2e3b
--- /dev/null
+++ b/libc/stdio2/Makefile
@@ -0,0 +1,52 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+ifneq ($(LIB_CPU),i86)
+CFLAGS=$(CCFLAGS) $(LIBDEFS) -DFLOATS
+endif
+
+ASRC=stdio.c
+AOBJ=_stdio_init.o fputc.o fgetc.o fflush.o fgets.o gets.o fputs.o \
+ puts.o fread.o fwrite.o fopen.o fclose.o fseek.o rewind.o ftell.o \
+ setbuffer.o setvbuf.o ungetc.o
+
+PSRC=printf.c
+POBJ=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o
+
+SSRC=scanf.c
+SOBJ=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o
+
+OBJ= $(AOBJ) $(POBJ) $(SOBJ)
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(AOBJ)): $(ASRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(POBJ)): $(PSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(SOBJ)): $(SSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+transfer:
+ -@rm -f ../include/stdio.h
+ cp -p stdio.h ../include/.
+
+clean:
+ rm -f *.o libc.a
+
+$(LIBC)($(OBJ)): stdio.h
+
diff --git a/libc/stdio2/printf.c b/libc/stdio2/printf.c
new file mode 100644
index 0000000..45c4aa7
--- /dev/null
+++ b/libc/stdio2/printf.c
@@ -0,0 +1,376 @@
+/*
+ * This file based on printf.c from 'Dlibs' on the atari ST (RdeBath)
+ *
+ *
+ * Dale Schumacher 399 Beacon Ave.
+ * (alias: Dalnefre') St. Paul, MN 55104
+ * dal@syntel.UUCP United States of America
+ * "It's not reality that's important, but how you perceive things."
+ */
+
+/* Altered to use stdarg, made the core function vfprintf.
+ * Hooked into the stdio package using 'inside information'
+ * Altered sizeof() assumptions, now assumes all integers except chars
+ * will be either
+ * sizeof(xxx) == sizeof(long) or sizeof(xxx) == sizeof(short)
+ *
+ * -RDB
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#define va_strt va_start
+#else
+#include <varargs.h>
+#define va_strt(p,i) va_start(p)
+#endif
+
+#include "stdio.h"
+
+#ifdef L_printf
+
+#ifdef __STDC__
+int printf(const char * fmt, ...)
+#else
+int printf(fmt, va_alist)
+__const char *fmt;
+va_dcl
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ rv = vfprintf(stdout,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_sprintf
+#ifdef __STDC__
+int sprintf(char * sp, const char * fmt, ...)
+#else
+int sprintf(sp, fmt, va_alist)
+char * sp;
+__const char *fmt;
+va_dcl
+#endif
+{
+static FILE string[1] =
+{
+ {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_WRITE}
+};
+
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ string->bufpos = sp;
+ rv = vfprintf(string,fmt,ptr);
+ va_end(ptr);
+ *(string->bufpos) = 0;
+ return rv;
+}
+#endif
+
+#ifdef L_fprintf
+#ifdef __STDC__
+int fprintf(FILE * fp, const char * fmt, ...)
+#else
+int fprintf(fp, fmt, va_alist)
+FILE * fp;
+__const char *fmt;
+va_dcl
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ rv = vfprintf(fp,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_vprintf
+int vprintf(fmt, ap)
+__const char *fmt;
+va_list ap;
+{
+ return vfprintf(stdout,fmt,ap);
+}
+#endif
+
+#ifdef L_vsprintf
+int vsprintf(sp, fmt, ap)
+char * sp;
+__const char *fmt;
+va_list ap;
+{
+static FILE string[1] =
+{
+ {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_WRITE}
+};
+
+ int rv;
+ string->bufpos = sp;
+ rv = vfprintf(string,fmt,ap);
+ *(string->bufpos) = 0;
+ return rv;
+}
+#endif
+
+#ifdef L_vfprintf
+
+#ifdef FLOATS
+int (*__fp_print)() = 0;
+#endif
+
+static int
+prtfld(op, buf, ljustf, sign, pad, width, preci, buffer_mode)
+register FILE *op;
+register unsigned char *buf;
+int ljustf;
+register char sign;
+char pad;
+register int width;
+int preci;
+int buffer_mode;
+/*
+ * Output the given field in the manner specified by the arguments. Return
+ * the number of characters output.
+ */
+{
+ register int cnt = 0, len;
+ register unsigned char ch;
+
+ len = strlen(buf);
+
+ if (*buf == '-')
+ sign = *buf++;
+ else if (sign)
+ len++;
+
+ if ((preci != -1) && (len > preci)) /* limit max data width */
+ len = preci;
+
+ if (width < len) /* flexible field width or width overflow */
+ width = len;
+
+ /*
+ * at this point: width = total field width len = actual data width
+ * (including possible sign character)
+ */
+ cnt = width;
+ width -= len;
+
+ while (width || len)
+ {
+ if (!ljustf && width) /* left padding */
+ {
+ if (len && sign && (pad == '0'))
+ goto showsign;
+ ch = pad;
+ --width;
+ }
+ else if (len)
+ {
+ if (sign)
+ {
+ showsign:ch = sign; /* sign */
+ sign = '\0';
+ }
+ else
+ ch = *buf++; /* main field */
+ --len;
+ }
+ else
+ {
+ ch = pad; /* right padding */
+ --width;
+ }
+ putc(ch, op);
+ if( ch == '\n' && buffer_mode == _IOLBF ) fflush(op);
+ }
+
+ return (cnt);
+}
+
+int
+vfprintf(op, fmt, ap)
+FILE *op;
+register __const char *fmt;
+register va_list ap;
+{
+ register int i, cnt = 0, ljustf, lval;
+ int preci, dpoint, width;
+ char pad, sign, radix, hash;
+ register char *ptmp;
+ char tmp[64], *ltostr(), *ultostr();
+ int buffer_mode;
+
+ /* This speeds things up a bit for unbuffered */
+ buffer_mode = (op->mode&__MODE_BUF);
+ op->mode &= (~__MODE_BUF);
+
+ while (*fmt)
+ {
+ if (*fmt == '%')
+ {
+ if( buffer_mode == _IONBF ) fflush(op);
+ ljustf = 0; /* left justify flag */
+ sign = '\0'; /* sign char & status */
+ pad = ' '; /* justification padding char */
+ width = -1; /* min field width */
+ dpoint = 0; /* found decimal point */
+ preci = -1; /* max data width */
+ radix = 10; /* number base */
+ ptmp = tmp; /* pointer to area to print */
+ hash = 0;
+ lval = (sizeof(int)==sizeof(long)); /* long value flaged */
+ fmtnxt:
+ i = 0;
+ for(;;)
+ {
+ ++fmt;
+ if(*fmt < '0' || *fmt > '9' ) break;
+ i = (i * 10) + (*fmt - '0');
+ if (dpoint)
+ preci = i;
+ else if (!i && (pad == ' '))
+ {
+ pad = '0';
+ goto fmtnxt;
+ }
+ else
+ width = i;
+ }
+
+ switch (*fmt)
+ {
+ case '\0': /* early EOS */
+ --fmt;
+ goto charout;
+
+ case '-': /* left justification */
+ ljustf = 1;
+ goto fmtnxt;
+
+ case ' ':
+ case '+': /* leading sign flag */
+ sign = *fmt;
+ goto fmtnxt;
+
+ case '*': /* parameter width value */
+ i = va_arg(ap, int);
+ if (dpoint)
+ preci = i;
+ else
+ width = i;
+ goto fmtnxt;
+
+ case '.': /* secondary width field */
+ dpoint = 1;
+ goto fmtnxt;
+
+ case 'l': /* long data */
+ lval = 1;
+ goto fmtnxt;
+
+ case 'h': /* short data */
+ lval = 0;
+ goto fmtnxt;
+
+ case 'd': /* Signed decimal */
+ case 'i':
+ ptmp = ltostr((long) ((lval)
+ ? va_arg(ap, long)
+ : va_arg(ap, short)),
+ 10);
+ goto printit;
+
+ case 'b': /* Unsigned binary */
+ radix = 2;
+ goto usproc;
+
+ case 'o': /* Unsigned octal */
+ radix = 8;
+ goto usproc;
+
+ case 'p': /* Pointer */
+ lval = (sizeof(char*) == sizeof(long));
+ pad = '0';
+ width = 6;
+ preci = 8;
+ /* fall thru */
+
+ case 'x': /* Unsigned hexadecimal */
+ case 'X':
+ radix = 16;
+ /* fall thru */
+
+ case 'u': /* Unsigned decimal */
+ usproc:
+ ptmp = ultostr((unsigned long) ((lval)
+ ? va_arg(ap, unsigned long)
+ : va_arg(ap, unsigned short)),
+ radix);
+ if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; }
+ goto printit;
+
+ case '#':
+ hash=1;
+ goto fmtnxt;
+
+ case 'c': /* Character */
+ ptmp[0] = va_arg(ap, int);
+ ptmp[1] = '\0';
+ goto nopad;
+
+ case 's': /* String */
+ ptmp = va_arg(ap, char*);
+ nopad:
+ sign = '\0';
+ pad = ' ';
+ printit:
+ cnt += prtfld(op, ptmp, ljustf,
+ sign, pad, width, preci, buffer_mode);
+ break;
+
+#if FLOATS
+ case 'e': /* float */
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ if ( __fp_print )
+ {
+ (*__fp_print)(&va_arg(ap, double), *fmt, preci, ptmp);
+ preci = -1;
+ goto printit;
+ }
+ /* FALLTHROUGH if no floating printf available */
+#endif
+
+ default: /* unknown character */
+ goto charout;
+ }
+ }
+ else
+ {
+ charout:
+ putc(*fmt, op); /* normal char out */
+ ++cnt;
+ if( *fmt == '\n' && buffer_mode == _IOLBF ) fflush(op);
+ }
+ ++fmt;
+ }
+ op->mode |= buffer_mode;
+ if( buffer_mode == _IONBF ) fflush(op);
+ if( buffer_mode == _IOLBF ) op->bufwrite = op->bufstart;
+ return (cnt);
+}
+#endif
diff --git a/libc/stdio2/scanf.c b/libc/stdio2/scanf.c
new file mode 100644
index 0000000..2d61ab2
--- /dev/null
+++ b/libc/stdio2/scanf.c
@@ -0,0 +1,521 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#define va_strt va_start
+#else
+#include <varargs.h>
+#define va_strt(p,i) va_start(p)
+#endif
+
+#ifdef L_scanf
+#ifdef __STDC__
+int scanf(const char * fmt, ...)
+#else
+int scanf(fmt, va_alist)
+__const char *fmt;
+va_dcl
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ rv = vfscanf(stdin,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_sscanf
+#ifdef __STDC__
+int sscanf(char * sp, const char * fmt, ...)
+#else
+int sscanf(sp, fmt, va_alist)
+char * sp;
+__const char *fmt;
+va_dcl
+#endif
+{
+static FILE string[1] =
+{
+ {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_READ}
+};
+
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ string->bufpos = sp;
+ rv = vfscanf(string,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_fscanf
+#ifdef __STDC__
+int fscanf(FILE * fp, const char * fmt, ...)
+#else
+int fscanf(fp, fmt, va_alist)
+FILE * fp;
+__const char *fmt;
+va_dcl
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_strt(ptr, fmt);
+ rv = vfscanf(fp,fmt,ptr);
+ va_end(ptr);
+ return rv;
+}
+#endif
+
+#ifdef L_vscanf
+int vscanf(fmt, ap)
+__const char *fmt;
+va_list ap;
+{
+ return vfscanf(stdin,fmt,ap);
+}
+#endif
+
+#ifdef L_vsscanf
+int vsscanf(sp, fmt, ap)
+char * sp;
+__const char *fmt;
+{
+static FILE string[1] =
+{
+ {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_READ}
+};
+
+ string->bufpos = sp;
+ return vfscanf(string,fmt,ap);
+}
+#endif
+
+#ifdef L_vfscanf
+/* #define skip() do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/
+
+#define skip() while(isspace(c)) { if ((c=getc(fp))<1) goto done; }
+
+#if FLOATS
+/* fp scan actions */
+#define F_NADA 0 /* just change state */
+#define F_SIGN 1 /* set sign */
+#define F_ESIGN 2 /* set exponent's sign */
+#define F_INT 3 /* adjust integer part */
+#define F_FRAC 4 /* adjust fraction part */
+#define F_EXP 5 /* adjust exponent part */
+#define F_QUIT 6
+
+#define NSTATE 8
+#define FS_INIT 0 /* initial state */
+#define FS_SIGNED 1 /* saw sign */
+#define FS_DIGS 2 /* saw digits, no . */
+#define FS_DOT 3 /* saw ., no digits */
+#define FS_DD 4 /* saw digits and . */
+#define FS_E 5 /* saw 'e' */
+#define FS_ESIGN 6 /* saw exp's sign */
+#define FS_EDIGS 7 /* saw exp's digits */
+
+#define FC_DIG 0
+#define FC_DOT 1
+#define FC_E 2
+#define FC_SIGN 3
+
+/* given transition,state do what action? */
+int fp_do[][NSTATE] = {
+ {F_INT,F_INT,F_INT,
+ F_FRAC,F_FRAC,
+ F_EXP,F_EXP,F_EXP}, /* see digit */
+ {F_NADA,F_NADA,F_NADA,
+ F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT}, /* see '.' */
+ {F_QUIT,F_QUIT,
+ F_NADA,F_QUIT,F_NADA,
+ F_QUIT,F_QUIT,F_QUIT}, /* see e/E */
+ {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
+ F_ESIGN,F_QUIT,F_QUIT}, /* see sign */
+};
+/* given transition,state what is new state? */
+int fp_ns[][NSTATE] = {
+ {FS_DIGS,FS_DIGS,FS_DIGS,
+ FS_DD,FS_DD,
+ FS_EDIGS,FS_EDIGS,FS_EDIGS}, /* see digit */
+ {FS_DOT,FS_DOT,FS_DD,
+ }, /* see '.' */
+ {0,0,
+ FS_E,0,FS_E,
+ }, /* see e/E */
+ {FS_SIGNED,0,0,0,0,
+ FS_ESIGN,0,0}, /* see sign */
+};
+/* which states are valid terminators? */
+int fp_sval[NSTATE] = {
+ 0,0,1,0,1,0,0,1
+};
+#endif
+
+vfscanf(fp, fmt, ap)
+register FILE *fp;
+register char *fmt;
+va_list ap;
+
+{
+ register long n;
+ register int c, width, lval, cnt = 0;
+ int store, neg, base, wide1, endnull, rngflag, c2;
+ register unsigned char *p;
+ unsigned char delim[128], digits[17], *q;
+#if FLOATS
+ long frac, expo;
+ int eneg, fraclen, fstate, trans;
+ double fx, fp_scan();
+#endif
+
+ if (!*fmt)
+ return (0);
+
+ c = getc(fp);
+ while (c > 0)
+ {
+ store = 0;
+ if (*fmt == '%')
+ {
+ n = 0;
+ width = -1;
+ wide1 = 1;
+ base = 10;
+ lval = (sizeof(long) == sizeof(int));
+ store = 1;
+ endnull = 1;
+ neg = -1;
+
+ strcpy(delim, "\011\012\013\014\015 ");
+ strcpy(digits, "0123456789ABCDEF");
+
+ if (fmt[1] == '*')
+ {
+ endnull = store = 0;
+ ++fmt;
+ }
+
+ while (isdigit(*++fmt))/* width digit(s) */
+ {
+ if (width == -1)
+ width = 0;
+ wide1 = width = (width * 10) + (*fmt - '0');
+ }
+ --fmt;
+ fmtnxt:
+ ++fmt;
+ switch (tolower(*fmt)) /* tolower() is a MACRO! */
+ {
+ case '*':
+ endnull = store = 0;
+ goto fmtnxt;
+
+ case 'l': /* long data */
+ lval = 1;
+ goto fmtnxt;
+ case 'h': /* short data */
+ lval = 0;
+ goto fmtnxt;
+
+ case 'i': /* any-base numeric */
+ base = 0;
+ goto numfmt;
+
+ case 'b': /* unsigned binary */
+ base = 2;
+ goto numfmt;
+
+ case 'o': /* unsigned octal */
+ base = 8;
+ goto numfmt;
+
+ case 'x': /* unsigned hexadecimal */
+ base = 16;
+ goto numfmt;
+
+ case 'd': /* SIGNED decimal */
+ neg = 0;
+ /* FALL-THRU */
+
+ case 'u': /* unsigned decimal */
+ numfmt:skip();
+
+ if (isupper(*fmt))
+ lval = 1;
+
+ if (!base)
+ {
+ base = 10;
+ neg = 0;
+ if (c == '%')
+ {
+ base = 2;
+ goto skip1;
+ }
+ else if (c == '0')
+ {
+ c = getc(fp);
+ if (c < 1)
+ goto savnum;
+ if ((c != 'x')
+ && (c != 'X'))
+ {
+ base = 8;
+ digits[8] = '\0';
+ goto zeroin;
+ }
+ base = 16;
+ goto skip1;
+ }
+ }
+
+ if ((neg == 0) && (base == 10)
+ && ((neg = (c == '-')) || (c == '+')))
+ {
+ skip1:
+ c = getc(fp);
+ if (c < 1)
+ goto done;
+ }
+
+ digits[base] = '\0';
+ p = ((unsigned char *)
+ strchr(digits, toupper(c)));
+
+ if ((!c || !p) && width)
+ goto done;
+
+ while (p && width-- && c)
+ {
+ n = (n * base) + (p - digits);
+ c = getc(fp);
+ zeroin:
+ p = ((unsigned char *)
+ strchr(digits, toupper(c)));
+ }
+ savnum:
+ if (store)
+ {
+ if (neg == 1)
+ n = -n;
+ if (lval)
+ *va_arg(ap, long*) = n;
+ else
+ *va_arg(ap, short*) = n;
+ ++cnt;
+ }
+ break;
+
+#if FLOATS
+ case 'e': /* float */
+ case 'f':
+ case 'g':
+ skip();
+
+ if (isupper(*fmt))
+ lval = 1;
+
+ fstate = FS_INIT;
+ neg = 0;
+ eneg = 0;
+ n = 0;
+ frac = 0;
+ expo = 0;
+ fraclen = 0;
+
+ while (c && width--)
+ {
+ if (c >= '0' && c <= '9')
+ trans = FC_DIG;
+ else if (c == '.')
+ trans = FC_DOT;
+ else if (c == '+' || c == '-')
+ trans = FC_SIGN;
+ else if (tolower(c) == 'e')
+ trans = FC_E;
+ else
+ goto fdone;
+
+ switch (fp_do[trans][fstate])
+ {
+ case F_SIGN:
+ neg = (c == '-');
+ break;
+ case F_ESIGN:
+ eneg = (c == '-');
+ break;
+ case F_INT:
+ n = 10 * n + (c - '0');
+ break;
+ case F_FRAC:
+ frac = 10 * frac + (c - '0');
+ fraclen++;
+ break;
+ case F_EXP:
+ expo = 10 * expo + (c - '0');
+ break;
+ case F_QUIT:
+ goto fdone;
+ }
+ fstate = fp_ns[trans][fstate];
+ c = getc(fp);
+ }
+
+ fdone:
+ if (!fp_sval[fstate])
+ goto done;
+ if (store)
+ {
+ fx = fp_scan(neg, eneg, n, frac, expo, fraclen);
+ if (lval)
+ *va_arg(ap, double *) = fx;
+ else
+ *va_arg(ap, float *) = fx;
+ ++cnt;
+ }
+ break;
+#endif
+
+ case 'c': /* character data */
+ width = wide1;
+ lval = endnull = 0;
+ delim[0] = '\0';
+ goto strproc;
+
+ case '[': /* string w/ delimiter set */
+
+ /* get delimiters */
+ p = delim;
+
+ if (*++fmt == '^')
+ {
+ fmt++;
+ lval = 0;
+ }
+ else
+ lval = 1;
+
+ rngflag = 2;
+ if ((*fmt == ']') || (*fmt == '-'))
+ {
+ *p++ = *fmt++;
+ rngflag = 0;
+ }
+
+ while (*fmt != ']')
+ {
+ if (*fmt == '\0')
+ goto done;
+ switch (rngflag)
+ {
+ case 1:
+ c2 = *(p - 2);
+ if (c2 <= *fmt)
+ {
+ p -= 2;
+ while (c2 < *fmt)
+ *p++ = c2++;
+ rngflag = 2;
+ break;
+ }
+ /* fall thru intentional */
+
+ case 0:
+ rngflag = (*fmt == '-');
+ break;
+
+ case 2:
+ rngflag = 0;
+ }
+
+ *p++ = *fmt++;
+ }
+
+ *p = '\0';
+ goto strproc;
+
+ case 's': /* string data */
+ lval = 0;
+ skip();
+ strproc:
+ /* process string */
+ p = va_arg(ap, unsigned char *);
+
+ /* if the 1st char fails, match fails */
+ if (width)
+ {
+ q = ((unsigned char *)
+ strchr(delim, c));
+ if ((c < 1) || lval == (q==0))
+ {
+ if (endnull)
+ *p = '\0';
+ goto done;
+ }
+ }
+
+ for (;;) /* FOREVER */
+ {
+ if (store)
+ *p++ = c;
+ if (((c = getc(fp)) < 1) ||
+ (--width == 0))
+ break;
+
+ q = ((unsigned char *)
+ strchr(delim, c));
+ if (lval == (q==0))
+ break;
+ }
+
+ if (store)
+ {
+ if (endnull)
+ *p = '\0';
+ ++cnt;
+ }
+ break;
+
+ case '\0': /* early EOS */
+ --fmt;
+ /* FALL THRU */
+
+ default:
+ goto cmatch;
+ }
+ }
+ else if (isspace(*fmt)) /* skip whitespace */
+ {
+ skip();
+ }
+ else
+ { /* normal match char */
+ cmatch:
+ if (c != *fmt)
+ break;
+ c = getc(fp);
+ }
+
+ if (!*++fmt)
+ break;
+ }
+
+ done: /* end of scan */
+ if ((c == EOF) && (cnt == 0))
+ return (EOF);
+
+ if( c != EOF )
+ ungetc(c, fp);
+ return (cnt);
+}
+
+#endif
diff --git a/libc/stdio2/stdio.c b/libc/stdio2/stdio.c
new file mode 100644
index 0000000..156d3e3
--- /dev/null
+++ b/libc/stdio2/stdio.c
@@ -0,0 +1,814 @@
+/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+/* This is an implementation of the C standard IO package.
+ */
+
+#include <stdio.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <malloc.h>
+#include <errno.h>
+
+extern FILE *__IO_list; /* For fflush at exit */
+
+#ifdef __AS386_16__
+#define Inline_init
+#endif
+
+#ifdef __AS386_32__
+#define Inline_init
+#endif
+
+#ifndef Inline_init
+#define Inline_init __io_init_vars()
+#endif
+
+#ifdef L__stdio_init
+
+#define buferr (stderr->unbuf) /* Stderr is unbuffered */
+
+FILE *__IO_list = 0; /* For fflush at exit */
+
+static char bufin[BUFSIZ];
+static char bufout[BUFSIZ];
+#ifndef buferr
+static char buferr[BUFSIZ];
+#endif
+
+FILE stdin[1] =
+{
+ {bufin, bufin, bufin, bufin, bufin + sizeof(bufin),
+ 0, _IOFBF | __MODE_READ | __MODE_IOTRAN}
+};
+
+FILE stdout[1] =
+{
+ {bufout, bufout, bufout, bufout, bufout + sizeof(bufout),
+ 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN}
+};
+
+FILE stderr[1] =
+{
+ {buferr, buferr, buferr, buferr, buferr + sizeof(buferr),
+ 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN}
+};
+
+/* Call the stdio initiliser; it's main job it to call atexit */
+
+#ifdef __AS386_16__
+#define STATIC static
+
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .word ___io_init_vars ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+#ifdef __AS386_32__
+#define STATIC static
+
+#asm
+ loc 1 ! Make sure the pointer is in the correct segment
+auto_func: ! Label for bcc -M to work.
+ .long ___io_init_vars ! Pointer to the autorun function
+ .text ! So the function after is also in the correct seg.
+#endasm
+#endif
+
+#ifndef STATIC
+#define STATIC
+#endif
+
+STATIC int
+__stdio_close_all()
+{
+ FILE *fp;
+ fflush(stdout);
+ fflush(stderr);
+ for (fp = __IO_list; fp; fp = fp->next)
+ {
+ fflush(fp);
+ close(fp->fd);
+ /* Note we're not de-allocating the memory */
+ /* There doesn't seem to be much point :-) */
+ fp->fd = -1;
+ }
+}
+
+STATIC void
+__io_init_vars()
+{
+#ifndef __AS386_16__
+#ifndef __AS386_32__
+ static int first_time = 1;
+ if( !first_time ) return ; first_time = 1;
+#endif
+#endif
+ if (isatty(1))
+ stdout->mode |= _IOLBF;
+ atexit(__stdio_close_all);
+}
+#endif
+
+#ifdef L_fputc
+int
+fputc(ch, fp)
+int ch;
+FILE *fp;
+{
+ register int v;
+ Inline_init;
+
+ v = fp->mode;
+ /* If last op was a read ... */
+ if ((v & __MODE_READING) && fflush(fp))
+ return EOF;
+
+ /* Can't write or there's been an EOF or error then return EOF */
+ if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)
+ return EOF;
+
+ /* In MSDOS translation mode */
+#if __MODE_IOTRAN
+ if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF)
+ return EOF;
+#endif
+
+ /* Buffer is full */
+ if (fp->bufpos >= fp->bufend && fflush(fp))
+ return EOF;
+
+ /* Right! Do it! */
+ *(fp->bufpos++) = ch;
+ fp->mode |= __MODE_WRITING;
+
+ /* Unbuffered or Line buffered and end of line */
+ if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF))
+ && fflush(fp))
+ return EOF;
+
+ /* Can the macro handle this by itself ? */
+ if (v & (__MODE_IOTRAN | _IOLBF | _IONBF))
+ fp->bufwrite = fp->bufstart; /* Nope */
+ else
+ fp->bufwrite = fp->bufend; /* Yup */
+
+ /* Correct return val */
+ return (unsigned char) ch;
+}
+#endif
+
+#ifdef L_fgetc
+int
+fgetc(fp)
+FILE *fp;
+{
+ int ch;
+
+ if (fp->mode & __MODE_WRITING)
+ fflush(fp);
+
+ try_again:
+ /* Can't read or there's been an EOF or error then return EOF */
+ if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ)
+ return EOF;
+
+ /* Nothing in the buffer - fill it up */
+ if (fp->bufpos >= fp->bufread)
+ {
+ fp->bufpos = fp->bufread = fp->bufstart;
+ ch = fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp);
+ if (ch == 0)
+ return EOF;
+ fp->bufread += ch;
+ fp->mode |= __MODE_READING;
+ fp->mode &= ~__MODE_UNGOT;
+ }
+ ch = *(fp->bufpos++);
+
+#if __MODE_IOTRAN
+ /* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */
+ if (ch == '\r' && (fp->mode & __MODE_IOTRAN))
+ goto try_again;
+#endif
+
+ return ch;
+}
+#endif
+
+#ifdef L_fflush
+int
+fflush(fp)
+FILE *fp;
+{
+ int len, cc;
+ if (fp == NULL) /* On NULL flush the lot. */
+ {
+ if (fflush(stdin))
+ return EOF;
+ if (fflush(stdout))
+ return EOF;
+ if (fflush(stderr))
+ return EOF;
+
+ for (fp = __IO_list; fp; fp = fp->next)
+ if (fflush(fp))
+ return EOF;
+
+ return 0;
+ }
+
+ /* If there's output data pending */
+ if (fp->mode & __MODE_WRITING)
+ {
+ len = fp->bufpos - fp->bufstart;
+
+ if (len)
+ {
+ /*
+ * The loop is so we don't get upset by signals
+ */
+ do
+ {
+ cc = write(fp->fd, fp->bufstart, len);
+ }
+ while (cc == -1 && errno == EINTR);
+ /*
+ * I think the following test is _too_ stringent, but it's not
+ * serious If it is found to be a problem then if cc>0 we can do
+ * a memcpy to put the buffer in a state for a retry. Or even do
+ * the retry ourselves.
+ */
+ if (cc != len)
+ {
+ fp->mode |= __MODE_ERR;
+ return EOF;
+ }
+ }
+ }
+ /* If there's data in the buffer sychronise the file positions */
+ else if (fp->mode & __MODE_READING)
+ {
+ /* Humm, I think this means sync the file like fpurge() ... */
+ /* Anyway the user isn't supposed to call this function when reading */
+
+ len = fp->bufread - fp->bufpos; /* Bytes buffered but unread */
+ /* If it's a file, make it good */
+ if (len > 0 && lseek(fp->fd, -len, 1) < 0)
+ {
+ /* Hummm - Not certain here, I don't think this is reported */
+ /*
+ * fp->mode |= __MODE_ERR; return EOF;
+ */
+ }
+ }
+
+ /* All done, no problem */
+ fp->mode &= (~(__MODE_READING|__MODE_WRITING|__MODE_EOF|__MODE_UNGOT));
+ fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart;
+ return 0;
+}
+#endif
+
+#ifdef L_fgets
+/* Nothing special here ... */
+char *
+fgets(s, count, f)
+char *s;
+size_t count;
+FILE *f;
+{
+ char *ret;
+ register size_t i;
+ register int ch;
+
+ ret = s;
+ for (i = count; i > 0; i--)
+ {
+ ch = getc(f);
+ if (ch == EOF)
+ {
+ if (s == ret)
+ return 0;
+ break;
+ }
+ *s++ = (char) ch;
+ if (ch == '\n')
+ break;
+ }
+ *s = 0;
+
+ if (ferror(f))
+ return 0;
+ return ret;
+}
+#endif
+
+#ifdef L_gets
+char *
+gets(str) /* BAD function; DON'T use it! */
+char *str;
+{
+ /* Auwlright it will work but of course _your_ program will crash */
+ /* if it's given a too long line */
+ register char *p = str;
+ register int c;
+
+ while (((c = getc(stdin)) != EOF) && (c != '\n'))
+ *p++ = c;
+ *p = '\0';
+ return (((c == EOF) && (p == str)) ? NULL : str); /* NULL == EOF */
+}
+#endif
+
+#ifdef L_fputs
+int
+fputs(str, fp)
+char *str;
+FILE *fp;
+{
+ register int n = 0;
+ while (*str)
+ {
+ if (putc(*str++, fp) == EOF)
+ return (EOF);
+ ++n;
+ }
+ return (n);
+}
+#endif
+
+#ifdef L_puts
+int
+puts(str)
+char *str;
+{
+ register int n;
+
+ if (((n = fputs(str, stdout)) == EOF)
+ || (putc('\n', stdout) == EOF))
+ return (EOF);
+ return (++n);
+}
+#endif
+
+#ifdef L_fread
+/*
+ * fread will often be used to read in large chunks of data calling read()
+ * directly can be a big win in this case. Beware also fgetc calls this
+ * function to fill the buffer.
+ *
+ * This ignores __MODE__IOTRAN; probably exactly what you want. (It _is_ what
+ * fgetc wants)
+ */
+int
+fread(buf, size, nelm, fp)
+char *buf;
+int size;
+int nelm;
+FILE *fp;
+{
+ int len, v;
+ unsigned bytes, got = 0;
+ Inline_init;
+
+ v = fp->mode;
+
+ /* Want to do this to bring the file pointer up to date */
+ if (v & __MODE_WRITING)
+ fflush(fp);
+
+ /* Can't read or there's been an EOF or error then return zero */
+ if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ)
+ return 0;
+
+ /* This could be long, doesn't seem much point tho */
+ bytes = size * nelm;
+
+ len = fp->bufread - fp->bufpos;
+ if (len >= bytes) /* Enough buffered */
+ {
+ memcpy(buf, fp->bufpos, (unsigned) bytes);
+ fp->bufpos += bytes;
+ return bytes;
+ }
+ else if (len > 0) /* Some buffered */
+ {
+ memcpy(buf, fp->bufpos, len);
+ got = len;
+ }
+
+ /* Need more; do it with a direct read */
+ len = read(fp->fd, buf + got, (unsigned) (bytes - got));
+
+ /* Possibly for now _or_ later */
+ if (len < 0)
+ {
+ fp->mode |= __MODE_ERR;
+ len = 0;
+ }
+ else if (len == 0)
+ fp->mode |= __MODE_EOF;
+
+ return (got + len) / size;
+}
+#endif
+
+#ifdef L_fwrite
+/*
+ * Like fread, fwrite will often be used to write out large chunks of
+ * data; calling write() directly can be a big win in this case.
+ *
+ * But first we check to see if there's space in the buffer.
+ *
+ * Again this ignores __MODE__IOTRAN.
+ */
+int
+fwrite(buf, size, nelm, fp)
+char *buf;
+int size;
+int nelm;
+FILE *fp;
+{
+ register int v;
+ int len;
+ unsigned bytes, put;
+
+ v = fp->mode;
+ /* If last op was a read ... */
+ if ((v & __MODE_READING) && fflush(fp))
+ return 0;
+
+ /* Can't write or there's been an EOF or error then return 0 */
+ if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE)
+ return 0;
+
+ /* This could be long, doesn't seem much point tho */
+ bytes = size * nelm;
+
+ len = fp->bufend - fp->bufpos;
+
+ /* Flush the buffer if not enough room */
+ if (bytes > len)
+ if (fflush(fp))
+ return 0;
+
+ len = fp->bufend - fp->bufpos;
+ if (bytes <= len) /* It'll fit in the buffer ? */
+ {
+ fp->mode |= __MODE_WRITING;
+ memcpy(fp->bufpos, buf, bytes);
+ fp->bufpos += bytes;
+
+ /* If we're not fully buffered */
+ if (v & (_IOLBF | _IONBF))
+ fflush(fp);
+
+ return nelm;
+ }
+ else
+ /* Too big for the buffer */
+ {
+ put = write(fp->fd, buf, bytes);
+ if (put < 0)
+ {
+ fp->mode |= __MODE_ERR;
+ put = 0;
+ }
+ }
+
+ return put / size;
+}
+#endif
+
+#ifdef L_rewind
+void
+rewind(fp)
+FILE * fp;
+{
+ fseek(fp, (long)0, 0);
+ clearerr(fp);
+}
+#endif
+
+#ifdef L_fseek
+int
+fseek(fp, offset, ref)
+FILE *fp;
+long offset;
+int ref;
+{
+ /* Use fflush to sync the pointers */
+
+#if 1
+ /* if __MODE_READING and no ungetc ever done can just move pointer */
+ /* This needs testing! */
+
+ if ( (fp->mode &(__MODE_READING | __MODE_UNGOT)) == __MODE_READING &&
+ ( ref == SEEK_SET || ref == SEEK_CUR ))
+ {
+ long fpos = lseek(fp->fd, 0L, SEEK_CUR);
+ if( fpos == -1 ) return EOF;
+
+ if( ref == SEEK_CUR )
+ {
+ ref = SEEK_SET;
+ offset = fpos + offset + fp->bufpos - fp->bufread;
+ }
+ if( ref == SEEK_SET )
+ {
+ if ( offset < fpos && offset >= fpos + fp->bufstart - fp->bufread )
+ {
+ fp->bufpos = offset - fpos + fp->bufread;
+ return 0;
+ }
+ }
+ }
+#endif
+
+ if (fflush(fp) == EOF)
+ return EOF;
+ if (lseek(fp->fd, offset, ref) < 0)
+ return EOF;
+ return 0;
+}
+#endif
+
+#ifdef L_ftell
+long ftell(fp)
+FILE * fp;
+{
+ long rv;
+ if (fflush(fp) == EOF)
+ return EOF;
+ return lseek(fp->fd, 0L, SEEK_CUR);
+}
+#endif
+
+#ifdef L_fopen
+/*
+ * This Fopen is all three of fopen, fdopen and freopen. The macros in
+ * stdio.h show the other names.
+ */
+FILE *
+__fopen(fname, fd, fp, mode)
+char *fname;
+int fd;
+FILE *fp;
+char *mode;
+{
+ int open_mode = 0;
+#if __MODE_IOTRAN
+ int do_iosense = 1;
+#endif
+ int fopen_mode = 0;
+ FILE *nfp = 0;
+
+ /* If we've got an fp close the old one (freopen) */
+ if (fp)
+ {
+ /* Careful, don't de-allocate it */
+ fopen_mode |= (fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF));
+ fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF);
+ fclose(fp);
+ }
+
+ /* decode the new open mode */
+ while (*mode)
+ switch (*mode++)
+ {
+ case 'r':
+ fopen_mode |= __MODE_READ;
+ break;
+ case 'w':
+ fopen_mode |= __MODE_WRITE;
+ open_mode = (O_CREAT | O_TRUNC);
+ break;
+ case 'a':
+ fopen_mode |= __MODE_WRITE;
+ open_mode = (O_CREAT | O_APPEND);
+ break;
+ case '+':
+ fopen_mode |= __MODE_RDWR;
+ break;
+#if __MODE_IOTRAN
+ case 'b': /* Binary */
+ fopen_mode &= ~__MODE_IOTRAN;
+ do_iosense=0;
+ break;
+ case 't': /* Text */
+ fopen_mode |= __MODE_IOTRAN;
+ do_iosense=0;
+ break;
+#endif
+ }
+
+ /* Add in the read/write options to mode for open() */
+ switch (fopen_mode & (__MODE_READ | __MODE_WRITE))
+ {
+ case 0:
+ return 0;
+ case __MODE_READ:
+ open_mode |= O_RDONLY;
+ break;
+ case __MODE_WRITE:
+ open_mode |= O_WRONLY;
+ break;
+ default:
+ open_mode |= O_RDWR;
+ break;
+ }
+
+ /* Allocate the (FILE) before we do anything irreversable */
+ if (fp == 0)
+ {
+ nfp = malloc(sizeof(FILE));
+ if (nfp == 0)
+ return 0;
+ }
+
+ /* Open the file itself */
+ if (fname)
+ fd = open(fname, open_mode, 0666);
+ if (fd < 0) /* Grrrr */
+ {
+ if (nfp)
+ free(nfp);
+ return 0;
+ }
+
+ /* If this isn't freopen create a (FILE) and buffer for it */
+ if (fp == 0)
+ {
+ fp = nfp;
+ fp->next = __IO_list;
+ __IO_list = fp;
+
+ fp->mode = __MODE_FREEFIL;
+ if( isatty(fd) )
+ {
+ fp->mode |= _IOLBF;
+#if __MODE_IOTRAN
+ if( do_iosense ) fopen_mode |= __MODE_IOTRAN;
+#endif
+ }
+ else
+ fp->mode |= _IOFBF;
+ fp->bufstart = malloc(BUFSIZ);
+ if (fp->bufstart == 0) /* Oops, no mem */
+ { /* Humm, full buffering with a two(!) byte
+ * buffer. */
+ fp->bufstart = fp->unbuf;
+ fp->bufend = fp->unbuf + sizeof(fp->unbuf);
+ }
+ else
+ {
+ fp->bufend = fp->bufstart + BUFSIZ;
+ fp->mode |= __MODE_FREEBUF;
+ }
+ }
+
+ /* Ok, file's ready clear the buffer and save important bits */
+ fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+ fp->mode |= fopen_mode;
+ fp->fd = fd;
+
+ return fp;
+}
+#endif
+
+#ifdef L_fclose
+int
+fclose(fp)
+FILE *fp;
+{
+ int rv = 0;
+
+ if (fp == 0)
+ {
+ errno = EINVAL;
+ return EOF;
+ }
+ if (fflush(fp))
+ return EOF;
+
+ if (close(fp->fd))
+ rv = EOF;
+ fp->fd = -1;
+
+ if (fp->mode & __MODE_FREEBUF)
+ {
+ free(fp->bufstart);
+ fp->mode &= ~__MODE_FREEBUF;
+ fp->bufstart = fp->bufend = 0;
+ }
+
+ if (fp->mode & __MODE_FREEFIL)
+ {
+ FILE *prev = 0, *ptr;
+ fp->mode = 0;
+
+ for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next)
+ ;
+ if (ptr == fp)
+ {
+ if (prev == 0)
+ __IO_list = fp->next;
+ else
+ prev->next = fp->next;
+ }
+ free(fp);
+ }
+ else
+ fp->mode = 0;
+
+ return rv;
+}
+#endif
+
+#ifdef L_setbuffer
+void
+setbuffer(fp, buf, size)
+FILE * fp;
+char * buf;
+int size;
+{
+ fflush(fp);
+ if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart);
+ fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF);
+
+ if( buf == 0 )
+ {
+ fp->bufstart = fp->unbuf;
+ fp->bufend = fp->unbuf + sizeof(fp->unbuf);
+ fp->mode |= _IONBF;
+ }
+ else
+ {
+ fp->bufstart = buf;
+ fp->bufend = buf+size;
+ fp->mode |= _IOFBF;
+ }
+ fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+}
+#endif
+
+#ifdef L_setvbuf
+int setvbuf(fp, buf, mode, size)
+FILE * fp;
+char * buf;
+int mode;
+size_t size;
+{
+ fflush(fp);
+ if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart);
+ fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF);
+ fp->bufstart = fp->unbuf;
+ fp->bufend = fp->unbuf + sizeof(fp->unbuf);
+ fp->mode |= _IONBF;
+
+ if( mode == _IOFBF || mode == _IOLBF )
+ {
+ if( size <= 0 ) size = BUFSIZ;
+ if( buf == 0 ) buf = malloc(size);
+ if( buf == 0 ) return EOF;
+
+ fp->bufstart = buf;
+ fp->bufend = buf+size;
+ fp->mode |= mode;
+ }
+ fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart;
+}
+#endif
+
+#ifdef L_ungetc
+int
+ungetc(c, fp)
+int c;
+FILE *fp;
+{
+ if (fp->mode & __MODE_WRITING)
+ fflush(fp);
+
+ /* Can't read or there's been an error then return EOF */
+ if ((fp->mode & (__MODE_READ | __MODE_ERR)) != __MODE_READ)
+ return EOF;
+
+ /* Can't do fast fseeks */
+ fp->mode |= __MODE_UNGOT;
+
+ if( fp->bufpos > fp->bufstart )
+ return *--fp->bufpos = (unsigned char) c;
+ else if( fp->bufread == fp->bufstart )
+ return *fp->bufread++ = (unsigned char) c;
+ else
+ return EOF;
+}
+#endif
+
diff --git a/libc/stdio2/stdio.h b/libc/stdio2/stdio.h
new file mode 100644
index 0000000..98ca38a
--- /dev/null
+++ b/libc/stdio2/stdio.h
@@ -0,0 +1,129 @@
+
+#ifndef __STDIO_H
+#define __STDIO_H
+
+#include <features.h>
+#include <sys/types.h>
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#define _IOFBF 0x00 /* full buffering */
+#define _IOLBF 0x01 /* line buffering */
+#define _IONBF 0x02 /* no buffering */
+#define __MODE_BUF 0x03 /* Modal buffering dependent on isatty */
+
+#define __MODE_FREEBUF 0x04 /* Buffer allocated with malloc, can free */
+#define __MODE_FREEFIL 0x08 /* FILE allocated with malloc, can free */
+
+#define __MODE_READ 0x10 /* Opened in read only */
+#define __MODE_WRITE 0x20 /* Opened in write only */
+#define __MODE_RDWR 0x30 /* Opened in read/write */
+
+#define __MODE_READING 0x40 /* Buffer has pending read data */
+#define __MODE_WRITING 0x80 /* Buffer has pending write data */
+
+#define __MODE_EOF 0x100 /* EOF status */
+#define __MODE_ERR 0x200 /* Error status */
+#define __MODE_UNGOT 0x400 /* Buffer has been polluted by ungetc */
+
+#ifdef __MSDOS__
+#define __MODE_IOTRAN 0x1000 /* MSDOS nl <-> cr,nl translation */
+#else
+#define __MODE_IOTRAN 0
+#endif
+
+/* when you add or change fields here, be sure to change the initialization
+ * in stdio_init and fopen */
+struct __stdio_file {
+ unsigned char *bufpos; /* the next byte to write to or read from */
+ unsigned char *bufread; /* the end of data returned by last read() */
+ unsigned char *bufwrite; /* highest address writable by macro */
+ unsigned char *bufstart; /* the start of the buffer */
+ unsigned char *bufend; /* the end of the buffer; ie the byte after the last
+ malloc()ed byte */
+
+ int fd; /* the file descriptor associated with the stream */
+ int mode;
+
+ char unbuf[8]; /* The buffer for 'unbuffered' streams */
+
+ struct __stdio_file * next;
+};
+
+#define EOF (-1)
+#ifndef NULL
+#define NULL (0)
+#endif
+
+typedef struct __stdio_file FILE;
+
+#ifdef __AS386_16__
+#define BUFSIZ (256)
+#else
+#define BUFSIZ (2048)
+#endif
+
+extern FILE stdin[1];
+extern FILE stdout[1];
+extern FILE stderr[1];
+
+#ifdef __MSDOS__
+#define putc(c, fp) fputc(c, fp)
+#define getc(fp) fgetc(fp)
+#else
+#define putc(c, stream) \
+ (((stream)->bufpos >= (stream)->bufwrite) ? fputc((c), (stream)) \
+ : (unsigned char) (*(stream)->bufpos++ = (c)) )
+
+#define getc(stream) \
+ (((stream)->bufpos >= (stream)->bufread) ? fgetc(stream): \
+ (*(stream)->bufpos++))
+#endif
+
+#define putchar(c) putc((c), stdout)
+#define getchar() getc(stdin)
+
+#define ferror(fp) (((fp)->mode&__MODE_ERR) != 0)
+#define feof(fp) (((fp)->mode&__MODE_EOF) != 0)
+#define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0)
+#define fileno(fp) ((fp)->fd)
+
+/* declare functions; not like it makes much difference without ANSI */
+/* RDB: The return values _are_ important, especially if we ever use
+ 8086 'large' model
+ */
+
+/* These two call malloc */
+#define setlinebuf(__fp) setvbuf((__fp), (char*)0, _IOLBF, 0)
+extern int setvbuf __P((FILE*, char*, int, size_t));
+
+/* These don't */
+#define setbuf(__fp, __buf) setbuffer((__fp), (__buf), BUFSIZ)
+extern void setbuffer __P((FILE*, char*, int));
+
+extern int fgetc __P((FILE*));
+extern int fputc __P((int, FILE*));
+
+extern int fclose __P((FILE*));
+extern int fflush __P((FILE*));
+extern char *fgets __P((char*, size_t, FILE*));
+extern FILE *__fopen __P((char*, int, FILE*, char*));
+
+#define fopen(__file, __mode) __fopen((__file), -1, (FILE*)0, (__mode))
+#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode))
+#define fdopen(__file, __mode) __fopen((char*)0, (__file), (FILE*)0, (__mode))
+
+extern int fputs __P((char*, FILE*));
+extern int puts __P((char*));
+
+extern int printf __P ((__const char*, ...));
+extern int fprintf __P ((FILE*, __const char*, ...));
+extern int sprintf __P ((char*, __const char*, ...));
+
+#define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos)
+
+#endif /* __STDIO_H */
diff --git a/libc/string/Config b/libc/string/Config
new file mode 100644
index 0000000..b712dcf
--- /dev/null
+++ b/libc/string/Config
@@ -0,0 +1 @@
+string: String and memory manipulation
diff --git a/libc/string/Makefile b/libc/string/Makefile
new file mode 100644
index 0000000..61fad41
--- /dev/null
+++ b/libc/string/Makefile
@@ -0,0 +1,30 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+SSRC=string.c
+SOBJ=strlen.o strcat.o strcpy.o strcmp.o strncat.o strncpy.o strncmp.o \
+ strchr.o strrchr.o strdup.o memcpy.o memccpy.o memchr.o memset.o \
+ memcmp.o memmove.o movedata.o
+
+OBJ=$(SOBJ) strpbrk.o strsep.o strstr.o strtok.o strcspn.o \
+ strspn.o strcasecmp.o strncasecmp.o
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(SOBJ)): $(SSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+transfer:
+ -@rm -f ../include/string.h
+ cp -p string.h ../include/.
+
+clean:
+ rm -f *.o
diff --git a/libc/string/strcasecmp.c b/libc/string/strcasecmp.c
new file mode 100644
index 0000000..0e7b038
--- /dev/null
+++ b/libc/string/strcasecmp.c
@@ -0,0 +1,26 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int
+strcasecmp(s, d)
+char *s;
+char *d;
+{
+ for(;;)
+ {
+ if( *s != *d )
+ {
+ if( tolower(*s) != tolower(*d) )
+ return *s - *d;
+ }
+ else if( *s == '\0' ) break;
+ s++; d++;
+ }
+ return 0;
+}
+
diff --git a/libc/string/strcspn.c b/libc/string/strcspn.c
new file mode 100644
index 0000000..619c8be
--- /dev/null
+++ b/libc/string/strcspn.c
@@ -0,0 +1,32 @@
+/* strcspn.c */
+
+/* from Schumacher's Atari library, improved */
+
+#include <string.h>
+
+size_t strcspn(string, set)
+register char *string;
+char *set;
+/*
+ * Return the length of the sub-string of <string> that consists
+ * entirely of characters not found in <set>. The terminating '\0'
+ * in <set> is not considered part of the match set. If the first
+ * character if <string> is in <set>, 0 is returned.
+ */
+{
+ register char *setptr;
+ char *start;
+
+ start = string;
+ while (*string)
+ {
+ setptr = set;
+ do
+ if (*setptr == *string)
+ goto break2;
+ while (*setptr++);
+ ++string;
+ }
+break2:
+ return string - start;
+}
diff --git a/libc/string/string.c b/libc/string/string.c
new file mode 100644
index 0000000..3e6d2e4
--- /dev/null
+++ b/libc/string/string.c
@@ -0,0 +1,669 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <malloc.h>
+
+#ifdef __AS386_16__
+#if __FIRST_ARG_IN_AX__
+#define BCC_AX_ASM /* BCC Assembler that can cope with arg in AX */
+#else
+#define BCC_AX_ASM
+#define BCC_ASM /* Use 16 bit BCC assembler */
+#endif
+
+#define PARANOID /* Include extra code for cld and ES register */
+#endif
+
+/* This is a basic string package; it includes the most used functions
+
+ strlen strcat strcpy strcmp strncat strncpy strncmp strchr strrchr strdup
+ memcpy memccpy memchr memset memcmp memmove
+
+ These functions are in seperate files.
+ strpbrk.o strsep.o strstr.o strtok.o strcspn.o
+ strspn.o strcasecmp.o strncasecmp.o
+ */
+
+/********************** Function strlen ************************************/
+
+#ifdef L_strlen
+size_t strlen(str)
+const char * str;
+{
+#ifdef BCC_AX_ASM
+#asm
+#if !__FIRST_ARG_IN_AX__
+ mov bx,sp
+#endif
+ push di
+
+#ifdef PARANOID
+ push es
+ push ds ; Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif ! This is almost the same as memchr, but it can
+ ! stay as a special.
+
+#if __FIRST_ARG_IN_AX__
+ mov di,ax
+#else
+ mov di,[bx+2]
+#endif
+ mov cx,#-1
+ xor ax,ax
+ repne
+ scasb
+ not cx
+ dec cx
+ mov ax,cx
+
+#ifdef PARANOID
+ pop es
+#endif
+ pop di
+#endasm
+#else
+ register char * p =(char *) str;
+ while(*p) p++;
+ return p-str;
+#endif /* ifdef BCC_AX_ASM */
+}
+#endif
+
+/********************** Function strcat ************************************/
+
+#ifdef L_strcat
+char * strcat(d, s)
+char *d;
+const char * s;
+{
+ (void) strcpy(d+strlen(d), s);
+ return d;
+}
+#endif
+
+/********************** Function strcpy ************************************/
+
+#ifdef L_strcpy
+char * strcpy(d, s)
+char *d;
+const char * s;
+{
+ /* This is probably the quickest on an 8086 but a CPU with a cache will
+ * prefer to do this in one pass */
+ return memcpy(d, s, strlen(s)+1);
+}
+#endif
+
+/********************** Function strcmp ************************************/
+
+#ifdef L_strcmp
+int strcmp(d, s)
+const char *d;
+const char * s;
+{
+ /* There are a number of ways to do this and it really does depend on the
+ types of strings given as to which is better, nevertheless the Glib
+ method is quite reasonable so we'll take that */
+
+#ifdef BCC_AX_ASM
+#asm
+ mov bx,sp
+ push di
+ push si
+
+#ifdef PARANOID
+ push es
+ push ds ; Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif
+
+#if __FIRST_ARG_IN_AX__
+ mov di,ax ; dest
+ mov si,[bx+2] ; source
+#else
+ mov di,[bx+2] ; dest
+ mov si,[bx+4] ; source
+#endif
+sc_1:
+ lodsb
+ scasb
+ jne sc_2 ; If bytes are diff skip out.
+ testb al,al
+ jne sc_1 ; If this byte in str1 is nul the strings are equal
+ xor ax,ax ; so return zero
+ jmp sc_3
+sc_2:
+ sbb ax,ax ; Collect correct val (-1,1).
+ orb al,#1
+sc_3:
+
+#ifdef PARANOID
+ pop es
+#endif
+ pop si
+ pop di
+#endasm
+#else /* ifdef BCC_AX_ASM */
+ register char *s1=(char *)d, *s2=(char *)s, c1,c2;
+ while((c1= *s1++) == (c2= *s2++) && c1 );
+ return c1 - c2;
+#endif /* ifdef BCC_AX_ASM */
+}
+#endif
+
+/********************** Function strncat ************************************/
+
+#ifdef L_strncat
+char * strncat(d, s, l)
+char *d, *s;
+size_t l;
+{
+ register char *s1=d+strlen(d), *s2;
+
+ s2 = memchr(s, l, 0);
+ if( s2 )
+ memcpy(s1, s, s2-s+1);
+ else
+ {
+ memcpy(s1, s, l);
+ s1[l] = '\0';
+ }
+ return d;
+}
+#endif
+
+/********************** Function strncpy ************************************/
+
+#ifdef L_strncpy
+char * strncpy(d, s, l) /* FIXME need the fast version of this */
+char *d, *s;
+size_t l;
+{
+ register char *s1=d, *s2=s;
+ while(l > 0)
+ {
+ l--;
+ if( (*s1++ = *s2++) == '\0')
+ break;
+ }
+
+ /* This _is_ correct strncpy is supposed to zap */
+ for(; l>0; l--) *s1++ = '\0';
+ return d;
+}
+#endif
+
+/********************** Function strncmp ************************************/
+
+#ifdef L_strncmp
+int strncmp(d, s, l)
+const char *d, *s;
+size_t l;
+{
+#ifdef BCC_AX_ASM
+#asm
+ mov bx,sp
+ push si
+ push di
+
+#ifdef PARANOID
+ push es
+ push ds ! Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif
+
+#if __FIRST_ARG_IN_AX__
+ mov si,ax
+ mov di,[bx+2]
+ mov cx,[bx+4]
+#else
+ mov si,[bx+2] ! Fetch
+ mov di,[bx+4]
+ mov cx,[bx+6]
+#endif
+
+ inc cx
+lp1:
+ dec cx
+ je lp2
+ lodsb
+ scasb
+ jne lp3
+ testb al,al
+ jne lp1
+lp2:
+ xor ax,ax
+ jmp lp4
+lp3:
+ sbb ax,ax
+ or al,#1
+lp4:
+
+#ifdef PARANOID
+ pop es
+#endif
+ pop di
+ pop si
+#endasm
+#else
+ register char c1=0, c2=0;
+ while(l-- >0)
+ if( (c1= *d++) != (c2= *s++) || c1 == '\0' )
+ break;
+ return c1-c2;
+#endif
+}
+#endif
+
+/********************** Function strchr ************************************/
+
+#ifdef L_strchr
+char *
+strchr(s, c)
+char * s;
+int c;
+{
+#ifdef BCC_AX_ASM
+#asm
+ mov bx,sp
+ push si
+#if __FIRST_ARG_IN_AX__
+ mov bx,[bx+2]
+ mov si,ax
+#else
+ mov si,[bx+2]
+ mov bx,[bx+4]
+#endif
+ xor ax,ax
+
+#ifdef PARANOID
+ cld
+#endif
+
+in_loop:
+ lodsb
+ cmp al,bl
+ jz got_it
+ or al,al
+ jnz in_loop
+ pop si
+ ret
+got_it:
+ lea ax,[si-1]
+ pop si
+
+#endasm
+#else /* ifdef BCC_AX_ASM */
+ register char ch;
+ for(;;)
+ {
+ if( (ch= *s) == c ) return s;
+ if( ch == 0 ) return 0;
+ s++;
+ }
+#endif /* ifdef BCC_AX_ASM */
+}
+#endif
+
+/********************** Function strrchr ************************************/
+
+#ifdef L_strrchr
+char * strrchr(s, c)
+char * s;
+int c;
+{
+ register char * prev = 0;
+ register char * p = s;
+ /* For null it's just like strlen */
+ if( c == '\0' ) return p+strlen(p);
+
+ /* everything else just step along the string. */
+ while( (p=strchr(p, c)) != 0 )
+ {
+ prev = p; p++;
+ }
+ return prev;
+}
+#endif
+
+/********************** Function strdup ************************************/
+
+#ifdef L_strdup
+char * strdup(s)
+char * s;
+{
+ register size_t len;
+ register char * p;
+
+ len = strlen(s)+1;
+ p = (char *) malloc(len);
+ if(p) memcpy(p, s, len); /* Faster than strcpy */
+ return p;
+}
+#endif
+
+/********************** Function memcpy ************************************/
+
+#ifdef L_memcpy
+void *
+memcpy(d, s, l)
+void *d;
+const void *s;
+size_t l;
+{
+#ifdef BCC_AX_ASM
+#asm
+ mov bx,sp
+ push di
+ push si
+
+#ifdef PARANOID
+ push es
+ push ds ; Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif
+
+#if __FIRST_ARG_IN_AX__
+ mov di,ax ; dest
+ mov si,[bx+2] ; source
+ mov cx,[bx+4] ; count
+#else
+ mov di,[bx+2] ; dest
+ mov si,[bx+4] ; source
+ mov cx,[bx+6] ; count
+
+ mov ax,di
+#endif
+ ; If di is odd mov 1 byte before doing word move
+ ; this will speed slightly but
+ ; NB 8086 has no problem with mis-aligned access.
+
+ shr cx,#1 ; Do this faster by doing a mov word
+ rep
+ movsw
+ adc cx,cx ; Retrieve the leftover 1 bit from cflag.
+ rep
+ movsb
+
+#ifdef PARANOID
+ pop es
+#endif
+ pop si
+ pop di
+#endasm
+#else /* ifdef BCC_AX_ASM */
+ register char *s1=d, *s2=(char *)s;
+ for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++);
+ return d;
+#endif /* ifdef BCC_AX_ASM */
+}
+#endif
+
+/********************** Function memccpy ************************************/
+
+#ifdef L_memccpy
+void * memccpy(d, s, c, l) /* Do we need a fast one ? */
+void *s, *d;
+int c;
+size_t l;
+{
+ register char *s1=d, *s2=s;
+ while(l-- > 0)
+ if((*s1++ = *s2++) == c )
+ return s1;
+ return 0;
+}
+#endif
+
+/********************** Function memchr ************************************/
+
+#ifdef L_memchr
+void * memchr(str, c, l)
+const void * str;
+int c;
+size_t l;
+{
+#ifdef BCC_ASM
+#asm
+ mov bx,sp
+ push di
+
+#ifdef PARANOID
+ push es
+ push ds ; Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif
+
+ mov di,[bx+2]
+ mov ax,[bx+4]
+ mov cx,[bx+6]
+ test cx,cx
+ je is_z ! Zero length, do not find.
+
+ repne ! Scan
+ scasb
+ jne is_z ! Not found, ret zero
+ dec di ! Adjust ptr
+ mov ax,di ! return
+ jmp xit
+is_z:
+ xor ax,ax
+xit:
+
+#ifdef PARANOID
+ pop es
+#endif
+ pop di
+#endasm
+#else /* ifdef BCC_ASM */
+ register char *p=(char *)str;
+ while(l-- > 0)
+ {
+ if(*p == c) return p;
+ p++;
+ }
+ return 0;
+#endif /* ifdef BCC_ASM */
+}
+#endif
+
+/********************** Function memset ************************************/
+
+#ifdef L_memset
+void * memset(str, c, l)
+void * str;
+int c;
+size_t l;
+{
+#ifdef BCC_AX_ASM
+#asm
+ mov bx,sp
+ push di
+
+#ifdef PARANOID
+ push es
+ push ds ; Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif
+
+#if __FIRST_ARG_IN_AX__
+ mov di,ax ; Fetch
+ mov ax,[bx+2]
+ mov cx,[bx+4]
+#else
+ mov di,[bx+2] ; Fetch
+ mov ax,[bx+4]
+ mov cx,[bx+6]
+#endif
+
+; How much difference does this alignment make ?
+; I don`t think it`s significant cause most will already be aligned.
+
+; test cx,cx ; Zero size - skip
+; je xit
+;
+; test di,#1 ; Line it up
+; je s_1
+; stosb
+; dec cx
+;s_1:
+
+ mov ah,al ; Replicate byte
+ shr cx,#1 ; Do this faster by doing a sto word
+ rep ; Bzzzzz ...
+ stosw
+ adc cx,cx ; Retrieve the leftover 1 bit from cflag.
+
+ rep ; ... z
+ stosb
+
+xit:
+ mov ax,[bx+2]
+#ifdef PARANOID
+ pop es
+#endif
+ pop di
+#endasm
+#else /* ifdef BCC_AX_ASM */
+ register char *s1=str;
+ while(l-->0) *s1++ = c;
+ return str;
+#endif /* ifdef BCC_AX_ASM */
+}
+#endif
+
+/********************** Function memcmp ************************************/
+
+#ifdef L_memcmp
+int memcmp(s, d, l)
+const void *s, *d;
+size_t l;
+{
+#ifdef BCC_ASM
+#asm
+ mov bx,sp
+ push di
+ push si
+
+#ifdef PARANOID
+ push es
+ push ds ! Im not sure if this is needed, so just in case.
+ pop es
+ cld
+#endif
+
+ mov si,[bx+2] ! Fetch
+ mov di,[bx+4]
+ mov cx,[bx+6]
+ xor ax,ax
+
+ rep ! Bzzzzz
+ cmpsb
+ je xit ! All the same!
+ sbb ax,ax
+ sbb ax,#-1 ! choose +/-1
+xit:
+#ifdef PARANOID
+ pop es
+#endif
+ pop si
+ pop di
+#endasm
+#else /* ifdef BCC_ASM */
+ register const char *s1=d, *s2=s;
+ register char c1=0, c2=0;
+ while(l-- > 0)
+ if( (c1= *s1++) != (c2= *s2++) )
+ break;
+ return c1-c2;
+#endif /* ifdef BCC_ASM */
+}
+#endif
+
+/********************** Function memmove ************************************/
+
+#ifdef L_memmove
+void *
+memmove(d, s, l)
+void *d, *s;
+size_t l;
+{
+ register char *s1=d, *s2=s;
+ /* This bit of sneakyness c/o Glibc, it assumes the test is unsigned */
+ if( s1-s2 >= l ) return memcpy(d,s,l);
+
+ /* This reverse copy only used if we absolutly have to */
+ s1+=l; s2+=l;
+ while(l-- >0)
+ *(--s1) = *(--s2);
+ return d;
+}
+#endif
+
+/********************** Function movedata ***********************************/
+
+#ifdef L_movedata
+
+/* NB There isn't any C version of this function ... */
+
+#ifdef BCC_AX_ASM
+void
+__movedata(srcseg, srcoff, destseg, destoff, len)
+unsigned int srcseg, srcoff, destseg, destoff, len;
+{
+#asm
+ push bp
+ mov bp,sp
+ push si
+ push di
+ push ds
+#ifdef PARANOID
+ push es
+ cld
+#endif
+
+ ! sei ! Are we _really_ paranoid ?
+
+#if !__FIRST_ARG_IN_AX__
+ mov ds,[bp+4] ! Careful, [bp+xx] is SS based.
+ mov si,[bp+6]
+ mov es,[bp+8]
+ mov di,[bp+10]
+ mov cx,[bp+12]
+#else
+ mov ds,ax
+ mov si,[bp+4]
+ mov es,[bp+6]
+ mov di,[bp+8]
+ mov cx,[bp+10]
+#endif
+ rep
+ movsb
+
+ ! cli ! Are we _really_ paranoid ?
+
+#ifdef PARANOID
+ pop es
+#endif
+ pop ds
+ pop di
+ pop si
+ pop bp
+#endasm
+}
+#endif
+
+#endif
+
+/********************** THE END ********************************************/
+
diff --git a/libc/string/string.h b/libc/string/string.h
new file mode 100644
index 0000000..2233bf9
--- /dev/null
+++ b/libc/string/string.h
@@ -0,0 +1,53 @@
+
+#ifndef __STRING_H
+#define __STRING_H
+#include <features.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+/* Basic string functions */
+extern size_t strlen __P ((__const char* __str));
+
+extern char * strcat __P ((char*, __const char*));
+extern char * strcpy __P ((char*, __const char*));
+extern int strcmp __P ((__const char*, __const char*));
+
+extern char * strncat __P ((char*, char*, size_t));
+extern char * strncpy __P ((char*, char*, size_t));
+extern int strncmp __P ((__const char*, __const char*, size_t));
+
+extern char * strchr __P ((char*, int));
+extern char * strrchr __P ((char*, int));
+extern char * strdup __P ((char*));
+
+/* Basic mem functions */
+extern void * memcpy __P ((void*, __const void*, size_t));
+extern void * memccpy __P ((void*, void*, int, size_t));
+extern void * memchr __P ((__const void*, __const int, size_t));
+extern void * memset __P ((void*, int, size_t));
+extern int memcmp __P ((__const void*, __const void*, size_t));
+
+extern void * memmove __P ((void*, void*, size_t));
+
+/* Minimal (very!) locale support */
+#define strcoll strcmp
+#define strxfrm strncpy
+
+/* BSDisms */
+#define index strchr
+#define rindex strrchr
+
+/* Other common BSD functions */
+extern int strcasecmp __P ((char*, char*));
+extern int strncasecmp __P ((char*, char*, size_t));
+char *strpbrk __P ((char *, char *));
+char *strsep __P ((char **, char *));
+char *strstr __P ((char *, char *));
+char *strtok __P ((char *, char *));
+size_t strcspn __P ((char *, char *));
+size_t strspn __P ((char *, char *));
+
+/* Linux silly hour */
+char *strfry __P ((char *));
+
+#endif
diff --git a/libc/string/strncasecmp.c b/libc/string/strncasecmp.c
new file mode 100644
index 0000000..561f72a
--- /dev/null
+++ b/libc/string/strncasecmp.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int
+strncasecmp(s, d, l)
+char *s;
+char *d;
+size_t l;
+{
+ while(l>0)
+ {
+ if( *s != *d )
+ {
+ if( tolower(*s) != tolower(*d) )
+ return *s - *d;
+ }
+ else
+ if( *s == '\0' ) return 0;
+ s++; d++; l--;
+ }
+ return 0;
+}
+
diff --git a/libc/string/strpbrk.c b/libc/string/strpbrk.c
new file mode 100644
index 0000000..3fc27ec
--- /dev/null
+++ b/libc/string/strpbrk.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+
+/* This uses strchr, strchr should be in assembler */
+
+char *strpbrk(str, set)
+register char *str;
+char *set;
+{
+ while (*str != '\0')
+ if (strchr(set, *str) == 0)
+ ++str;
+ else
+ return (char *) str;
+
+ return 0;
+}
diff --git a/libc/string/strsep.c b/libc/string/strsep.c
new file mode 100644
index 0000000..21aa1bb
--- /dev/null
+++ b/libc/string/strsep.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h>
+
+char *
+strsep(pp, delim)
+char **pp;
+char *delim;
+{
+ char *p, *q;
+
+ if (!(p = *pp))
+ return 0;
+ if (q = strpbrk (p, delim))
+ {
+ *pp = q + 1;
+ *q = '\0';
+ }
+ else
+ *pp = 0;
+ return p;
+}
diff --git a/libc/string/strspn.c b/libc/string/strspn.c
new file mode 100644
index 0000000..2094caa
--- /dev/null
+++ b/libc/string/strspn.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h>
+
+/* Return the length of the maximum initial segment
+ of S which contains only characters in ACCEPT. */
+size_t
+strspn(s, accept)
+char *s;
+char *accept;
+{
+ register char *p;
+ register char *a;
+ register size_t count = 0;
+
+ for (p = s; *p != '\0'; ++p)
+ {
+ for (a = accept; *a != '\0'; ++a)
+ if (*p == *a)
+ break;
+ if (*a == '\0')
+ return count;
+ else
+ ++count;
+ }
+
+ return count;
+}
diff --git a/libc/string/strstr.c b/libc/string/strstr.c
new file mode 100644
index 0000000..aafcaf9
--- /dev/null
+++ b/libc/string/strstr.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <string.h>
+
+#if 1
+/* We've now got a nice fast strchr and memcmp use them */
+
+char *
+strstr(s1, s2)
+char *s1; char *s2;
+{
+ register int l = strlen(s2);
+ register char * p = s1;
+
+ if( l==0 ) return p;
+
+ while (p = strchr(p, *s2))
+ {
+ if( memcmp(p, s2, l) == 0 )
+ return p;
+ p++;
+ }
+ return (char *) 0;
+}
+
+#else
+/* This is a nice simple self contained strstr,
+ now go and work out why the GNU one is faster :-) */
+
+char *strstr(str1, str2)
+char *str1, *str2;
+{
+ register char *Sptr, *Tptr;
+ int len = strlen(str1) -strlen(str2) + 1;
+
+ if (*str2)
+ for (; len > 0; len--, str1++){
+ if (*str1 != *str2)
+ continue;
+
+ for (Sptr = str1, Tptr = str2; *Tptr != '\0'; Sptr++, Tptr++)
+ if (*Sptr != *Tptr)
+ break;
+
+ if (*Tptr == '\0')
+ return (char*) str1;
+ }
+
+ return (char*)0;
+}
+#endif
diff --git a/libc/string/strtok.c b/libc/string/strtok.c
new file mode 100644
index 0000000..27d8f25
--- /dev/null
+++ b/libc/string/strtok.c
@@ -0,0 +1,71 @@
+/* Copyright (C) 1991 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#include <string.h>
+
+
+static char *olds = 0;
+
+/* Parse S into tokens separated by characters in DELIM.
+ If S is NULL, the last string strtok() was called with is
+ used. For example:
+ char s[] = "-abc=-def";
+ x = strtok(s, "-"); // x = "abc"
+ x = strtok(NULL, "=-"); // x = "def"
+ x = strtok(NULL, "="); // x = NULL
+ // s = "abc\0-def\0"
+*/
+char *
+strtok(s, delim)
+register char *s;
+register char *delim;
+{
+ char *token;
+
+ if (s == 0)
+ {
+ if (olds == 0)
+ {
+ return 0;
+ }
+ else
+ s = olds;
+ }
+
+ /* Scan leading delimiters. */
+ s += strspn(s, delim);
+ if (*s == '\0')
+ {
+ olds = 0;
+ return 0;
+ }
+
+ /* Find the end of the token. */
+ token = s;
+ s = strpbrk(token, delim);
+ if (s == 0)
+ /* This token finishes the string. */
+ olds = 0;
+ else
+ {
+ /* Terminate the token and make OLDS point past it. */
+ *s = '\0';
+ olds = s + 1;
+ }
+ return token;
+}
diff --git a/libc/syscall/Config b/libc/syscall/Config
new file mode 100644
index 0000000..472e74b
--- /dev/null
+++ b/libc/syscall/Config
@@ -0,0 +1 @@
+syscall: Linux-8086 system call routines
diff --git a/libc/syscall/Makefile b/libc/syscall/Makefile
new file mode 100644
index 0000000..fd1b187
--- /dev/null
+++ b/libc/syscall/Makefile
@@ -0,0 +1,64 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+LSRC=syslibc.c
+LOBJ=time.o abort.o wait.o waitpid.o wait3.o killpg.o setpgrp.o sleep.o \
+ usleep.o
+
+LSRC0=syslib0.c
+LOBJ0=__cstartup.o lseek.o getpid.o getppid.o getuid.o geteuid.o getgid.o \
+ getegid.o dup2.o dup.o getpgrp.o times.o
+
+ESRC=exec.c
+EOBJ=execve.o execl.o execv.o execle.o execlp.o execvp.o
+
+DSRC=dirent.c
+DOBJ=opendir.o closedir.o readdir.o
+
+ifeq ($(LIB_CPU)-$(LIB_OS),i86-ELKS)
+OBJ=$(LOBJ0) $(LOBJ) $(DOBJ) $(EOBJ) signal.o setjmp.o
+SYSCALLS=call_i86
+endif
+
+ifeq ($(SYSCALLS),)
+OBJ=setjmp.o
+endif
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(SYSCALLS) $(LIBC)
+ @:
+
+call_i86: syscall.mak
+ $(MAKE) -f syscall.mak LIBC="$(LIBC)" CFLAGS="$(CFLAGS)"
+
+syscall.mak: mksyscall syscall.dat
+ sh mksyscall
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(LOBJ)): $(LSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(DOBJ)): $(DSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(EOBJ)): $(ESRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+$(LIBC)($(LOBJ0)): $(LSRC0)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+
+clean:
+ rm -f *.o libc.a
+ rm -f syscall.c syscall.mak
+ rm -f call_tab.v defn_tab.v
diff --git a/libc/syscall/TODO b/libc/syscall/TODO
new file mode 100644
index 0000000..b178a96
--- /dev/null
+++ b/libc/syscall/TODO
@@ -0,0 +1,5 @@
+SYSV IPC, there's and __ipc syscall and the hardware can manage messages and
+semaphores.
+
+Idea, for RPC syscall, seperate all the FD related calls from the system ones
+IIRC all the single FD related ones have the FD in arg0
diff --git a/libc/syscall/dirent.c b/libc/syscall/dirent.c
new file mode 100644
index 0000000..8f7574c
--- /dev/null
+++ b/libc/syscall/dirent.c
@@ -0,0 +1,106 @@
+
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <malloc.h>
+
+#ifdef L_opendir
+DIR *
+opendir(dname)
+const char *dname;
+{
+ struct stat st;
+ int fd;
+ DIR *p;
+
+ if (stat(dname, &st) < 0)
+ return 0;
+
+ if (!S_ISDIR(st.st_mode))
+ {
+ errno = ENOTDIR;
+ return 0;
+ }
+ if ((fd = open(dname, O_RDONLY)) < 0)
+ return 0;
+
+ p = malloc(sizeof(DIR));
+ if (p == 0)
+ {
+ close(fd);
+ return 0;
+ }
+
+ p->dd_buf = malloc(sizeof(struct dirent));
+ if (p->dd_buf == 0)
+ {
+ free(p);
+ close(fd);
+ return 0;
+ }
+ p->dd_fd = fd;
+ p->dd_loc = p->dd_size = 0;
+
+ return p;
+}
+#endif
+
+#ifdef L_closedir
+int
+closedir(dirp)
+DIR *dirp;
+{
+ int fd;
+ fd = dirp->dd_fd;
+ free(dirp->dd_buf);
+ free(dirp);
+ return close(fd);
+}
+#endif
+
+#ifdef __AS386_16__
+#ifdef L_readdir
+/*
+ * This currently assumes we see a v. simple diectory structure, it's
+ * probably faked!
+ */
+struct dirent *
+readdir(dirp)
+DIR *dirp;
+{
+ int cc;
+ cc = read(dirp->dd_fd, dirp->dd_buf, sizeof(struct dirent));
+
+ if (cc <= 0)
+ return 0;
+ if (cc != sizeof(struct dirent))
+ {
+ errno = EBADF;
+ return 0;
+ }
+ return dirp->dd_buf;
+}
+#endif
+#else
+
+/* This is for 386 linux */
+
+#ifdef L_readdir
+struct dirent *
+readdir(dirp)
+DIR *dirp;
+{
+ int cc;
+
+ cc = __readdir(dirp->dd_fd, dirp->dd_buf, 1);
+ if (cc <= 0)
+ return 0;
+ if (cc>1) dirp->dd_buf->d_name[cc] = 0;
+
+ return dirp->dd_buf;
+}
+#endif
+
+#endif
diff --git a/libc/syscall/exec.c b/libc/syscall/exec.c
new file mode 100644
index 0000000..411b744
--- /dev/null
+++ b/libc/syscall/exec.c
@@ -0,0 +1,292 @@
+
+#include <errno.h>
+#include <sys/stat.h>
+
+extern char ** environ;
+
+#ifdef L_execl
+int
+execl(fname, arg0)
+char * fname, *arg0;
+{
+ return execve(fname, &arg0, environ);
+}
+#endif
+
+#ifdef L_execv
+int
+execv(fname, argv)
+char * fname, **argv;
+{
+ return execve(fname, argv, environ);
+}
+#endif
+
+#ifdef L_execle
+int
+execle(fname, arg0)
+char *fname, *arg0;
+{
+ char ** envp = &arg0;
+ while(*envp) envp++;
+ return execve(fname, &arg0, envp+1);
+}
+#endif
+
+#ifdef L_execve
+int
+execve(fname, argv, envp)
+char * fname;
+char ** argv;
+char ** envp;
+{
+ char **p;
+ int argv_len=0, argv_count=0;
+ int envp_len=0, envp_count=0;
+ int stack_bytes;
+ unsigned short * pip;
+ char * pcp, * stk_ptr, *baseoff;
+ int rv;
+
+ /* How much space for argv */
+ for(p=argv; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+
+ /* How much space for envp */
+ for(p=envp; p && *p && envp_len >= 0; p++)
+ {
+ envp_count++; envp_len += strlen(*p)+1;
+ }
+
+ /* tot it all up */
+ stack_bytes = 2 /* argc */
+ + argv_count * 2 + 2 /* argv */
+ + argv_len
+ + envp_count * 2 + 2 /* envp */
+ + envp_len;
+
+ /* Allocate it */
+ if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0
+ || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+/* Sanity check
+ printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
+ argv_count, argv_len, envp_count, envp_len, stack_bytes);
+*/
+
+ /* Now copy in the strings */
+ pip=(unsigned short *) stk_ptr;
+ pcp=stk_ptr+2*(1+argv_count+1+envp_count+1);
+
+ /* baseoff = stk_ptr + stack_bytes; */
+ baseoff = stk_ptr;
+ *pip++ = argv_count;
+ for(p=argv; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ for(p=envp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ rv = __exec(fname, stk_ptr, stack_bytes);
+ /* FIXME: This will probably have to interpret '#!' style exe's */
+ sbrk(-stack_bytes);
+ return rv;
+}
+#endif
+
+#ifdef L_execlp
+int
+execlp(fname, arg0)
+char * fname, *arg0;
+{
+ return execvp(fname, &arg0);
+}
+#endif
+
+#ifdef L_execvp
+int
+execvp(fname, argv)
+char * fname, **argv;
+{
+ char *pname = fname, *path;
+ int besterr = ENOENT;
+ int flen, plen;
+ char * bp = sbrk(0);
+
+ if( *fname != '/' && (path = getenv("PATH")) != 0 )
+ {
+ flen = strlen(fname)+2;
+
+ for(;path;)
+ {
+ if( *path == ':' || *path == '\0' )
+ {
+ tryrun(fname, argv);
+ if( errno == EACCES ) besterr = EACCES;
+ if( *path ) path++; else break;
+ }
+ else
+ {
+ char * p = strchr(path, ':');
+ if(p) *p = '\0';
+ plen = strlen(path);
+ pname = sbrk(plen+flen);
+
+ strcpy(pname, path);
+ strcat(pname, "/");
+ strcat(pname, fname);
+
+ tryrun(pname, argv);
+ if( errno == EACCES ) besterr = EACCES;
+
+ brk(pname);
+ pname = fname;
+ if(p) *p++ = ':';
+ path=p;
+ }
+ }
+ }
+
+ tryrun(pname, argv);
+ brk(bp);
+ if( errno == ENOENT || errno == 0 ) errno = besterr;
+ return -1;
+}
+
+static int tryrun(pname, argv)
+char * pname;
+char ** argv;
+{
+static char *shprog[] = {"/bin/sh", "", 0};
+ struct stat st;
+
+ if( stat(pname, &st) < 0 ) return;
+ if( !S_ISREG(st.st_mode) ) return;
+
+#ifdef __AS386_16__
+ __execvve(pname, (void*)0, argv, environ);
+ if( errno == ENOEXEC )
+ {
+ shprog[1] = pname;
+ __execvve(shprog[0], shprog, argv, environ);
+ }
+#else
+ execve(pname, argv, environ);
+ /* FIXME - running /bin/sh in 386 mode */
+#endif
+}
+
+#ifdef __AS386_16__
+static int
+__execvve(fname, interp, argv, envp)
+char * fname;
+char ** interp;
+char ** argv;
+char ** envp;
+{
+ char **p;
+ int argv_len=0, argv_count=0;
+ int envp_len=0, envp_count=0;
+ int stack_bytes;
+ unsigned short * pip;
+ char * pcp, * stk_ptr, *baseoff;
+ int rv;
+
+ /* How much space for argv */
+ for(p=interp; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+ for(p=argv; p && *p && argv_len >= 0; p++)
+ {
+ argv_count++; argv_len += strlen(*p)+1;
+ }
+
+ /* How much space for envp */
+ for(p=envp; p && *p && envp_len >= 0; p++)
+ {
+ envp_count++; envp_len += strlen(*p)+1;
+ }
+
+ /* tot it all up */
+ stack_bytes = 2 /* argc */
+ + argv_count * 2 + 2 /* argv */
+ + argv_len
+ + envp_count * 2 + 2 /* envp */
+ + envp_len;
+
+ /* Allocate it */
+ if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0
+ || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+/* Sanity check
+ printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n",
+ argv_count, argv_len, envp_count, envp_len, stack_bytes);
+*/
+
+ /* Now copy in the strings */
+ pip=(unsigned short *) stk_ptr;
+ pcp=stk_ptr+2*(1+argv_count+1+envp_count+1);
+
+ /* baseoff = stk_ptr + stack_bytes; */
+ baseoff = stk_ptr;
+ *pip++ = argv_count;
+ for(p=interp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ for(p=argv; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ for(p=envp; p && *p; p++)
+ {
+ int l;
+ *pip++ = pcp-baseoff;
+ l = strlen(*p)+1;
+ memcpy(pcp, *p, l);
+ pcp += l;
+ }
+ *pip++ = 0;
+
+ rv = __exec(fname, stk_ptr, stack_bytes);
+ /* FIXME: This will probably have to interpret '#!' style exe's */
+ sbrk(-stack_bytes);
+ return rv;
+}
+#endif
+#endif
diff --git a/libc/syscall/mksyscall b/libc/syscall/mksyscall
new file mode 100644
index 0000000..2005029
--- /dev/null
+++ b/libc/syscall/mksyscall
@@ -0,0 +1,289 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+#
+# This script generates the 'simple' system calls.
+#
+# Each call is put into it's own object file, if the semantics of the
+# call are not correct UNIX then the 4th field in the dat file has a
+# marker and the function is generated with a __ prefix.
+#
+#
+# Different levels of squeeze
+# 0 = each is complete
+# 1 = Short codes calling common function
+
+COMPACT=1
+
+rm -f syscall.c syscall.mak call_tab.v defn_tab.v
+
+tr '[A-Z]' '[a-z]' < syscall.dat | \
+awk -v COMPACT=$COMPACT 'BEGIN{
+ print "# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>" > "syscall.mak";
+ print "# This file is part of the Linux-8086 C library and is distributed" > "syscall.mak";
+ print "# under the GNU Library General Public License." > "syscall.mak";
+ print "# " > "syscall.mak";
+ print "# This file is automatically generated\n" > "syscall.mak"
+
+ print "/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>";
+ print " * This file is part of the Linux-8086 C library and is distributed";
+ print " * under the GNU Library General Public License.";
+ print " * ";
+ print " * This file is automatically generated */\n"
+ obj="OBJ=";
+
+ print "/* Standard start */\n\n"
+ printf("#ifndef __MSDOS__\n");
+ printf("#ifdef __AS386_16__\n");
+ printf("#asm\n");
+ printf(" .text\n");
+ printf(" .even\n");
+ printf("#endasm\n\n");
+
+ {
+ obj=obj "__syscall.o __syscall4.o ";
+ print "/* Shared system call code */\n"
+ printf("#ifdef L___syscall\n", funcname);
+ printf("#asm\n");
+ printf("#if __FIRST_ARG_IN_AX__\n");
+
+ printf("export sys_call3\nsys_call3:\n");
+ printf(" mov bx,sp\n");
+ printf(" mov cx,[bx+2]\n");
+ printf(" mov bx,[bx+4]\n");
+ # ax=arg1 bx=arg3 cx=arg2 dx=arg0
+ printf(" xchg ax,bx\n");
+ # ax=arg3 bx=arg1 cx=arg2 dx=arg0
+ printf(" xchg ax,dx\n");
+ # ax=arg0 bx=arg1 cx=arg2 dx=arg3
+ printf(" jmp sys_call0\n\n");
+
+ printf("export sys_call2\nsys_call2:\n");
+ printf(" mov bx,sp\n");
+ printf(" mov cx,[bx+2]\n");
+ printf(" mov bx,ax\n");
+ printf(" mov ax,dx\n");
+ printf(" jmp sys_call0\n\n");
+
+ printf("export sys_call1\nsys_call1:\n");
+ printf(" mov bx,ax\n");
+ printf(" mov ax,dx\n");
+ printf("#else\n");
+ printf("export sys_call3\nsys_call3:\n");
+ printf(" mov bx,sp\n");
+ printf(" mov dx,[bx+6]\n");
+ printf(" mov cx,[bx+4]\n");
+ printf(" mov bx,[bx+2]\n");
+ printf(" jmp sys_call0\n\n");
+
+ printf("export sys_call2\nsys_call2:\n");
+ printf(" mov bx,sp\n");
+ printf(" mov cx,[bx+4]\n");
+ printf(" mov bx,[bx+2]\n");
+ printf(" jmp sys_call0\n\n");
+
+ printf("export sys_call1\nsys_call1:\n");
+ printf(" mov bx,sp\n");
+ printf(" mov bx,[bx+2]\n");
+ printf("#endif\n\n");
+
+ printf("export sys_call0\nsys_call0:\n");
+ printf(" int $80\n");
+ printf(" test ax,ax\n");
+ printf(" jge syscall_ok\n");
+ printf(" neg ax\n");
+ printf(" mov [_errno],ax\n");
+ printf(" mov ax,#-1\n");
+ printf("syscall_ok:\n");
+ printf(" ret\n");
+ printf("#endasm\n");
+ printf("#endif\n\n");
+
+ print "/* Shared system call code, syscalls with 4/5 args */\n"
+ printf("#ifdef L___syscall4\n", funcname);
+ printf("#asm\n");
+ printf("#if __FIRST_ARG_IN_AX__\n");
+
+ printf("export sys_call4\nsys_call4:\n");
+ printf("export sys_call5\nsys_call5:\n");
+ printf(" mov bx,sp\n");
+ printf(" push si\n");
+ printf(" mov si,[bx+8]\n");
+ printf(" push di\n");
+ printf(" mov di,[bx+6]\n");
+ printf(" mov cx,[bx+2]\n");
+ printf(" mov bx,[bx+4]\n");
+ # ax=arg1 bx=arg3 cx=arg2 dx=arg0
+ printf(" xchg ax,bx\n");
+ # ax=arg3 bx=arg1 cx=arg2 dx=arg0
+ printf(" xchg ax,dx\n");
+ # ax=arg0 bx=arg1 cx=arg2 dx=arg3
+ printf("#else\n");
+ printf("export sys_call4\nsys_call4:\n");
+ printf("export sys_call5\nsys_call5:\n");
+ printf(" mov bx,sp\n");
+ printf(" push si\n");
+ printf(" mov si,[bx+10]\n");
+ printf(" push di\n");
+ printf(" mov di,[bx+8]\n");
+ printf(" mov dx,[bx+6]\n");
+ printf(" mov cx,[bx+4]\n");
+ printf(" mov bx,[bx+2]\n");
+ printf("#endif\n\n");
+
+ printf(" int $80\n");
+ printf(" pop di\n");
+ printf(" pop si\n");
+ printf(" test ax,ax\n");
+ printf(" jge syscall_ok\n");
+ printf(" neg ax\n");
+ printf(" mov [_errno],ax\n");
+ printf(" mov ax,#-1\n");
+ printf("syscall_ok:\n");
+ printf(" ret\n");
+ printf("#endasm\n");
+ printf("#endif\n\n");
+ }
+}
+/^[ ]*#/ { next; }
+/^[ ]*$/ { next; }
+{
+ if( $2 > max_call ) max_call = $2;
+ if( !($2 in calltab) )
+ callwas[$2] = " /* " $1 " */";
+
+ if( $3 == "x" || $3 == "" ) next;
+ else if( $4 == "-" ) next;
+ else if( $4 == "*" ) funcname="__" $1;
+ else funcname=$1;
+
+ calltab[$2] = $1;
+
+ if( length(obj) > 60 )
+ {
+ printf("%s\t\\\n", obj) > "syscall.mak";
+ obj=" ";
+ }
+ obj=obj funcname ".o ";
+
+ printf "/* CALL %s */\n\n", $0;
+
+ printf("#ifdef L_%s\n", funcname);
+ printf("#asm\n", funcname);
+ printf("export _%s\n", funcname);
+ printf("_%s:\n", funcname);
+
+ # Inline assembler max to 5 args (10 bytes)
+ if( $3 != 4 && $3 != 5 && ( COMPACT || $3 > 5 ))
+ {
+ if( $3 == 0 )
+ {
+ printf(" mov ax,#%d\n", $2);
+ }
+ else
+ {
+ printf("#if __FIRST_ARG_IN_AX__\n");
+ printf(" mov dx,#%d\n", $2);
+ printf("#else\n");
+ printf(" mov ax,#%d\n", $2);
+ printf("#endif\n");
+ }
+ printf(" br sys_call%d\n", $3);
+ }
+ else
+ {
+ if( $3 >= 1 )
+ printf("#if __FIRST_ARG_IN_AX__\n");
+ if( $3 >= 2 )
+ printf(" mov bx,sp\n");
+ if( $3 >= 5 )
+ printf(" push si\n");
+ if( $3 >= 5 )
+ printf(" mov si,[bx+8]\n");
+ if( $3 >= 4 )
+ printf(" push di\n");
+ if( $3 >= 4 )
+ printf(" mov di,[bx+6]\n");
+ if( $3 >= 3 )
+ printf(" mov dx,[bx+4]\n");
+ if( $3 >= 2 )
+ printf(" mov cx,[bx+2]\n");
+ if( $3 >= 1 )
+ printf(" mov bx,ax\n");
+ if( $3 >= 1 )
+ printf("#else\n");
+ if( $3 >= 1 )
+ printf(" mov bx,sp\n");
+ if( $3 >= 5 )
+ printf(" push si\n");
+ if( $3 >= 5 )
+ printf(" mov si,[bx+10]\n");
+ if( $3 >= 4 )
+ printf(" push di\n");
+ if( $3 >= 4 )
+ printf(" mov di,[bx+8]\n");
+ if( $3 >= 3 )
+ printf(" mov dx,[bx+6]\n");
+ if( $3 >= 2 )
+ printf(" mov cx,[bx+4]\n");
+ if( $3 >= 1 )
+ printf(" mov bx,[bx+2]\n");
+ if( $3 >= 1 )
+ printf("#endif\n");
+
+ printf(" mov ax,#%d\n", $2);
+
+ printf(" int $80\n");
+
+ if( $3 >= 4 )
+ printf(" pop di\n");
+ if( $3 >= 5 )
+ printf(" pop si\n");
+
+ printf(" test ax,ax\n");
+ printf(" jl syscall_err\n");
+ printf(" ret\n");
+ printf("syscall_err:\n");
+ printf(" neg ax\n");
+ printf(" mov [_errno],ax\n");
+ printf(" mov ax,#-1\n");
+ printf(" ret\n");
+ }
+ printf("#endasm\n");
+ printf("#endif\n\n");
+}
+END{
+
+ for(i=0; i<=max_call; i++)
+ if( i in calltab )
+ {
+ printf("#ifndef sys_%s\n", calltab[i]) > "defn_tab.v";
+ printf("#define sys_%s sys_enosys\n", calltab[i]) > "defn_tab.v";
+ printf("#endif\n\n") > "defn_tab.v";
+ }
+
+ for(i=0; i<=max_call; i++)
+ if( i in calltab )
+ printf("/* %3d */ sys_%s,\n", i, calltab[i]) > "call_tab.v";
+ else
+ printf("/* %3d */ sys_enosys,%s\n", i, callwas[i]) > "call_tab.v";
+
+ printf("#endif /* __AS386_16__ */\n\n");
+ printf("#endif /* __MSDOS__ */\n\n");
+ printf("%s\n", obj) > "syscall.mak";
+ printf "\n" > "syscall.mak";
+
+}' > syscall.c
+
+cat >> syscall.mak <<\!
+
+all: $(LIBC)($(OBJ))
+ @:
+
+$(LIBC)($(OBJ)): syscall.dat
+ $(CC) $(CFLAGS) -DL_$* syscall.c -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+!
+
+exit $?
diff --git a/libc/syscall/setjmp.c b/libc/syscall/setjmp.c
new file mode 100644
index 0000000..58b57ad
--- /dev/null
+++ b/libc/syscall/setjmp.c
@@ -0,0 +1,56 @@
+
+#include <setjmp.h>
+
+#if __AS386_16__
+
+int
+setjmp(env)
+jmp_buf env;
+{
+#asm
+export __setjmp
+__setjmp:
+
+ pop cx ! PC
+#if __FIRST_ARG_IN_AX__
+ mov bx,ax
+#else
+ mov bx,sp
+ mov bx,[bx] ! TOS is prt -> env
+#endif
+ mov [bx+0],cx ! PC
+ mov [bx+2],sp ! This registers are all that may be constant.
+ mov [bx+4],bp
+ mov [bx+6],si ! Is saving these the "right thing" ?
+ mov [bx+8],di
+ xor ax,ax
+ jmp cx
+#endasm
+}
+
+void
+longjmp(env, rv)
+jmp_buf env;
+int rv;
+{
+#asm
+export __longjmp
+__longjmp:
+
+ pop cx ! pc
+#if __FIRST_ARG_IN_AX__
+ mov bx,ax ! env->
+#else
+ pop bx ! env->
+#endif
+ pop ax ! rv
+ mov cx,[bx+0] ! PC
+ mov sp,[bx+2]
+ mov bp,[bx+4]
+ mov si,[bx+6]
+ mov di,[bx+8]
+ jmp cx
+#endasm
+}
+
+#endif
diff --git a/libc/syscall/signal.c b/libc/syscall/signal.c
new file mode 100644
index 0000000..dad3389
--- /dev/null
+++ b/libc/syscall/signal.c
@@ -0,0 +1,99 @@
+
+#ifndef __MSDOS__
+#ifdef __AS386_16__
+
+#include <errno.h>
+#include <signal.h>
+
+typedef __sighandler_t Sig;
+
+extern int __signal __P((int, __sighandler_t));
+static Sig system_signal();
+
+Sig __sigtable[_NSIG-1];
+
+/*
+ * Signal handler.
+ *
+ */
+
+/*
+ * KERNEL INTERFACE:
+ * It is assumed the kernel will never give us a signal we haven't
+ * _explicitly_ asked for!
+ *
+ * The Kernel need only save space for _one_ function pointer
+ * (to system_signal) and must deal with SIG_DFL and SIG_IGN
+ * in kernel space.
+ *
+ * When a signal is required the kernel must set all the registers as if
+ * returning from a interrupt normally then push the number of the signal
+ * to be generated, push the current pc value, then set the pc to the
+ * address of the 'system_signal' function.
+ */
+
+Sig
+signal(number, pointer)
+int number;
+Sig pointer;
+{
+ Sig old_sig;
+ int rv;
+ if( number < 1 || number >= _NSIG ) { errno=EINVAL; return SIG_ERR; }
+
+ if( pointer == SIG_DFL || pointer == SIG_IGN )
+ rv = __signal(number, pointer);
+ else
+ rv = __signal(number, (__sighandler_t) system_signal);
+
+ if( rv < 0 ) return SIG_ERR;
+
+ old_sig = __sigtable[number-1];
+ __sigtable[number-1] = pointer;
+
+ switch(rv)
+ {
+ case 0: return SIG_DFL;
+ case 1: return SIG_IGN;
+ return old_sig;
+ }
+}
+
+#asm
+ .text
+_system_signal: ! When this is called by the kernel the stack contains
+ pushf ! in order:
+ push ax !
+ push bx ! The signal number, (NOS)
+ push cx ! The program counter, (TOS)
+ push dx !
+ push si ! It does NOT contain the CS register or the flags.
+ push di ! This means it cannot be unraveled by an iret.
+ push bp
+ push es ! Note also only ES segment register is saved.
+ mov bx,sp ! Unlike minix the rv from a system call is in AX.
+ mov bx,[bx+20]
+#if __FIRST_ARG_IN_AX__
+ mov ax,bx
+#else
+ push bx ! NB this is _unchecked_, do we want to ?
+#endif
+ add bx,bx
+ mov bx,[bx+___sigtable-2] ! Offset by 2 cause no entry for signal 0
+ call bx ! Do we want to check BX for 0 or 1 ?
+ inc sp
+ inc sp
+ pop es
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ popf
+ ret #2 ! Get rid of the signum too.
+#endasm
+
+#endif /* __AS386_16__ */
+#endif /* __MSDOS__ */
diff --git a/libc/syscall/syscall.dat b/libc/syscall/syscall.dat
new file mode 100644
index 0000000..de5ed9b
--- /dev/null
+++ b/libc/syscall/syscall.dat
@@ -0,0 +1,142 @@
+#
+# Name No Args Flag, comment
+#
+# . = Ok, with comment
+# * = Needs libc code (Prefix __)
+# - = Obsolete/not required
+#
+# WARNING!
+# This file is used to generate includes for ELKSemu too.
+# This file is continually changing, when you upgrade you _MUST_ ensure
+# that ELKSemu is of a matching build!
+#
+# Calls that use one fd
+READ 3 3
+WRITE 4 3
+CLOSE 6 1
+LSEEK 19 3 * NB 2nd arg is an IO ptr to long not a long.
+FSTAT 28 2
+IOCTL 54 3 . Make this and fcntl the same ?
+FCNTL 55 3
+FTRUNCATE 93 3
+FCHMOD 94 2
+FCHOWN 95 3
+FSYNC 118 1
+FCHDIR 133 1
+LLSEEK 140 3 * 2nd arg is ptr to two longs
+READV 145 3
+WRITEV 146 3
+FLOCK 143 2 - Use fcntl
+DUP 41 1 - Using nasty fcntl function
+
+#
+SETUP 0 X
+EXIT 1 1 * C exit does stdio, _exit in crt0
+FORK 2 0
+OPEN 5 3
+WAIT4 7 4
+VFORK 8 0 . Needed for 8086
+GETINFO 49 1 - Possible? Gets pid,ppid,uid,euid etc
+LINK 9 2
+UNLINK 10 1
+EXEC 11 3 * Minix style exec
+CHDIR 12 1
+GETTIMEOFDAY 13 2 . time() exists only in libc
+MKNOD 14 3
+CHMOD 15 2
+CHOWN 16 3
+BRK 17 1 * This is only to tell the system
+STAT 18 2
+GETPID 20 1 * This gets both pid & ppid
+MOUNT 21 5
+UMOUNT 22 1
+SETUID 23 1
+GETUID 24 1 * This gets both uid and euid
+SETTIMEOFDAY 25 2 . STIME should _NOT_ exist even as a libc.
+STIME 25 2 - This must NOT exist - even as a libc.
+PTRACE 26 4
+ALARM 27 2
+PAUSE 29 0
+UTIME 30 2
+ACCESS 33 2
+NICE 34 1 .
+FTIME 35 1 - Use gettimeofday
+SYNC 36 0
+KILL 37 2
+RENAME 38 2
+MKDIR 39 2
+RMDIR 40 1
+PIPE 42 1
+TIMES 43 2 * 2nd arg is pointer for long ret val.
+SETGID 46 1
+GETGID 47 1 * This gets both gid and egid
+SIGNAL 48 2 * Have put the despatch table in user space.
+ACCT 51 1 -
+SETPGID 57 2
+ULIMIT 58 2
+UMASK 60 1
+CHROOT 61 1
+USTAT 62 2
+GETPGRP 65 0 - use getpgid(0)
+SETSID 66 0
+SIGACTION 67 X
+SGETMASK 68 X
+SSETMASK 69 X
+SETREUID 70 2
+SETREGID 71 2
+SIGSUSPEND 72 X
+SIGPENDING 73 X
+SETHOSTNAME 74 2
+SETRLIMIT 75 2
+GETRLIMIT 76 2
+GETRUSAGE 77 2
+GETGROUPS 80 2
+SETGROUPS 81 2
+SYMLINK 83 2
+LSTAT 84 2
+READLINK 85 3
+SWAPON 87 X
+REBOOT 88 3 . The magic number is 0xfee1,0xdead,...
+MUNMAP 91 X
+TRUNCATE 92 3
+GETPRIORITY 96 2
+SETPRIORITY 97 3
+PROFIL 98 X
+STATFS 99 2
+FSTATFS 100 2
+SOCKETCALL 102 X
+SYSLOG 103 X
+SETITIMER 104 3
+GETITIMER 105 2
+UNAME 109 1
+VHANGUP 111 0
+SWAPOFF 115 X
+SYSINFO 116 X - Use /proc
+IPC 117 5 * This is for all SYSV IPC
+SIGRETURN 119 X
+SETDOMAINNAME 121 X
+ADJTIMEX 124 X
+MPROTECT 125 X
+SIGPROCMASK 126 X
+QUOTACTL 131 X
+GETPGID 132 1
+SYSFS 135 X
+PERSONALITY 136 X
+SETFSUID 138 1
+SETFSGID 139 1
+GETDENTS 141 X
+SELECT 142 5 *
+MSYNC 144 X
+GETSID 147 X
+FDATASYNC 148 X
+SYSCTL 149 X
+MUNLOCK 151 X
+MUNLOCKALL 153 X
+SCHED_SETPARAM 154 X
+SCHED_GETPARAM 155 X
+SCHED_SETSCHEDULER 156 X
+SCHED_GETSCHEDULER 157 X
+SCHED_YIELD 158 X
+SCHED_GET_PRIORITY_MAX 159 X
+SCHED_GET_PRIORITY_MIN 160 X
+SCHED_RR_GET_INTERVAL 161 X
diff --git a/libc/syscall/syscall.dat.chad b/libc/syscall/syscall.dat.chad
new file mode 100644
index 0000000..a6e8b06
--- /dev/null
+++ b/libc/syscall/syscall.dat.chad
@@ -0,0 +1,55 @@
+exit 1 1 * c exit does stdio, _exit in crt0
+fork 2 0
+read 3 3
+write 4 3
+open 5 3
+close 6 1
+wait 7 0 . THIS one is different
+creat 8 0 . THIS one is different
+link 9 2
+unlink 10 1
+exec 11 3 * minix style exec
+chdir 12 1
+time 13 0 . THIS one is different
+mknod 14 3
+chmod 15 2
+chown 16 3
+brk 17 1 * This is only to tell the system
+stat 18 2
+lseek 19 3 * nb 2nd arg is an io ptr to long not a long.
+getpid 20 1 * this gets both pid & ppid
+mount 21 5
+umount 22 1
+setuid 23 1
+getuid 24 1 * this gets both uid and euid
+stime 25 2 - this must not exist - even as a libc.
+ptrace 26 4
+alarm 27 2
+fstat 28 2
+pause 29 0
+utime 30 2
+access 33 2
+nice 34 1 .
+sleep 35 0 . THIS one is different
+sync 36 0
+kill 37 2
+rename 38 2
+mkdir 39 2
+rmdir 40 1
+dup 41 1 - using nasty fcntl function
+pipe 42 1
+times 43 2 * 2nd arg is pointer for long ret val.
+profil 44 0
+setgid 46 1
+getgid 47 1 * this gets both gid and egid
+signal 48 2 * have put the despatch table in user space.
+getinfo 49 1 - possible? gets pid,ppid,uid,euid etc
+fcntl 50 3
+acct 51 1 -
+phys 52 0 . THIS one is different
+lock 53 0 . THIS one is different
+ioctl 54 3 . make this and fcntl the same ?
+reboot 55 3 . the magic number is 0xfee1,0xdead,...
+mpx 56 0 . THIS one is different
+dup2 57 0 . THIS one is different
+umask 60 1
diff --git a/libc/syscall/syscall.dat.code b/libc/syscall/syscall.dat.code
new file mode 100644
index 0000000..a91ca86
--- /dev/null
+++ b/libc/syscall/syscall.dat.code
@@ -0,0 +1,70 @@
+(
+tr '[A-Z]' '[a-z]' < syscall.dat.rdb
+echo %%%
+cat <<!
+exit 1 0
+fork 2 0
+read 3 0
+write 4 0
+open 5 0
+close 6 0
+wait 7 0
+creat 8 0
+link 9 0
+unlink 10 0
+exec 11 0
+chdir 12 0
+time 13 0
+mknod 14 0
+chmod 15 0
+chown 16 0
+brk 17 0
+stat 18 0
+lseek 19 0
+getpid 20 0
+mount 21 0
+umount 22 0
+setuid 23 0
+getuid 24 0
+stime 25 0
+ptrace 26 0
+alarm 27 0
+fstat 28 0
+pause 29 0
+utime 30 0
+access 33 0
+nice 34 0
+sleep 35 0
+sync 36 0
+kill 37 0
+rename 38 0
+mkdir 39 0
+rmdir 40 0
+dup 41 0
+pipe 42 0
+times 43 0
+profil 44 0
+setgid 46 0
+getgid 47 0
+signal 48 0
+getinfo 49 0
+fcntl 50 0
+acct 51 0
+phys 52 0
+lock 53 0
+ioctl 54 0
+reboot 55 0
+mpx 56 0
+dup2 57 0
+umask 60 0
+!
+) | awk '/%%%/{ flg++; OFS="\t"; next;}
+flg==0 { save4[$1] = $4; save3[$1] = $3;
+ for(i=5; i<=NF; i++) saverest[$1] = saverest[$1] " " $i;
+}
+flg==1 {
+ if( $1 in save3 )
+ print $1, $2, save3[$1]+0, save4[$1] " " saverest[$1] ;
+ else
+ print $1, $2, "0", ". THIS one is different";
+ }'
diff --git a/libc/syscall/syscall.dat.rdb b/libc/syscall/syscall.dat.rdb
new file mode 100644
index 0000000..de5ed9b
--- /dev/null
+++ b/libc/syscall/syscall.dat.rdb
@@ -0,0 +1,142 @@
+#
+# Name No Args Flag, comment
+#
+# . = Ok, with comment
+# * = Needs libc code (Prefix __)
+# - = Obsolete/not required
+#
+# WARNING!
+# This file is used to generate includes for ELKSemu too.
+# This file is continually changing, when you upgrade you _MUST_ ensure
+# that ELKSemu is of a matching build!
+#
+# Calls that use one fd
+READ 3 3
+WRITE 4 3
+CLOSE 6 1
+LSEEK 19 3 * NB 2nd arg is an IO ptr to long not a long.
+FSTAT 28 2
+IOCTL 54 3 . Make this and fcntl the same ?
+FCNTL 55 3
+FTRUNCATE 93 3
+FCHMOD 94 2
+FCHOWN 95 3
+FSYNC 118 1
+FCHDIR 133 1
+LLSEEK 140 3 * 2nd arg is ptr to two longs
+READV 145 3
+WRITEV 146 3
+FLOCK 143 2 - Use fcntl
+DUP 41 1 - Using nasty fcntl function
+
+#
+SETUP 0 X
+EXIT 1 1 * C exit does stdio, _exit in crt0
+FORK 2 0
+OPEN 5 3
+WAIT4 7 4
+VFORK 8 0 . Needed for 8086
+GETINFO 49 1 - Possible? Gets pid,ppid,uid,euid etc
+LINK 9 2
+UNLINK 10 1
+EXEC 11 3 * Minix style exec
+CHDIR 12 1
+GETTIMEOFDAY 13 2 . time() exists only in libc
+MKNOD 14 3
+CHMOD 15 2
+CHOWN 16 3
+BRK 17 1 * This is only to tell the system
+STAT 18 2
+GETPID 20 1 * This gets both pid & ppid
+MOUNT 21 5
+UMOUNT 22 1
+SETUID 23 1
+GETUID 24 1 * This gets both uid and euid
+SETTIMEOFDAY 25 2 . STIME should _NOT_ exist even as a libc.
+STIME 25 2 - This must NOT exist - even as a libc.
+PTRACE 26 4
+ALARM 27 2
+PAUSE 29 0
+UTIME 30 2
+ACCESS 33 2
+NICE 34 1 .
+FTIME 35 1 - Use gettimeofday
+SYNC 36 0
+KILL 37 2
+RENAME 38 2
+MKDIR 39 2
+RMDIR 40 1
+PIPE 42 1
+TIMES 43 2 * 2nd arg is pointer for long ret val.
+SETGID 46 1
+GETGID 47 1 * This gets both gid and egid
+SIGNAL 48 2 * Have put the despatch table in user space.
+ACCT 51 1 -
+SETPGID 57 2
+ULIMIT 58 2
+UMASK 60 1
+CHROOT 61 1
+USTAT 62 2
+GETPGRP 65 0 - use getpgid(0)
+SETSID 66 0
+SIGACTION 67 X
+SGETMASK 68 X
+SSETMASK 69 X
+SETREUID 70 2
+SETREGID 71 2
+SIGSUSPEND 72 X
+SIGPENDING 73 X
+SETHOSTNAME 74 2
+SETRLIMIT 75 2
+GETRLIMIT 76 2
+GETRUSAGE 77 2
+GETGROUPS 80 2
+SETGROUPS 81 2
+SYMLINK 83 2
+LSTAT 84 2
+READLINK 85 3
+SWAPON 87 X
+REBOOT 88 3 . The magic number is 0xfee1,0xdead,...
+MUNMAP 91 X
+TRUNCATE 92 3
+GETPRIORITY 96 2
+SETPRIORITY 97 3
+PROFIL 98 X
+STATFS 99 2
+FSTATFS 100 2
+SOCKETCALL 102 X
+SYSLOG 103 X
+SETITIMER 104 3
+GETITIMER 105 2
+UNAME 109 1
+VHANGUP 111 0
+SWAPOFF 115 X
+SYSINFO 116 X - Use /proc
+IPC 117 5 * This is for all SYSV IPC
+SIGRETURN 119 X
+SETDOMAINNAME 121 X
+ADJTIMEX 124 X
+MPROTECT 125 X
+SIGPROCMASK 126 X
+QUOTACTL 131 X
+GETPGID 132 1
+SYSFS 135 X
+PERSONALITY 136 X
+SETFSUID 138 1
+SETFSGID 139 1
+GETDENTS 141 X
+SELECT 142 5 *
+MSYNC 144 X
+GETSID 147 X
+FDATASYNC 148 X
+SYSCTL 149 X
+MUNLOCK 151 X
+MUNLOCKALL 153 X
+SCHED_SETPARAM 154 X
+SCHED_GETPARAM 155 X
+SCHED_SETSCHEDULER 156 X
+SCHED_GETSCHEDULER 157 X
+SCHED_YIELD 158 X
+SCHED_GET_PRIORITY_MAX 159 X
+SCHED_GET_PRIORITY_MIN 160 X
+SCHED_RR_GET_INTERVAL 161 X
diff --git a/libc/syscall/syslib0.c b/libc/syscall/syslib0.c
new file mode 100644
index 0000000..1a92179
--- /dev/null
+++ b/libc/syscall/syslib0.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/times.h>
+
+/* MSDOS has it's own versions */
+#ifndef __MSDOS__
+#ifdef __AS386_16__
+
+/********************** Function __cstartup *******************************/
+
+#ifdef L___cstartup
+
+void (*__cleanup)() = 0;
+char ** environ;
+
+#asm
+ loc 2
+call_main:
+ .word _main ! Segment 2 is the trailing pointers, main and the
+ .word call_exit ! routine to call exit.
+#if __FIRST_ARG_IN_AX__
+ .data
+saved_arg1:
+ .word 0
+#endif
+ .data
+loop_safe:
+ .word 0
+ .text
+
+export ___cstartup
+___cstartup: ! Crt0 startup
+ pop cx ! Argc
+ mov bx,sp ! Calculate ptrs to argv and envp
+ mov ax,cx
+ inc ax
+ shl ax,#1
+ add ax,bx
+
+export ___mkargv
+___mkargv: ! BCC tells the linker to init argc,argv with this.
+
+ push ax ! Push Envp
+ mov [_environ],ax ! And save
+ push bx ! Push argv
+#if __FIRST_ARG_IN_AX__
+ mov [saved_arg1],cx
+#else
+ push cx ! Push argc
+#endif
+
+ mov bx,#auto_start ! Pointer to first autostart function
+auto_run:
+#if __FIRST_ARG_IN_AX__
+ mov ax,[saved_arg1]
+#endif
+ mov [loop_safe],bx
+ mov bx,[bx]
+ test bx,bx
+ jz no_entry
+ call bx ! Call the function
+no_entry:
+ mov bx,[loop_safe]
+ inc bx ! next
+ inc bx
+ jmp auto_run ! And round for the next.
+
+call_exit: ! Last item called by above.
+ pop bx ! Be tidy.
+#if !__FIRST_ARG_IN_AX__
+ push ax ! At the end the last called was main() push it`s
+#endif
+ call _exit ! return val and call exit();
+bad_exit:
+ jmp bad_exit ! Exit returned !!
+
+export _exit
+export __exit
+_exit: ! exit(rv) function
+#if __FIRST_ARG_IN_AX__
+ mov [saved_arg1],ax
+#else
+ mov bx,sp
+ push [bx+2] ! Copy the `rv` for the exit fuctions.
+#endif
+ mov bx,[___cleanup] ! Call exit, normally this is `__do_exit`
+ test bx,bx
+ je no_clean ! But it`s default is null
+ call bx
+no_clean:
+#if __FIRST_ARG_IN_AX__
+ mov ax,[saved_arg1]
+#else
+ inc sp
+ inc sp
+#endif
+__exit: ! _exit(rv)
+ br ___exit ! This is just an alias for __exit();
+
+#endasm
+
+#endif
+
+/********************** Function lseek ************************************/
+
+#ifdef L_lseek
+off_t lseek(fd, posn, where)
+int fd;
+off_t posn;
+int where;
+{
+ if( __lseek(fd, &posn, where) < 0 ) return -1;
+ else return posn;
+}
+#endif
+
+/********************** Function getpid ************************************/
+
+#ifdef L_getpid
+int getpid()
+{
+ int ppid;
+ return __getpid(&ppid);
+}
+#endif
+
+/********************** Function getppid ************************************/
+
+#ifdef L_getppid
+int getppid()
+{
+ int ppid;
+ __getpid(&ppid);
+ return ppid;
+}
+#endif
+
+/********************** Function getuid ************************************/
+
+#ifdef L_getuid
+int getuid()
+{
+ int euid;
+ return __getuid(&euid);
+}
+#endif
+
+/********************** Function geteuid ************************************/
+
+#ifdef L_geteuid
+int geteuid()
+{
+ int euid;
+ __getuid(&euid);
+ return euid;
+}
+#endif
+
+/********************** Function getgid ************************************/
+
+#ifdef L_getgid
+int getgid()
+{
+ int egid;
+ return __getgid(&egid);
+}
+#endif
+
+/********************** Function getegid ************************************/
+
+#ifdef L_getegid
+int getegid()
+{
+ int egid;
+ __getgid(&egid);
+ return egid;
+}
+#endif
+
+/********************** Function dup2 ************************************/
+
+#ifdef L_dup2
+
+#include <fcntl.h>
+
+int dup2(ifd, ofd)
+int ifd;
+{
+ return fcntl(ifd, F_DUPFD, ofd);
+}
+#endif
+
+/********************** Function dup ************************************/
+
+#ifdef L_dup
+#include <sys/param.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* This is horribly complicated, there _must_ be a better way! */
+
+int
+dup(fd)
+int fd;
+{
+ int nfd;
+ extern int errno;
+ int oerr = errno;
+
+ errno = 0;
+ for(nfd=0; nfd<NR_OPEN; nfd++)
+ {
+ if( fcntl(nfd, F_GETFD) < 0 )
+ break;
+ }
+ if( nfd == NR_OPEN ) { errno = EMFILE ; return -1; }
+ errno = oerr;
+ if( fcntl(fd, F_DUPFD, nfd) < 0 )
+ {
+ if( errno == EINVAL ) errno = EMFILE;
+ return -1;
+ }
+ return nfd;
+}
+#endif
+
+/********************** Function getpgrp ************************************/
+
+#ifdef L_getpgrp
+int
+getpgrp()
+{
+ return getpgid(0);
+}
+#endif
+
+/********************** Function times ************************************/
+
+#ifdef L_times
+clock_t times(buf)
+struct tms* buf;
+{
+ long rv;
+ __times(buf, &rv);
+ return rv;
+}
+#endif
+
+/********************** THE END ********************************************/
+
+#endif /* __AS386_16__ */
+#endif /* __MSDOS__ */
diff --git a/libc/syscall/syslibc.c b/libc/syscall/syslibc.c
new file mode 100644
index 0000000..3486ef6
--- /dev/null
+++ b/libc/syscall/syslibc.c
@@ -0,0 +1,168 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This file is part of the Linux-8086 C library and is distributed
+ * under the GNU Library General Public License.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <time.h>
+
+/* MSDOS has it's own versions */
+#ifndef __MSDOS__
+
+/********************** Function time ************************************/
+
+#ifdef L_time
+time_t time(where)
+time_t *where;
+{
+ struct timeval rv;
+ if( gettimeofday(&rv, (void*)0) < 0 ) return -1;
+ if(where) *where = rv.tv_sec;
+ return rv.tv_sec;
+}
+#endif
+
+/********************** Function abort ************************************/
+
+#ifdef L_abort
+#include <signal.h>
+
+int abort()
+{
+ signal(SIGABRT, SIG_DFL);
+ kill(SIGABRT, getpid()); /* Correct one */
+ pause(); /* System may just schedule */
+ signal(SIGKILL, SIG_DFL);
+ kill(SIGKILL, getpid()); /* Can't trap this! */
+ __exit(255); /* WHAT!! */
+}
+#endif
+
+/********************** Function wait ************************************/
+
+#ifdef L_wait
+int
+wait(status)
+int * status;
+{
+ return wait4(-1, status, 0, (void*)0);
+}
+#endif
+
+/********************** Function wait3 **************************************/
+
+#ifdef L_wait3
+int
+wait3(status, opts, usage)
+int * status;
+int opts;
+struct rusage * usage;
+{
+ return wait4(-1, status, opts, usage);
+}
+#endif
+
+/********************** Function waitpid ************************************/
+
+#ifdef L_waitpid
+int
+waitpid(pid, status, opts)
+int pid;
+int * status;
+int opts;
+{
+ return wait4(pid, status, opts, (void*)0);
+}
+#endif
+
+/********************** Function killpg ************************************/
+
+#ifdef L_killpg
+int
+killpg(pid, sig)
+int pid;
+int sig;
+{
+ if(pid == 0)
+ pid = getpgrp();
+ if(pid > 1)
+ return kill(-pid, sig);
+ errno = EINVAL;
+ return -1;
+}
+#endif
+
+/********************** Function setpgrp ************************************/
+
+#ifdef L_setpgrp
+int
+setpgrp()
+{
+ return setpgid(0,0);
+}
+#endif
+
+/********************** Function sleep ************************************/
+
+#ifdef L_sleep
+#include <signal.h>
+
+/* This uses SIGALRM, it does keep the previous alarm call but will lose
+ * any alarms that go off during the sleep
+ */
+
+static void alrm() { }
+
+unsigned int sleep(seconds)
+unsigned int seconds;
+{
+ void (*last_alarm)();
+ unsigned int prev_sec;
+
+ prev_sec = alarm(0);
+ if( prev_sec <= seconds ) prev_sec = 1; else prev_sec -= seconds;
+
+ last_alarm = signal(SIGALRM, alrm);
+ alarm(seconds);
+ pause();
+ seconds = alarm(prev_sec);
+ signal(SIGALRM, last_alarm);
+ return seconds;
+}
+#if 0
+ /* Is this a better way ? If we have select of course :-) */
+#include <sys/time.h>
+unsigned int
+sleep(seconds)
+unsigned int seconds;
+{
+ struct timeval timeout;
+ time_t start = time((void*)0);
+ timeout.tv_sec = seconds;
+ timeout.tv_usec = 0;
+ select(1, NULL, NULL, NULL, &timeout);
+ return seconds - (time((void*)0) - start);
+}
+#endif
+
+#endif
+
+/********************** Function usleep ************************************/
+
+#ifdef L_usleep
+#include <sys/time.h>
+void
+usleep(useconds)
+unsigned long useconds;
+{
+ struct timeval timeout;
+ timeout.tv_sec = useconds%1000000L;
+ timeout.tv_usec = useconds/1000000L;
+ select(1, NULL, NULL, NULL, &timeout);
+}
+#endif
+
+/********************** THE END ********************************************/
+
+#endif /* __MSDOS__ */
diff --git a/libc/termios/Config b/libc/termios/Config
new file mode 100644
index 0000000..f0c9bde
--- /dev/null
+++ b/libc/termios/Config
@@ -0,0 +1 @@
+termios: Termios functions
diff --git a/libc/termios/Makefile b/libc/termios/Makefile
new file mode 100644
index 0000000..cfc3baa
--- /dev/null
+++ b/libc/termios/Makefile
@@ -0,0 +1,30 @@
+# Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+TSRC=termios.c
+TOBJ=tcsetattr.o tcgetattr.o tcdrain.o tcflow.o tcflush.o tcsendbreak.o \
+ tcsetpgrp.o tcgetpgrp.o isatty.o \
+ cfgetospeed.o cfgetispeed.o cfsetospeed.o cfsetispeed.o cfmakeraw.o
+
+ifeq ($(LIB_OS),ELKS)
+OBJ=$(TOBJ) ttyname.o
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+$(LIBC)($(TOBJ)): $(TSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(AR) $(ARFLAGS) $@ $*.o
+ $(RM) $*.o
+else
+all:
+ @:
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/termios/README b/libc/termios/README
new file mode 100644
index 0000000..c83448d
--- /dev/null
+++ b/libc/termios/README
@@ -0,0 +1,7 @@
+Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+This file is part of the Linux-8086 C library and is distributed
+under the GNU Library General Public License.
+
+There's currently nothing special about termios.
+
+-Robert
diff --git a/libc/termios/termios.c b/libc/termios/termios.c
new file mode 100644
index 0000000..a617e86
--- /dev/null
+++ b/libc/termios/termios.c
@@ -0,0 +1,220 @@
+/* Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk> This
+ * file is part of the Linux-8086 C library and is distributed under the
+ * GNU Library General Public License.
+ */
+
+/* Note: This is based loosely on the Glib termios routines. */
+
+#ifndef __MSDOS__
+
+#include <errno.h>
+#include <stddef.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#ifdef L_isatty
+isatty(fd)
+int fd;
+{
+ struct termios term;
+ int rv, err = errno;
+ rv= (ioctl(fd, TCGETS, &term)==0);
+ if( rv==0 && errno == ENOSYS )
+ rv = (fd<3);
+ errno = err;
+ return rv;
+}
+#endif
+
+#ifdef L_tcgetattr
+int
+tcgetattr(fd, term)
+int fd;
+struct termios *term;
+{
+ return ioctl(fd, TCGETS, term);
+}
+#endif
+
+#ifdef L_tcsetattr
+int
+tcsetattr(fildes, optional_actions, termios_p)
+int fildes;
+int optional_actions;
+struct termios *termios_p;
+{
+ switch (optional_actions)
+ {
+ case TCSANOW:
+ return ioctl(fildes, TCSETS, termios_p);
+ case TCSADRAIN:
+ return ioctl(fildes, TCSETSW, termios_p);
+ case TCSAFLUSH:
+ return ioctl(fildes, TCSETSF, termios_p);
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+#endif
+
+#ifdef L_tcdrain
+/* Wait for pending output to be written on FD. */
+int
+tcdrain(fd)
+int fd;
+{
+ /* With an argument of 1, TCSBRK just waits for output to drain. */
+ return ioctl(fd, TCSBRK, 1);
+}
+#endif
+
+#ifdef L_tcflow
+int
+tcflow(fd, action)
+int fd;
+int action;
+{
+ return ioctl(fd, TCXONC, action);
+}
+#endif
+
+#ifdef L_tcflush
+/* Flush pending data on FD. */
+int
+tcflush(fd, queue_selector)
+int fd;
+int queue_selector;
+{
+ return ioctl(fd, TCFLSH, queue_selector);
+}
+#endif
+
+#ifdef L_tcsendbreak
+/* Send zero bits on FD. */
+int
+tcsendbreak(fd, duration)
+int fd;
+int duration;
+{
+ /*
+ * The break lasts 0.25 to 0.5 seconds if DURATION is zero, and an
+ * implementation-defined period if DURATION is nonzero. We define a
+ * positive DURATION to be number of milliseconds to break.
+ */
+ if (duration <= 0)
+ return ioctl(fd, TCSBRK, 0);
+
+ /*
+ * ioctl can't send a break of any other duration for us. This could be
+ * changed to use trickery (e.g. lower speed and send a '\0') to send
+ * the break, but for now just return an error.
+ */
+ errno = EINVAL;
+ return -1;
+}
+#endif
+
+#ifdef L_tcsetpgrp
+/* Set the foreground process group ID of FD set PGRP_ID. */
+int
+tcsetpgrp(fd, pgrp_id)
+int fd;
+pid_t pgrp_id;
+{
+ return ioctl(fd, TIOCSPGRP, &pgrp_id);
+}
+#endif
+
+#ifdef L_tcgetpgrp
+/* Return the foreground process group ID of FD. */
+pid_t
+tcgetpgrp(fd)
+int fd;
+{
+ int pgrp;
+ if (ioctl(fd, TIOCGPGRP, &pgrp) < 0)
+ return (pid_t) - 1;
+ return (pid_t) pgrp;
+}
+#endif
+
+#ifdef L_cfgetospeed
+speed_t cfgetospeed(tp)
+struct termios *tp;
+{
+ return (tp->c_cflag & CBAUD);
+}
+#endif
+
+#ifdef L_cfgetispeed
+speed_t cfgetispeed(tp)
+struct termios *tp;
+{
+ return (tp->c_cflag & CBAUD);
+}
+#endif
+
+#ifdef L_cfsetospeed
+int cfsetospeed(tp, speed)
+struct termios *tp; speed_t speed;
+{
+#ifdef CBAUDEX
+ if ((speed & ~CBAUD) ||
+ ((speed & CBAUDEX) && (speed < B57600 || speed > B115200)))
+ return 0;
+#else
+ if (speed & ~CBAUD)
+ return 0;
+#endif
+ tp->c_cflag &= ~CBAUD;
+ tp->c_cflag |= speed;
+
+ return 0;
+}
+#endif
+
+#ifdef L_cfsetispeed
+int cfsetispeed(tp, speed)
+struct termios *tp; speed_t speed;
+{
+ return cfsetospeed(tp, speed);
+}
+#endif
+
+/* From linux libc-4.6.27 again */
+#ifdef L_cfmakeraw
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.*/
+
+void
+cfmakeraw(t)
+struct termios *t;
+{
+/* I changed it to the current form according to the suggestions
+ * from Bruce Evans. Thanks Bruce. Please report the problems to
+ * H.J. Lu (hlu@eecs.wsu.edu).
+ */
+
+/*
+ * I took out the bits commented out by #if 1...#else - RHP
+ */
+
+ /* VMIN = 0 means non-blocking for Linux */
+ t->c_cc[VMIN] = 1; t->c_cc[VTIME] = 1;
+ /* clear some bits with &= ~(bits), set others with |= */
+ t->c_cflag &= ~(CSIZE|PARENB|CSTOPB);
+ t->c_cflag |= (CS8|HUPCL|CREAD);
+ t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INPCK|ISTRIP);
+ t->c_iflag &= ~(INLCR|IGNCR|ICRNL|IXON|IXOFF);
+ t->c_iflag |= (BRKINT|IGNPAR);
+ t->c_oflag &= ~(OPOST|OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL);
+ t->c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
+ t->c_oflag |= (ONLCR|NL0|CR0|TAB3|BS0|VT0|FF0);
+ t->c_lflag &= ~(ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK|ECHONL);
+ t->c_lflag &= ~(NOFLSH|XCASE);
+ t->c_lflag &= ~(ECHOPRT|ECHOCTL|ECHOKE);
+}
+#endif
+
+#endif
diff --git a/libc/termios/ttyname.c b/libc/termios/ttyname.c
new file mode 100644
index 0000000..d777ab3
--- /dev/null
+++ b/libc/termios/ttyname.c
@@ -0,0 +1,45 @@
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+char *
+ttyname(fd)
+int fd;
+{
+ static char dev[] = "/dev";
+ struct stat st, dst;
+ DIR *fp;
+ struct dirent *d;
+ static char name[MAXNAMLEN];
+ int noerr = errno;
+
+ if (fstat(fd, &st) < 0)
+ return 0;
+ if (!isatty(fd))
+ {
+ errno = ENOTTY;
+ return 0;
+ }
+
+ fp = opendir(dev);
+ if (fp == 0)
+ return 0;
+ strcpy(name, dev);
+ strcat(name, "/");
+
+ while ((d = readdir(fp)) != 0)
+ {
+ strcpy(name + sizeof(dev), d->d_name);
+ if (stat(name, &dst) == 0
+ && st.st_dev == dst.st_dev && st.st_ino == dst.st_ino)
+ {
+ closedir(fp);
+ errno = noerr;
+ return name;
+ }
+ }
+ closedir(fp);
+ errno = noerr;
+ return 0;
+}
diff --git a/libc/time/Config b/libc/time/Config
new file mode 100644
index 0000000..053ab81
--- /dev/null
+++ b/libc/time/Config
@@ -0,0 +1 @@
+time: Unix time manipulation functions.
diff --git a/libc/time/Makefile b/libc/time/Makefile
new file mode 100644
index 0000000..6e95444
--- /dev/null
+++ b/libc/time/Makefile
@@ -0,0 +1,15 @@
+# Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+# This file is part of the Linux-8086 C library and is distributed
+# under the GNU Library General Public License.
+
+OBJ=localtime.o gmtime.o asctime.o ctime.o asc_conv.o tm_conv.o
+
+CFLAGS=$(ARCH) $(CCFLAGS) $(DEFS)
+
+all: $(LIBC)
+ @:
+
+$(LIBC): $(LIBC)($(OBJ))
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/time/README b/libc/time/README
new file mode 100644
index 0000000..da4f4e6
--- /dev/null
+++ b/libc/time/README
@@ -0,0 +1,8 @@
+Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk>
+This file is part of the Linux-8086 C library and is distributed
+under the GNU Library General Public License.
+
+There are two ways of converting the time_t to a struct tm, I'm not
+quite sure which is better.
+
+-Robert
diff --git a/libc/time/asc_conv.c b/libc/time/asc_conv.c
new file mode 100644
index 0000000..78cbcdd
--- /dev/null
+++ b/libc/time/asc_conv.c
@@ -0,0 +1,49 @@
+
+#include <time.h>
+#include <string.h>
+/*
+ * Internal ascii conversion routine, avoid use of printf, it's a bit big!
+ */
+
+
+static void
+hit(buf, val)
+char * buf;
+int val;
+{
+ *buf = '0' + val%10;
+}
+
+void
+__asctime(buffer, ptm)
+register char * buffer;
+struct tm * ptm;
+{
+static char days[] = "SunMonTueWedThuFriSat";
+static char mons[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+ int year;
+
+ /* 012345678901234567890123456 */
+ strcpy(buffer, "Err Err .. ..:..:.. ....\n");
+ if( (ptm->tm_wday >= 0) && (ptm->tm_wday <= 6) )
+ memcpy(buffer, days+3*(ptm->tm_wday), 3);
+
+ if( (ptm->tm_mon >= 0) && (ptm->tm_mon <= 11) )
+ memcpy(buffer+4, mons+3*(ptm->tm_mon), 3);
+
+
+ hit(buffer+ 8, ptm->tm_mday/10);
+ hit(buffer+ 9, ptm->tm_mday );
+ hit(buffer+11, ptm->tm_hour/10);
+ hit(buffer+12, ptm->tm_hour );
+ hit(buffer+14, ptm->tm_min/10);
+ hit(buffer+15, ptm->tm_min );
+ hit(buffer+17, ptm->tm_sec/10);
+ hit(buffer+18, ptm->tm_sec );
+
+ year = ptm->tm_year + 1900;
+ hit(buffer+20, year/1000);
+ hit(buffer+21, year/100);
+ hit(buffer+22, year/10);
+ hit(buffer+23, year);
+}
diff --git a/libc/time/asctime.c b/libc/time/asctime.c
new file mode 100644
index 0000000..ea13bf8
--- /dev/null
+++ b/libc/time/asctime.c
@@ -0,0 +1,15 @@
+
+#include <time.h>
+
+extern void __asctime();
+
+char *
+asctime(timeptr)
+__const struct tm * timeptr;
+{
+static char timebuf[26];
+
+ if( timeptr == 0 ) return 0;
+ __asctime(timebuf, timeptr);
+ return timebuf;
+}
diff --git a/libc/time/ctime.c b/libc/time/ctime.c
new file mode 100644
index 0000000..2f42cd3
--- /dev/null
+++ b/libc/time/ctime.c
@@ -0,0 +1,26 @@
+
+#include <time.h>
+
+extern void __tm_conv();
+extern void __asctime();
+
+char *
+ctime(timep)
+__const time_t * timep;
+{
+ static char cbuf[26];
+ struct tm tmb;
+ struct timezone tz;
+ time_t offt;
+
+ gettimeofday((void*)0, &tz);
+
+ offt = -tz.tz_minuteswest*60L;
+
+ /* tmb.tm_isdst = ? */
+ __tm_conv(&tmb, timep, offt);
+
+ __asctime(cbuf, &tmb);
+
+ return cbuf;
+}
diff --git a/libc/time/gmtime.c b/libc/time/gmtime.c
new file mode 100644
index 0000000..aa0a246
--- /dev/null
+++ b/libc/time/gmtime.c
@@ -0,0 +1,15 @@
+
+#include <time.h>
+
+extern void __tm_conv();
+
+struct tm *
+gmtime(timep)
+__const time_t * timep;
+{
+ static struct tm tmb;
+
+ __tm_conv(&tmb, timep, 0L);
+
+ return &tmb;
+}
diff --git a/libc/time/localtime.c b/libc/time/localtime.c
new file mode 100644
index 0000000..9d9b46d
--- /dev/null
+++ b/libc/time/localtime.c
@@ -0,0 +1,22 @@
+
+#include <time.h>
+
+extern void __tm_conv();
+
+struct tm *
+localtime(timep)
+__const time_t * timep;
+{
+ static struct tm tmb;
+ struct timezone tz;
+ time_t offt;
+
+ gettimeofday((void*)0, &tz);
+
+ offt = -tz.tz_minuteswest*60L;
+
+ /* tmb.tm_isdst = ? */
+ __tm_conv(&tmb, timep, offt);
+
+ return &tmb;
+}
diff --git a/libc/time/tm_conv.c b/libc/time/tm_conv.c
new file mode 100644
index 0000000..ffd524c
--- /dev/null
+++ b/libc/time/tm_conv.c
@@ -0,0 +1,138 @@
+
+#if 0
+#include <time.h>
+
+/* This is a translation from ALGOL in Collected Algorithms of CACM. */
+/* Copied from Algorithm 199, Author: Robert G. Tantzen */
+
+void
+__tm_conv(tmbuf, timep, offset)
+struct tm *tmbuf;
+time_t *timep;
+time_t offset;
+{
+static int moffset[] =
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+ long s;
+ long j, d, m, y;
+
+ offset += *timep;
+
+ tmbuf->tm_isdst = 0; /* Someone else can set this */
+
+ j = offset / 86400L + 719469;
+ s = offset % 86400L;
+
+ if( s < 0 ) { s += 86400L; j--; }
+
+ tmbuf->tm_sec = s % 60;
+ tmbuf->tm_min = (s / 60) % 60;
+ tmbuf->tm_hour = s / 3600;
+
+ tmbuf->tm_wday = (j+2) % 7;
+
+ /*
+ * Julian date converter. Takes a julian date (the number of days since
+ * some distant epoch or other), and fills tmbuf.
+ */
+
+ y = (4L * j - 1L) / 146097L;
+ j = 4L * j - 1L - 146097L * y;
+ d = j / 4L;
+ j = (4L * d + 3L) / 1461L;
+ d = 4L * d + 3L - 1461L * j;
+ d = (d + 4L) / 4L;
+ m = (5L * d - 3L) / 153L;
+ d = 5L * d - 3 - 153L * m;
+ d = (d + 5L) / 5L;
+ y = 100L * y + j;
+ if (m < 10)
+ m += 2;
+ else
+ {
+ m -= 10;
+ ++y;
+ }
+
+ tmbuf->tm_year = y - 1900;
+ tmbuf->tm_mon = m;
+ tmbuf->tm_mday = d;
+
+ tmbuf->tm_yday = d + moffset[m];
+ if (m > 1 && ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0)))
+ tmbuf->tm_yday++;
+}
+
+#else
+
+/* This is adapted from glibc */
+/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */
+
+#define SECS_PER_HOUR 3600L
+#define SECS_PER_DAY 86400L
+
+#include <time.h>
+
+static const unsigned short int __mon_lengths[2][12] =
+ {
+ /* Normal years. */
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ /* Leap years. */
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ };
+
+
+void
+__tm_conv(tmbuf, t, offset)
+struct tm *tmbuf;
+time_t *t;
+time_t offset;
+{
+ long days, rem;
+ register int y;
+ register unsigned short int *ip;
+
+ days = *t / SECS_PER_DAY;
+ rem = *t % SECS_PER_DAY;
+ rem += offset;
+ while (rem < 0)
+ {
+ rem += SECS_PER_DAY;
+ --days;
+ }
+ while (rem >= SECS_PER_DAY)
+ {
+ rem -= SECS_PER_DAY;
+ ++days;
+ }
+ tmbuf->tm_hour = rem / SECS_PER_HOUR;
+ rem %= SECS_PER_HOUR;
+ tmbuf->tm_min = rem / 60;
+ tmbuf->tm_sec = rem % 60;
+ /* January 1, 1970 was a Thursday. */
+ tmbuf->tm_wday = (4 + days) % 7;
+ if (tmbuf->tm_wday < 0)
+ tmbuf->tm_wday += 7;
+ y = 1970;
+ while (days >= (rem = __isleap(y) ? 366 : 365))
+ {
+ ++y;
+ days -= rem;
+ }
+ while (days < 0)
+ {
+ --y;
+ days += __isleap(y) ? 366 : 365;
+ }
+ tmbuf->tm_year = y - 1900;
+ tmbuf->tm_yday = days;
+ ip = __mon_lengths[__isleap(y)];
+ for (y = 0; days >= ip[y]; ++y)
+ days -= ip[y];
+ tmbuf->tm_mon = y;
+ tmbuf->tm_mday = days + 1;
+ tmbuf->tm_isdst = -1;
+}
+
+#endif