summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorRobert de Bath <rdebath@poboxes.com>1996-03-24 21:25:23 +0100
committerLubomir Rintel <lkundrak@v3.sk>2013-10-23 23:29:54 +0200
commitdcc973ea3e31710429858c99d4f040334ac67c06 (patch)
tree8883b902eb18eba489957b7f03caa491fd7992a7 /libc
parentfe22c37817ce338fbbc90b239320248c270957fa (diff)
downloaddev86-dcc973ea3e31710429858c99d4f040334ac67c06.tar.gz
Import Dev86-0.0.5.tar.gzv0.0.5
Diffstat (limited to 'libc')
-rw-r--r--libc/COPYING481
-rw-r--r--libc/Changes130
-rw-r--r--libc/Config_sh141
-rw-r--r--libc/Contributors8
-rw-r--r--libc/KERNEL37
-rw-r--r--libc/MAGIC23
-rw-r--r--libc/Make.defs68
-rw-r--r--libc/Makefile74
-rwxr-xr-xlibc/New_subdir67
-rw-r--r--libc/Pre_main55
-rw-r--r--libc/README74
-rw-r--r--libc/TODO55
-rw-r--r--libc/bcc/Config2
-rw-r--r--libc/bcc/Makefile58
-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_int.c162
-rw-r--r--libc/bcc/bcc_io.c189
-rw-r--r--libc/bcc/bcc_long.c479
-rw-r--r--libc/bcc/heap.c116
-rw-r--r--libc/crt0.c57
-rw-r--r--libc/crt0.obin0 -> 125 bytes
-rw-r--r--libc/error/Config2
-rw-r--r--libc/error/Makefile17
-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.c75
-rw-r--r--libc/error/sys_siglist.c38
-rw-r--r--libc/grp/Config1
-rw-r--r--libc/grp/Makefile41
-rw-r--r--libc/grp/__getgrent.c168
-rw-r--r--libc/grp/config-grp.h65
-rw-r--r--libc/grp/config.h65
-rw-r--r--libc/grp/fgetgrent.c35
-rw-r--r--libc/grp/getgrgid.c48
-rw-r--r--libc/grp/getgrnam.c51
-rw-r--r--libc/grp/grent.c57
-rw-r--r--libc/grp/initgroups.c80
-rw-r--r--libc/grp/test_grp.c107
-rw-r--r--libc/gtermcap/COPYING339
-rw-r--r--libc/gtermcap/ChangeLog52
-rw-r--r--libc/gtermcap/Makefile21
-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/include/a.out.h115
-rw-r--r--libc/include/ar.h18
-rw-r--r--libc/include/assert.h23
-rw-r--r--libc/include/ctype.h37
-rw-r--r--libc/include/dirent.h52
-rw-r--r--libc/include/dos.h34
-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.h33
-rw-r--r--libc/include/malloc.h30
-rw-r--r--libc/include/memory.h1
-rw-r--r--libc/include/paths.h20
-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.h26
-rw-r--r--libc/include/sgtty.h1
-rw-r--r--libc/include/signal.h85
-rw-r--r--libc/include/stdarg.h38
-rw-r--r--libc/include/stddef.h26
-rw-r--r--libc/include/stdio.h125
-rw-r--r--libc/include/stdlib.h30
-rw-r--r--libc/include/string.h53
-rw-r--r--libc/include/strings.h1
-rw-r--r--libc/include/sys/cdefs.h33
-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/param.h18
-rw-r--r--libc/include/sys/signal.h1
-rw-r--r--libc/include/sys/stat.h27
-rw-r--r--libc/include/sys/types.h2
-rw-r--r--libc/include/sys/utsname.h18
-rw-r--r--libc/include/sys/wait.h2
-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.h61
-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/Makefile18
-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.h55
-rw-r--r--libc/kinclude/linuxmt/termios.h258
-rw-r--r--libc/kinclude/linuxmt/types.h32
-rw-r--r--libc/libc.abin0 -> 74344 bytes
-rw-r--r--libc/malloc1/Config1
-rw-r--r--libc/malloc1/Makefile24
-rw-r--r--libc/malloc1/README9
-rw-r--r--libc/malloc1/malloc.c540
-rw-r--r--libc/malloc1/malloc.h30
-rw-r--r--libc/malloc2/Config1
-rw-r--r--libc/malloc2/Makefile23
-rw-r--r--libc/malloc2/README19
-rw-r--r--libc/malloc2/malloc.c127
-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/Makefile52
-rw-r--r--libc/misc/aliases.c109
-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.c344
-rw-r--r--libc/misc/crypt.c50
-rw-r--r--libc/misc/ctype.c68
-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/strtod.c96
-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/Makefile36
-rw-r--r--libc/msdos/Notes8
-rw-r--r--libc/msdos/i86.c163
-rw-r--r--libc/msdos/msdos.c540
-rw-r--r--libc/pwd/Config1
-rw-r--r--libc/pwd/Makefile40
-rw-r--r--libc/pwd/__getpwent.c99
-rw-r--r--libc/pwd/fgetpwent.c35
-rw-r--r--libc/pwd/getpw.c51
-rw-r--r--libc/pwd/getpwnam.c52
-rw-r--r--libc/pwd/getpwuid.c44
-rw-r--r--libc/pwd/putpwent.c39
-rw-r--r--libc/pwd/pwent.c62
-rw-r--r--libc/pwd/test_pwd.c91
-rw-r--r--libc/regexp/Config1
-rw-r--r--libc/regexp/Makefile28
-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/stdio1/BUGS15
-rw-r--r--libc/stdio1/Config3
-rw-r--r--libc/stdio1/Makefile36
-rw-r--r--libc/stdio1/NOTICE17
-rw-r--r--libc/stdio1/README13
-rw-r--r--libc/stdio1/TODO33
-rw-r--r--libc/stdio1/__ffillbuf.c55
-rw-r--r--libc/stdio1/__stdio_init.c66
-rw-r--r--libc/stdio1/fclose.c41
-rw-r--r--libc/stdio1/fcntl.h72
-rw-r--r--libc/stdio1/fflush.c36
-rw-r--r--libc/stdio1/fgetc.c39
-rw-r--r--libc/stdio1/fgets.c50
-rw-r--r--libc/stdio1/fopen.c80
-rw-r--r--libc/stdio1/fputc.c53
-rw-r--r--libc/stdio1/fputs.c32
-rw-r--r--libc/stdio1/idealgetline.c67
-rw-r--r--libc/stdio1/old_printf.c230
-rw-r--r--libc/stdio1/printf.c649
-rw-r--r--libc/stdio1/puts.c26
-rw-r--r--libc/stdio1/scanf.c151
-rw-r--r--libc/stdio1/stdio.h135
-rwxr-xr-xlibc/stdio1/test.sh12
-rw-r--r--libc/stdio2/Config4
-rw-r--r--libc/stdio2/Makefile39
-rw-r--r--libc/stdio2/printf.c362
-rw-r--r--libc/stdio2/scanf.c511
-rw-r--r--libc/stdio2/stdio.c739
-rw-r--r--libc/stdio2/stdio.h125
-rw-r--r--libc/string/Config1
-rw-r--r--libc/string/Makefile31
-rw-r--r--libc/string/strcasecmp.c26
-rw-r--r--libc/string/strcspn.c32
-rw-r--r--libc/string/string.c667
-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/Makefile44
-rw-r--r--libc/syscall/TODO7
-rw-r--r--libc/syscall/dirent.c84
-rw-r--r--libc/syscall/execve.c114
-rw-r--r--libc/syscall/getinfo.c32
-rw-r--r--libc/syscall/mksyscall300
-rw-r--r--libc/syscall/setjmp.c50
-rw-r--r--libc/syscall/signal.c94
-rw-r--r--libc/syscall/syscall.dat147
-rw-r--r--libc/syscall/syslibc.c330
-rw-r--r--libc/termios/Config1
-rw-r--r--libc/termios/Makefile30
-rw-r--r--libc/termios/README7
-rw-r--r--libc/termios/termios.c185
-rw-r--r--libc/termios/ttyname.c45
-rw-r--r--libc/tests/Config2
-rw-r--r--libc/tests/Makefile20
-rw-r--r--libc/tests/README19
-rw-r--r--libc/tests/Real_make19
-rw-r--r--libc/tests/compr.c383
-rw-r--r--libc/tests/env.c82
-rw-r--r--libc/tests/ft.c1217
-rwxr-xr-xlibc/tests/grab.c80
-rw-r--r--libc/tests/hd.c90
-rw-r--r--libc/tests/line2.c15
-rw-r--r--libc/tests/lines.c36
-rwxr-xr-xlibc/tests/ls.c1049
-rw-r--r--libc/tests/ouch.c27
-rw-r--r--libc/tests/rand.c16
-rw-r--r--libc/tests/size.c51
-rw-r--r--libc/tests/sync.c1
-rw-r--r--libc/tests/ucomp.c108
-rw-r--r--libc/tests/wc.c133
-rw-r--r--libc/utmp/Makefile24
-rw-r--r--libc/utmp/utent.c152
255 files changed, 23672 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/Changes b/libc/Changes
new file mode 100644
index 0000000..3066545
--- /dev/null
+++ b/libc/Changes
@@ -0,0 +1,130 @@
+# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+# This file is part of the Linux-8086 C library which is distributed
+# under the GNU Library General Public License.
+
+If you make any changes please put a little note here. -RDB
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+----- Mar 21 '96 - RDB
+Add -Md -Mf flags to bcc.c
+corrected oops on ../Makefile
+Changes to READMEs
+----- Mar 18 '96 - RDB
+Re-written to wetware storage "Robert must remember to fill in changes!"
+Ok, there's now some makefiles in the directory above for creating an
+environment with cleanup of bcc/as/ld makefiles and new home for bcc files.
+My version of a standard I/O package has been added, I've split the
+output libs for Linux-86 and MSDOS.
+A couple of functions (including reboot) added to elksemu.
+----- Mar 3 '96 - RDB
+open/close in doselks
+----- Feb 25 '96 - RDB
+iota.c - oops -ve numbers give infinite loop
+altered a.out.h changed size of n_name from 8 to 24, ld needs recompile,
+dis88 bombed (bad malloc), nm etc will need to know.
+added popen, pclose, system
+----- Feb 24 '96 - RDB
+Problem with __lseek syscall, was trying to return a long - no way jose
+Little change to malloc1/* if you #define __MINI_MALLOC__ (used in LIB)
+a _much_ smaller but more limited version of malloc is used.
+Added assert.h - no __assert() in lib yet.
+Added in printf c/o Steven Huang <sthuang@hns.com>.
+ELKSemu; added -Wall, cleaned up mess.
+----- Feb 23 '96 - RDB
+Release 0.0.3, bump version to 0.0.4
+----- Feb 18 '96 - RDB
+ELKSemu signals now seem to be working.
+ELKSemu; Added symlinks
+ELKSemu; Added opendir support
+ELKSemu; now runs as ELF executable
+Added exec* functions except exec*p ones
+Small cleanup of doselks.
+Start final checks for 0.0.3
+----- Feb 16 '96 - RDB
+I do _NOT_ believe this - sbrk() yet again!! RIGHT! This time it WILL work!!
+Groan! There was no problem with sbrk, it was elksemu :-( fixed!
+----- Feb 12 '96 - RDB
+Yet another problem with sbrk() return val wrong! - FIXed
+Alter elksemu change in way *_tab.v files work.
+----- Feb 11 '96 - RDB
+Fix on strchr (asm86) - SI not saved
+First cut at opendir/readdir/closedir
+Move in ar.h
+add in 'make config' - (split malloc's and options for stdio packages)
+Merge in Nat's grp and other pieces.
+ELKSemu; Little i386 kernel patch, i8086 programs now run transparently :-)
+----- Feb 10 '96 - RDB
+Found a _nasty_ bug with atexit; the actual problem was in cstartup but ...
+----- Feb 4 '96 - RDB
+Corrected minor problem in atexit/on_exit
+----- Jan 28 '96 - RDB
+Debug, execve in libc _and_ elksemu
+perror added
+----- Jan 27 '96 - RDB
+Debug pwd, pw_fd was static
+Started modifing syscall.dat, adjusting elksemu to match.
+----- Jan 21 '96 - RDB
+Altered fflush to test return status. Corrected porting bug in printf.c
+----- Jan 20 '96 - RDB
+Imported printf from the 'DLibs' library, I've now found the rest of the
+Dlibs stdio, it appears to be very ST specific tho :-(
+NB: This is not in the dist, still sending out Joel's
+----- Jan 19 '96 - RDB
+Making some test alterations to stdio.
+Made ungetc into function, removed ungetc specific structure items
+Altered putc() to micro-macro.
+----- Jan 16 '96 - RDB
+Added in patches from Nat, corrected minor oops in misc/alias.c
+----- Jan 11 '96 - RDB
+Final checks, release version 0.0.2
+----- Jan 9 '96 - RDB
+Added 'signal' function.
+Added 'setjmp' Is it right for SI & DI to be saved ?
+----- Jan 8 '96 - RDB
+Added various MS-DOS functions, COM files are now starting to be able to
+do something useful.
+----- Jan 7 '96 - RDB
+Added the 'New_subdir' script.
+Now YOU (Yes I mean you reading this!) can use it :-)
+----- Jan 6 '96 - RDB
+Problem with sbrk() shown up by Joel's malloc, the error checks failed if
+you were allocating big blocks, fixed.
+----- Jan 6 '96 - RDB
+Added in Joel's malloc routine after a solid hack to actually debug it
+it seems to work now but I haven't really tested it; I can't do it under
+x386 Linux as something tried to link in 'realloc' too.
+----- Jan 5 '96 - RDB
+Ok, I've messed around and joined in Joel's stdio.h routines
+----- Jan 3 '96 - RDB
+(This is a good idea, dates, Always overlook the little things, ho hum!)
+----- - RDB
+Added 'movedata' function like MSC version to string/string.h
+----- - RDB
+Added support for the -C-f and -C-c options of BCC. BUT note for the moment
+the string functions degenerate to the C versions for -C-f
+----- - RDB
+Added getenv/putenv
+----- - RDB
+Changed crt0.c. It now only jmps to ___cstartup. This is so the same crt0
+can be used for both DOS and Linux, only the libc needs to be changed.
+Cost is 4 bytes at the start of the exe.
+----- - RDB
+Added support for automatic calling of functions before main. (See Pre_main)
+Added support for atexit() and onexit() functions.
+----- - RDB
+Added fast strchr
+Altered strstr to use strchr.
+----- - RDB
+Added cputype function - CPU detector.
+----- - RDB
+Dec 12 95
+Just completed a working debugged malloc set _including_ a 'fake' alloca
+function. (The assembler version will not work for BCC) It's a classical
+algorthm so may be slow in some cases. I had a look at the GNU malloc ...
+erm ... I _think_ I see what they're doing! :-)
+----- - RDB
+Added tiny printf, to be replaced by Joel.
+Added HP-UX long->ascii function.
+----- - RDB
+Split off brk/sbrk etc into own file. Asm alloca not compiled.
diff --git a/libc/Config_sh b/libc/Config_sh
new file mode 100644
index 0000000..e27acaa
--- /dev/null
+++ b/libc/Config_sh
@@ -0,0 +1,141 @@
+#!/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
+ 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 ]
+ then echo '
+ You should now run a "make realclean" 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/Contributors b/libc/Contributors
new file mode 100644
index 0000000..27a3145
--- /dev/null
+++ b/libc/Contributors
@@ -0,0 +1,8 @@
+Alan Cox <alan@cymru.net>
+Bruce Evans <bde@FreeBSD.org>
+Chad Page <page0588@sundance.sjsu.edu>
+Dale Schumacher <dal@syntel.UUCP>
+Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+Nat Friedman <ndf@aleph1.mit.edu>
+Robert de Bath <robert@mayday.compulink.co.uk>
+Steven Huang <sthuang@hns.com>
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/MAGIC b/libc/MAGIC
new file mode 100644
index 0000000..69c9c2d
--- /dev/null
+++ b/libc/MAGIC
@@ -0,0 +1,23 @@
+Useful bits for /etc/magic:
+
+#------------------------------------------------------------------------------
+# Localstuff: file(1) magic for locally observed files
+#
+# $Id: Localstuff,v 1.3 1995/01/21 21:09:00 christos Exp $
+# Add any locally observed files here. Remember:
+# text if readable, executable if runnable binary, data if unreadable.
+#
+0 string \01\03\020\04 Linux-8086 impure executable
+>16 long !0 not stripped
+0 string \01\03\040\04 Linux-8086 executable
+>16 long !0 not stripped
+#
+0 string \243\206\001\0 Linux-8086 object file
+# There is _no_ difference between 16 and 32 bit .o files
+#
+0 string \01\03\020\20 Minix-386 impure executable
+>16 long !0 not stripped
+0 string \01\03\040\20 Minix-386 executable
+>16 long !0 not stripped
+#
+#------------------------------------------------------------------------------
diff --git a/libc/Make.defs b/libc/Make.defs
new file mode 100644
index 0000000..3cee160
--- /dev/null
+++ b/libc/Make.defs
@@ -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.
+
+# Set PLATFORM to i386-Linux to build for Linux/386 and to i86-ELKS to
+# build for ELKS. This doesn't quite work yet, though, because of some of
+# the platform and/or compiler-specific code flying around here.
+# Eventually, compiler-specificity won't be an issue, and we can put
+# platform-specific code in i86/ and i386/. -Nat
+
+# Define enviroment var for others.
+ifeq ($(PLATFORM),)
+PLATFORM=i86-ELKS
+#PLATFORM=i86-FAST
+#PLATFORM=i86-DOS
+#PLATFORM=i386-Linux
+endif
+
+VERMAJOR=0
+VERMINOR=0
+VERPATCH=5
+VER=$(VERMAJOR).$(VERMINOR).$(VERPATCH)
+
+LIBDEFS=-D__LIBC__
+LIBC=libc.a
+
+ifneq ($(PLATFORM),i386-Linux)
+
+# Normal standard 8086 code
+ifeq ($(PLATFORM),i86-ELKS)
+ARCH=-0
+endif
+
+# 8086 elks code With "Caller saves" and "First arg in AX"
+ifeq ($(PLATFORM),i86-FAST)
+ARCH=-0 -Mf
+LIBC=libc_f.a
+endif
+
+# MSDOS COM file (msdos libs don't support "First arg in AX")
+ifeq ($(PLATFORM),i86-DOS)
+ARCH=-0 -Md
+LIBC=libdos.a
+endif
+
+# BCC 386.
+ifeq ($(PLATFORM),i386-BCC)
+ARCH=-3
+endif
+
+CC=bcc $(ARCH)
+CCFLAGS=-O -I -I$(TOP)/include
+LKFLAGS=-L -L$(TOP)/ -s
+
+else # ifeq ($(PLATFORM),i386-Linux)
+
+CC=gcc $(ARCH)
+# ARCH=-b i486-linuxaout
+LKFLAGS=-static -N
+CCFLAGS=-O6 -fomit-frame-pointer -I- -I$(TOP)/include -I. -fno-builtin
+WALL= -ansi -pedantic -Wwrite-strings -Wpointer-arith -Wcast-qual \
+ -Wcast-align -Wtraditional -Wstrict-prototypes -Wmissing-prototypes \
+ -Wnested-externs -Winline -Wshadow
+
+endif # ifeq ($(PLATFORM),i386-Linux)
+
+CFLAGS=$(CCFLAGS) $(LIBDEFS)
+LDFLAGS=$(LKFLAGS)
diff --git a/libc/Makefile b/libc/Makefile
new file mode 100644
index 0000000..41fd68d
--- /dev/null
+++ b/libc/Makefile
@@ -0,0 +1,74 @@
+# 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.
+
+TOP=.
+include $(TOP)/Make.defs
+
+SRC=crt0.c
+OBJ=crt0.o
+
+TARGETS=$(OBJ) $(LIBC)
+TXT=Makefile Make.defs README TODO KERNEL COPYING Changes Contributors MAGIC \
+ New_subdir Pre_main Config_sh
+
+all: .config.lst $(TARGETS)
+
+install: all
+ install -d $(BCCHOME)
+ rm -rf $(BCCHOME)/include
+ ln -s $(TOPDIR)/libc/include $(BCCHOME)/include
+ install -d $(LIBDIR)/i86
+ install -m 644 crt0.o $(LIBDIR)/i86
+ install -m 644 $(LIBC) $(LIBDIR)/i86
+ -install -m 644 error/liberror.txt /usr/lib
+
+tests: dummy
+ make -C tests
+
+dummy:
+
+$(LIBC): .config.dir transfer
+ @for i in `cat .config.dir` ; do \
+ echo make -C $$i libc.a ; make -C $$i libc.a || exit 1 ; \
+ done
+
+realclean: dummy
+ rm -f $(OBJ) $(LIBC) .config.dir
+ @for i in */Makefile ; do \
+ grep -q '^clean:' $$i && make -C `dirname $$i` clean ; \
+ done ; echo -n
+
+clean: .config.dir
+ @for i in */Makefile ; do \
+ make -C `dirname $$i` $@ || exit 1 ; \
+ done
+
+.config.lst: Makefile Make.defs Config_sh
+ sh Config_sh
+
+config:
+ sh Config_sh
+
+.config.dir: .config.lst
+ @grep '^[^:]*:+:' < .config.lst | sed 's/:.*//' > .config.dir
+
+dist: clean
+ -rm -f include/linuxmt
+ tar cf temp.tar \
+ $(TXT) $(TARGETS) $(SRC) include \
+ `for i in */Makefile */Config; do dirname $$i; done | sort -u`
+ rm -rf libc-$(VER)
+ mkdir libc-$(VER) ; cd libc-$(VER) ; tar xf ../temp.tar
+ tar czf libc-8086-$(VER).tar.gz libc-$(VER)
+ rm -rf libc-$(VER) temp.tar
+
+dist_ver: dist
+ mv libc-8086-$(VER).tar.gz ..
+ echo $(VER) > ../Libc_version
+
+transfer: dummy
+ @echo Checking for transfers
+ @for i in `cat .config.dir`; do \
+ grep -q '^transfer' $$i/Makefile && make -C $$i $@ ; \
+ done ; echo -n
diff --git a/libc/New_subdir b/libc/New_subdir
new file mode 100755
index 0000000..92f523d
--- /dev/null
+++ b/libc/New_subdir
@@ -0,0 +1,67 @@
+#!/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.
+
+TOP=..
+include \$(TOP)/Make.defs
+
+OBJ=$1.o
+
+all: \$(OBJ)
+
+libc.a: \$(OBJ)
+ ar r ../$(LIBC) \$(OBJ)
+ @touch libc.a
+
+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..e3793f1
--- /dev/null
+++ b/libc/Pre_main
@@ -0,0 +1,55 @@
+
+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 specific; the method
+is similar to this:
+
+/**********************/
+int global_var_that_needs_init;
+
+#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
+
+static void init_vars()
+{
+ global_var_that_needs_init = getuid();
+}
+/**********************/
+
+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 tht 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..2b4bbdc
--- /dev/null
+++ b/libc/README
@@ -0,0 +1,74 @@
+
+This is the README for libc-8086-0.0.4.tar.gz
+Robert de Bath, 21/Mar/96, rdebath@cix.compulink.co.uk
+
+The lib is now positivly plump, there's a new standard IO package, passwd,
+group, utmp, crypt and lots of other pieces.
+
+The lib can be compiled five different ways for Linux-8086 standard,
+Linux-8086 with 'First arg in AX', MS-DOS, BCC-386 or for GNU-386. At
+the moment the 386 versions are missing some _very_ important bits.
+This can be done by running.
+ make PLATFORM=i86-FAST clean all
+ make PLATFORM=i86-DOS clean all
+an so on.
+
+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 (0.0.4).
+The system call table will only be frozen when the linux-86 kernel is
+running and reasonably stable.
+
+THE COMPILER
+You should use the versions of bcc, unproto, as86, ld86 and elksemu that
+are in version 0.0.4 combined development environment. Some other
+versions will work but often they'll just appear to work or not work at
+all. The standard bcc-cc1 won't pickup the right header files, the
+standard ld86 won't generate COM files and looks in the wrong place for
+crt0.o and libc.a.
+
+Main Subdirectories.
+
+bcc Lots of BCC helper functions
+error The C error functions.
+grp Routines for /etc/group, from Nat
+include Some include files, some new others Glib or Glib hacked.
+kinclude Kernel include files, here for now.
+malloc1 My malloc routines
+malloc2 Joel's malloc routines
+misc Various larger functions
+msdos This is the equlivent of the syscall directory for msdos.
+pwd Routines for /etc/passwd, from Nat
+regexp Standard regular expression parser
+stdio1 Joel's standard I/O functions - as yet rather incomplete
+stdio2 My standard I/O
+string The functions for string.h
+syscall All the system call functions, and a few tied lib ones.
+termios Termimal mode control.
+utmp /etc/utmp updating
+tests Various C programs used to test the lib.
+
+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 by renaming Makefile<->makefile.
+ (This seemed like a good idea, I'm not so sure now ...)
+
+ 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/TODO b/libc/TODO
new file mode 100644
index 0000000..83e1a4e
--- /dev/null
+++ b/libc/TODO
@@ -0,0 +1,55 @@
+Here's a short list of bits that are required. If you want to do one of
+these it's probably best to post to the list <linux-8086@vger.rutgers.edu>.
+
+Add more to this todo list!
+
+
+TODO for libc-8086:
+Item Notes
+---------------------------------------------------------------------------
+Header Files - This will take some time, also some files should
+ be kernel.
+Floating Point - Bruce is on this (Yes that one) Initially it'll
+ assume an FPU is available. "int" version soon
+ after.
+dirent &co - Directory listing - Partial.
+hsearch &co -
+tsearch &co -
+locale processing - multi national, unicode (string stuff has a couple
+ of stubs)
+login - getpass and friends - Some, rest soon.
+rpc -
+syslog &co - make stubs to splatter to console.
+time calcs - mktime gmtime localtime etc, Nat
+timezone - Probably V simplistic, List of UTC's
+ offsets & STDvDST
+i386 support - For both GCC and BCC-386.
+
+Stdio - Joel is on this. (stdio1) (RDB stdio2)
+getgrent &co - Nat -Done
+getpwent &co - Nat -Done
+utmp/wtmp - Nat -Done
+setjmp - Done, Rob
+shadow password - Do we need ? Do we want :-) [No! Ick! ;) -Nat]
+termcap - and curses; what does ncurses need ? (150kb!!)
+crypt - TEA version, first cut.
+signal stuff - Got a basic 'signal' appears to work correctly.
+getenv/setenv - Done
+bsearch - Grabbed (Public Domain)
+lsearch - Grabbed (Public Domain)
+random numbers - Got ZX81 version (better than some) (And 2nd now)
+Build environment - Good first cut is now available.
+
+Other projects:
+Project Notes
+---------------------------------------------------------------------------
+Optimiser for BCC - A lot of work, but lucrative.
+ (assembler level one started, by?)
+Tiny vi editor - Use 'ae' ?
+Shells: Bourne, Csh,
+menu, silly - ash now compiles, Rob.
+Tiny Perl - :-) :-) You first ;)
+User commands - Everything in /bin /usr/bin - will existing PD/GPL
+ compile in 16 bit ? Or do smaller ones exist,
+ need to be written ?
+
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..4f52133
--- /dev/null
+++ b/libc/bcc/Makefile
@@ -0,0 +1,58 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+# Support for integer arithmetic
+IOBJ=__idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o
+ISRC=bcc_int.c
+
+# 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
+
+OBJ=__ldivmod.o $(IOBJ) $(LOBJ) $(AOBJ)
+OLDOBJ=$(ROBJ) $(POBJ)
+
+all: $(OBJ)
+
+$(IOBJ): $(ISRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ISRC)
+
+$(LOBJ): $(LSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC)
+
+$(AOBJ): $(ASRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+
+$(ROBJ): $(RSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(RSRC)
+
+$(POBJ): $(PSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(PSRC)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+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_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..af4e898
--- /dev/null
+++ b/libc/bcc/heap.c
@@ -0,0 +1,116 @@
+/* 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.
+ */
+
+/****************************************************************************/
+
+#ifdef L_errno
+int errno = 0; /* libc error value */
+#endif
+
+/****************************************************************************/
+
+#ifdef L___brk_addr
+#ifdef __AS386_16__
+#asm
+.data
+export brk_addr
+brk_addr: .word __end ! This holds the current return for sbrk(0)
+.text
+#endasm
+#endif
+#endif
+
+/****************************************************************************/
+
+#ifdef L_sbrk
+#ifdef __AS386_16__
+int sbrk(brk_off)
+unsigned 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,#64 ! Safety space
+ cmp bx,ax ! Too close ?
+ jb Enomem
+
+sbrk_ok:
+#ifndef __MSDOS__
+ 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
+#endif
+
+/****************************************************************************/
+
+#ifdef L_brk
+#ifdef __AS386_16__
+int
+brk(new_brk)
+void * new_brk;
+{
+#asm
+ mov bx,sp
+#if !__FIRST_ARG_IN_AX__
+ mov ax,[bx+2] ! Fetch the requested value
+#endif
+ sub bx,#64 ! Safety space
+ 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:
+#ifndef __MSDOS__
+ 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
+
+/****************************************************************************/
diff --git a/libc/crt0.c b/libc/crt0.c
new file mode 100644
index 0000000..71ca6bc
--- /dev/null
+++ b/libc/crt0.c
@@ -0,0 +1,57 @@
+/* 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 (the byte was free :-) )
+ ret
+
+ loc 1 ! Segment 1 is where the pointers to the autostart
+ZP_safety: ! functions are stored.
+ .word 0 ! But first some zeros to avoid null pointer writes.
+ .word 0
+ .word 0
+ .word 0
+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/crt0.o b/libc/crt0.o
new file mode 100644
index 0000000..e43705b
--- /dev/null
+++ b/libc/crt0.o
Binary files differ
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..bcc9287
--- /dev/null
+++ b/libc/error/Makefile
@@ -0,0 +1,17 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+OBJ=error.o sys_errlist.o perror.o sys_siglist.o __assert.o
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+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..1d9e65b
--- /dev/null
+++ b/libc/error/sys_errlist.c
@@ -0,0 +1,75 @@
+/* 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
+ .word no_op ! Space filler cause segs are padded to 4 bytes.
+ .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/grp/Config b/libc/grp/Config
new file mode 100644
index 0000000..9f49d93
--- /dev/null
+++ b/libc/grp/Config
@@ -0,0 +1 @@
+grp: /etc/group managment
diff --git a/libc/grp/Makefile b/libc/grp/Makefile
new file mode 100644
index 0000000..e8cb13a
--- /dev/null
+++ b/libc/grp/Makefile
@@ -0,0 +1,41 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+ifeq ($(PLATFORM),i386-Linux)
+CFLAGS+=$(WALL)
+else # ifeq ($(PLATFORM),i86-ELKS)
+CFLAGS=$(CCFLAGS) $(LIBDEFS) -ansi
+endif
+
+GSRC=__getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c initgroups.c \
+ config-grp.h
+GOBJ=__getgrent.o grent.o getgrnam.o getgrgid.o fgetgrent.o initgroups.o
+
+all: $(GOBJ)
+
+%.o: %.c config-grp.h
+ $(CC) $(CFLAGS) -o $@ $< -c
+
+libc.a: $(GOBJ)
+ ar r ../$(LIBC) $(GOBJ)
+ @touch libc.a
+
+test: test_grp.c libgrp.a
+ $(CC) $(CFLAGS) test_grp.c -o test_grp -L -lgrp # -static
+
+libgrp: libgrp.a
+
+libgrp.a: $(GOBJ)
+ ar r libgrp.a $(GOBJ)
+ ranlib libgrp.a
+
+clean:
+ rm -f *.o libc.a libgrp.a
+
+
+
+
diff --git a/libc/grp/__getgrent.c b/libc/grp/__getgrent.c
new file mode 100644
index 0000000..612f112
--- /dev/null
+++ b/libc/grp/__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/grp/config-grp.h b/libc/grp/config-grp.h
new file mode 100644
index 0000000..337d54b
--- /dev/null
+++ b/libc/grp/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/grp/config.h b/libc/grp/config.h
new file mode 100644
index 0000000..337d54b
--- /dev/null
+++ b/libc/grp/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/grp/fgetgrent.c b/libc/grp/fgetgrent.c
new file mode 100644
index 0000000..800236f
--- /dev/null
+++ b/libc/grp/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/grp/getgrgid.c b/libc/grp/getgrgid.c
new file mode 100644
index 0000000..c1dd20e
--- /dev/null
+++ b/libc/grp/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/grp/getgrnam.c b/libc/grp/getgrnam.c
new file mode 100644
index 0000000..e6c27fc
--- /dev/null
+++ b/libc/grp/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/grp/grent.c b/libc/grp/grent.c
new file mode 100644
index 0000000..19d618b
--- /dev/null
+++ b/libc/grp/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/grp/initgroups.c b/libc/grp/initgroups.c
new file mode 100644
index 0000000..35e1d03
--- /dev/null
+++ b/libc/grp/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/grp/test_grp.c b/libc/grp/test_grp.c
new file mode 100644
index 0000000..b5ecd36
--- /dev/null
+++ b/libc/grp/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/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..fe4e8ae
--- /dev/null
+++ b/libc/gtermcap/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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+OBJ=termcap.o tparam.o
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+clean:
+ rm -f *.o libc.a
+
+$(SOBJ): $(SSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(SSRC)
+
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/include/a.out.h b/libc/include/a.out.h
new file mode 100644
index 0000000..f6a7b94
--- /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[24]; /* 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/ctype.h b/libc/include/ctype.h
new file mode 100644
index 0000000..038659f
--- /dev/null
+++ b/libc/include/ctype.h
@@ -0,0 +1,37 @@
+/*
+ * 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)
+
+#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..28575b4
--- /dev/null
+++ b/libc/include/dos.h
@@ -0,0 +1,34 @@
+
+#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;
+};
+
+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));
+
+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..579287e
--- /dev/null
+++ b/libc/include/limits.h
@@ -0,0 +1,33 @@
+/* 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
+#else
+#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/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..58bade7
--- /dev/null
+++ b/libc/include/paths.h
@@ -0,0 +1,20 @@
+/* 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_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..c2bfadb
--- /dev/null
+++ b/libc/include/setjmp.h
@@ -0,0 +1,26 @@
+
+#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 !?
+ */
+#endif
diff --git a/libc/include/sgtty.h b/libc/include/sgtty.h
new file mode 100644
index 0000000..9e26956
--- /dev/null
+++ b/libc/include/sgtty.h
@@ -0,0 +1 @@
+#include <termios.h>
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..978529b
--- /dev/null
+++ b/libc/include/stdarg.h
@@ -0,0 +1,38 @@
+ /*
+ * @(#) 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.
+ */
+
+#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
diff --git a/libc/include/stddef.h b/libc/include/stddef.h
new file mode 100644
index 0000000..f21f683
--- /dev/null
+++ b/libc/include/stddef.h
@@ -0,0 +1,26 @@
+/* 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
+
+#if __AS386_16__ /* Only for 8086 */
+#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..ba70b1d
--- /dev/null
+++ b/libc/include/stdio.h
@@ -0,0 +1,125 @@
+
+#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;
+
+#define BUFSIZ (256)
+
+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..f67984a
--- /dev/null
+++ b/libc/include/stdlib.h
@@ -0,0 +1,30 @@
+/* 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));
+extern double strtod __P ((const char * nptr, char ** endptr));
+
+#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..366b0c6
--- /dev/null
+++ b/libc/include/sys/cdefs.h
@@ -0,0 +1,33 @@
+
+#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 *
+typedef double __long_double_t;
+
+#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/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/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..4a4bdbd
--- /dev/null
+++ b/libc/include/sys/stat.h
@@ -0,0 +1,27 @@
+#ifndef _SYS_STAT_H
+#define _SYS_STAT_H
+
+#include <linuxmt/stat.h>
+#include <sys/types.h>
+#include <features.h>
+
+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;
+};
+
+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));
+
+#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/wait.h b/libc/include/sys/wait.h
new file mode 100644
index 0000000..70a0e4a
--- /dev/null
+++ b/libc/include/sys/wait.h
@@ -0,0 +1,2 @@
+
+/** FIXME **/
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..4ca1ec8
--- /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 int cfgetispeed __P ((struct termios *__termios_p));
+extern int 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..b9eb87c
--- /dev/null
+++ b/libc/include/time.h
@@ -0,0 +1,61 @@
+#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;
+};
+
+#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));
+extern __CONSTVALUE double difftime __P ((time_t __time2,
+ time_t __time1)) __CONSTVALUE2;
+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..79dd5c2
--- /dev/null
+++ b/libc/kinclude/Makefile
@@ -0,0 +1,18 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+OBJ=
+
+all: $(OBJ)
+
+libc.a:
+
+transfer:
+ -@rm -f ../include/linuxmt
+ ln -s ../kinclude/linuxmt ../include
+
+clean:
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..d6690d1
--- /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 int __u16;
+typedef unsigned int * __pu16;
+typedef int __s16;
+typedef int * __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..0eb1c0e
--- /dev/null
+++ b/libc/kinclude/linuxmt/stat.h
@@ -0,0 +1,55 @@
+#ifndef _LINUX_STAT_H
+#define _LINUX_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)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+
+#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..52bde9a
--- /dev/null
+++ b/libc/kinclude/linuxmt/termios.h
@@ -0,0 +1,258 @@
+#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
+
+#endif /* _LINUXMT_TERMIOS_H */
diff --git a/libc/kinclude/linuxmt/types.h b/libc/kinclude/linuxmt/types.h
new file mode 100644
index 0000000..437d985
--- /dev/null
+++ b/libc/kinclude/linuxmt/types.h
@@ -0,0 +1,32 @@
+#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 unsigned int speed_t;
+
+typedef __u16 dev_t;
+typedef __u16 ino_t;
+typedef __u32 tcflag_t;
+typedef __u8 cc_t;
+
+#endif
+
diff --git a/libc/libc.a b/libc/libc.a
new file mode 100644
index 0000000..9c13df0
--- /dev/null
+++ b/libc/libc.a
Binary files differ
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..6322454
--- /dev/null
+++ b/libc/malloc1/Makefile
@@ -0,0 +1,24 @@
+
+TOP=..
+include $(TOP)/Make.defs
+
+ASRC=malloc.c
+AOBJ=malloc.o alloca.o free.o calloc.o realloc.o
+
+OBJ=$(AOBJ)
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+clean:
+ rm -f *.o libc.a
+
+$(AOBJ): $(ASRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+
+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..91912f7
--- /dev/null
+++ b/libc/malloc1/malloc.c
@@ -0,0 +1,540 @@
+/* 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) + 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 sbrk", chk);
+ sbrk(-m_size(chk) * sizeof(mem));
+ /*
+ * 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
+ */
+
+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 (m_size(ptr) < (MAX_INT/sizeof(mem))
+ && 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 */
+ {
+ for(alloc/=2; alloc>256; )
+ {
+ ptr = __mini_malloc(alloc);
+ if (ptr) 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..0396df2
--- /dev/null
+++ b/libc/malloc2/Makefile
@@ -0,0 +1,23 @@
+
+TOP=..
+include $(TOP)/Make.defs
+
+MOBJ=malloc.o stack.o
+
+OBJ=$(MOBJ)
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+clean:
+ rm -f $(OBJ) libc.a
+
+$(AOBJ): $(ASRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+
+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..143d324
--- /dev/null
+++ b/libc/malloc2/malloc.c
@@ -0,0 +1,127 @@
+/* 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
+ .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
+
+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..87ad1e5
--- /dev/null
+++ b/libc/misc/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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+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
+
+OBJ=$(MOBJ) $(EOBJ) \
+ atoi.o atol.o ltoa.o ltostr.o \
+ ctype.o qsort.o bsearch.o rand.o lsearch.o getopt.o \
+ getenv.o putenv.o itoa.o cputype.o \
+ strtol.o popen.o system.o crypt.o
+
+# No ELKS strtod() until BCC does 16 bit FP...
+ifeq ($(PLATFORM),i386-Linux)
+OBJ+=strtod.o
+endif
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+clean:
+ rm -f *.o libc.a
+
+$(MOBJ): $(MSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(MSRC)
+
+$(EOBJ): $(ESRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ESRC)
+
+crypt.o: crypt.c
+ifeq ($(PLATFORM),i386-Linux)
+ $(CC) $(CFLAGS) $< -c -o $@ $(WALL)
+else
+ $(CC) $(CFLAGS) $< -c -o $@ -ansi
+endif
+
+strto%.o: strto%.c
+ifeq ($(PLATFORM),i386-Linux)
+ $(CC) $(CFLAGS) $< -c -o $@ $(WALL)
+else
+ $(CC) $(CFLAGS) $< -c -o $@ -ansi
+endif
diff --git a/libc/misc/aliases.c b/libc/misc/aliases.c
new file mode 100644
index 0000000..466cb74
--- /dev/null
+++ b/libc/misc/aliases.c
@@ -0,0 +1,109 @@
+/* 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)
+void * src, *dest;
+unsigned int len;
+{
+ (void) memcpy(dest, src, len);
+}
+#endif
+
+#ifdef L_bzero
+#undef bzero
+void
+bzero(dest, len)
+void *dest;
+unsigned int len;
+{
+ (void) memset(dest, '\0', len);
+}
+#endif
+
+#ifdef L_bcmp
+#undef bcmp
+int
+bcmp(dest, src, len)
+void * src, *dest;
+unsigned int len;
+{
+ return memcmp(dest, src, len);
+}
+#endif
+
+#ifdef L_index
+#undef index
+char *
+index(src, chr)
+char *src;
+int chr;
+{
+ return strchr(src, chr);
+}
+#endif
+
+#ifdef L_rindex
+#undef rindex
+char *
+rindex(src, chr)
+char *src;
+int chr;
+{
+ return strrchr(src, chr);
+}
+#endif
+
+#ifdef L_remove
+#include <errno.h>
+
+int
+remove(src)
+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..642edf6
--- /dev/null
+++ b/libc/misc/cputype.c
@@ -0,0 +1,344 @@
+/*
+ * 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)
+ * An MSDOS compiled version is available.
+ *
+ * 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-1995
+ */
+
+#ifdef STANDALONE
+
+#include <stdio.h>
+#include <signal.h>
+
+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
+export _cputype
+_cputype:
+ ; 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 ; 286 == FFFF, 386+ anything else
+ inc ax
+ jz cpu_prot
+ mov bh,#$13 ; Major CPU type >= 80386
+
+; smsw ax
+; ror ax,#1
+; jnc try_486 ; If in real mode and running MSDOS
+
+ 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 cpu_prot ; It`s id`ed as a 286 we already know
+ ; different but it`s probably a bad idea
+ ; to try for a 486.
+
+try_486:
+ ; This trys to trap undefined instructions
+ ; it may not work if the CPU is in protected mode
+ ; Note: This does actually re-test 286 v 386
+ 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
+ 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
+;;
+ 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..1514668
--- /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/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/strtod.c b/libc/misc/strtod.c
new file mode 100644
index 0000000..8acb423
--- /dev/null
+++ b/libc/misc/strtod.c
@@ -0,0 +1,96 @@
+/*
+ * 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>
+
+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);
+}
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..2dd3497
--- /dev/null
+++ b/libc/msdos/Makefile
@@ -0,0 +1,36 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+ASRC=msdos.c
+AOBJ= dos_start.o __mkargv.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_setvect.o dos_getvect.o dos_isatty.o
+
+BSRC=i86.c
+BOBJ= __set_es.o __peek_es.o __poke_es.o __deek_es.o __strchr_es.o
+
+ifeq ($(PLATFORM),i86-DOS)
+OBJ=$(AOBJ) $(BOBJ)
+else
+OBJ=$(BOBJ)
+endif
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+clean:
+ rm -f *.o libc.a
+
+$(AOBJ): $(ASRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+
+$(BOBJ): $(BSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(BSRC)
+
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..0613756
--- /dev/null
+++ b/libc/msdos/i86.c
@@ -0,0 +1,163 @@
+/* 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___set_es
+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___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..02c35db
--- /dev/null
+++ b/libc/msdos/msdos.c
@@ -0,0 +1,540 @@
+/* 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 * argdef[2] = { "C" };
+char ** __argv =argdef;
+char ** environ =argdef+1;
+
+int __argc =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
+
+ call ___mkargv ! Fetch the arguments and enviroment
+ push [_environ]
+ push [___argv]
+ push [___argc]
+
+ mov si,#auto_start ! Pointer to first autostart function
+auto_run:
+ call [si] ! Call the function
+ 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
+
+extern char ** environ;
+extern char ** __argv;
+extern int __argc;
+
+__mkargv()
+{
+ 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_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_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_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/pwd/Config b/libc/pwd/Config
new file mode 100644
index 0000000..b5aaad0
--- /dev/null
+++ b/libc/pwd/Config
@@ -0,0 +1 @@
+pwd: /etc/passwd managment
diff --git a/libc/pwd/Makefile b/libc/pwd/Makefile
new file mode 100644
index 0000000..a31ac02
--- /dev/null
+++ b/libc/pwd/Makefile
@@ -0,0 +1,40 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+ifeq ($(PLATFORM),i386-Linux)
+CFLAGS+=$(WALL)
+else # ifeq ($(PLATFORM),i86-ELKS)
+CFLAGS=$(CCFLAGS) $(LIBDEFS) -ansi
+endif
+
+PSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c fgetpwent.c
+POBJ=__getpwent.o pwent.o getpwnam.o getpwuid.o putpwent.o getpw.o fgetpwent.o
+
+all: $(POBJ)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ $< -c
+
+libc.a: $(POBJ)
+ ar r ../$(LIBC) $(POBJ)
+ @touch libc.a
+
+test: test_pwd.c libpwd.a
+ $(CC) $(CFLAGS) test_pwd.c -o test_pwd -L. -lpwd
+
+libpwd.a: $(POBJ)
+ ar r libpwd.a $(POBJ)
+ ranlib libpwd.a
+
+libpwd: libpwd.a
+
+clean:
+ rm -f *.o libc.a libpwd.a
+
+
+
+
diff --git a/libc/pwd/__getpwent.c b/libc/pwd/__getpwent.c
new file mode 100644
index 0000000..9836ca7
--- /dev/null
+++ b/libc/pwd/__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/pwd/fgetpwent.c b/libc/pwd/fgetpwent.c
new file mode 100644
index 0000000..e12b890
--- /dev/null
+++ b/libc/pwd/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/pwd/getpw.c b/libc/pwd/getpw.c
new file mode 100644
index 0000000..4f4e390
--- /dev/null
+++ b/libc/pwd/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/pwd/getpwnam.c b/libc/pwd/getpwnam.c
new file mode 100644
index 0000000..85dbc8e
--- /dev/null
+++ b/libc/pwd/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/pwd/getpwuid.c b/libc/pwd/getpwuid.c
new file mode 100644
index 0000000..ffd58c1
--- /dev/null
+++ b/libc/pwd/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/pwd/putpwent.c b/libc/pwd/putpwent.c
new file mode 100644
index 0000000..a0035ea
--- /dev/null
+++ b/libc/pwd/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/pwd/pwent.c b/libc/pwd/pwent.c
new file mode 100644
index 0000000..fd65db2
--- /dev/null
+++ b/libc/pwd/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/pwd/test_pwd.c b/libc/pwd/test_pwd.c
new file mode 100644
index 0000000..74f7657
--- /dev/null
+++ b/libc/pwd/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/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..71c2b81
--- /dev/null
+++ b/libc/regexp/Makefile
@@ -0,0 +1,28 @@
+
+TOP=..
+include $(TOP)/Make.defs
+
+OBJ=regexp.o regsub.o
+LSRC=regexp.c regsub.c regerror.c
+
+try: try.o $(OBJ)
+ $(CC) $(CFLAGS) try.o $(OBJ) -o try
+
+# Regression test.
+test: try tests
+ @echo 'No news is good news...'
+ try <tests
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+transfer:
+ -@rm -f ../include/regexp.h ../include/regmagic.h
+ cp -p regexp.h regmagic.h ../include/.
+
+regexp.o: regexp.c regexp.h regmagic.h
+regsub.o: regsub.c regexp.h regmagic.h
+
+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/stdio1/BUGS b/libc/stdio1/BUGS
new file mode 100644
index 0000000..0e8e0db
--- /dev/null
+++ b/libc/stdio1/BUGS
@@ -0,0 +1,15 @@
+Error checking is known to be wanting. However the author just wants to
+get it working right now.
+
+fread() and fwrite() are not supported. open(), read(), write(), and close()
+work very well for binary data.
+
+fopen() is the only way to open a file. None of the temp stuff is supported,
+and frepon() is unsupported.
+
+GNU extensions are unsupported.
+
+Some printf specifications may not work. Read the code for details of what
+IS supported.
+
+Other than that, this should be a perfectly normal stdio lib when it's finished.
diff --git a/libc/stdio1/Config b/libc/stdio1/Config
new file mode 100644
index 0000000..3b3b35f
--- /dev/null
+++ b/libc/stdio1/Config
@@ -0,0 +1,3 @@
+
+
+stdio: Joel's stdio package altered by Nat
diff --git a/libc/stdio1/Makefile b/libc/stdio1/Makefile
new file mode 100644
index 0000000..d8058b0
--- /dev/null
+++ b/libc/stdio1/Makefile
@@ -0,0 +1,36 @@
+TOP=..
+include $(TOP)/Make.defs
+OBJ = __ffillbuf.o __stdio_init.o fflush.o fgetc.o fgets.o \
+ fputc.o fputs.o puts.o printf.o fopen.o fclose.o scanf.o
+
+#missing functions from above: printf etc, scanf etc, idealgetline
+#seek
+
+#fopen.c, fclose.c removed because of malloc() use
+
+CFLAGS+=$(WALL)
+
+ifeq ($(PLATFORM),i86-ELKS)
+CFLAGS=$(CCFLAGS) $(DEFS) -ansi
+endif
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+$(OBJ): stdio.h
+
+test: test.o $(OBJ)
+ $(CC) -o test test.o $(OBJ)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ $< -c
+
+clean:
+ rm -f *.o test libc.a
+
+transfer:
+ -@rm -f ../include/stdio.h
+ cp -p stdio.h ../include/.
diff --git a/libc/stdio1/NOTICE b/libc/stdio1/NOTICE
new file mode 100644
index 0000000..25ca5b6
--- /dev/null
+++ b/libc/stdio1/NOTICE
@@ -0,0 +1,17 @@
+/*
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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.
+ */
diff --git a/libc/stdio1/README b/libc/stdio1/README
new file mode 100644
index 0000000..5dc59aa
--- /dev/null
+++ b/libc/stdio1/README
@@ -0,0 +1,13 @@
+I found that it was helpful to have the extern stuff actually defined in
+one file as not external...
+
+Still trying to find the other problems
+
+Whether it is desireable to list stdio.h as a dependency is debateable
+
+-Joel
+
+I've made a horrible number of changes here, look in 'Reverse_Patch' for
+how to go back ...
+
+-Robert
diff --git a/libc/stdio1/TODO b/libc/stdio1/TODO
new file mode 100644
index 0000000..481f6d9
--- /dev/null
+++ b/libc/stdio1/TODO
@@ -0,0 +1,33 @@
+Sun Jan 21 18:16:03 EST 1996 -- Nat Friedman
+============================================
+I've made a load of changes to this code, but there's still a lot to be done.
+- scanf, fscanf
+
+
+
+
+input, file positioning, eof, declarations of functions, printf
+
+look for unsigned char references
+
+specifically
+fix printf and figure out what's going on in there.
+write idealgetline, scanf, other stuff
+then deal with above stuff...
+
+
+LATEST LIST:
+printf, fprintf
+scanf, fscanf
+feof
+seek support
+error handling (not too hard since system calls only in a few places)
+atexit stuff (close files; will need to add a linked list of files)
+setvbuf if desired
+check that fopen() and stdio_init() fill in ALL the fields
+testing!
+
+rm NOTICE
+
+
+
diff --git a/libc/stdio1/__ffillbuf.c b/libc/stdio1/__ffillbuf.c
new file mode 100644
index 0000000..e705cbf
--- /dev/null
+++ b/libc/stdio1/__ffillbuf.c
@@ -0,0 +1,55 @@
+/* simplified linux __ffillbuf.c
+ 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 <unistd.h>
+#include "stdio.h"
+
+/* this function makes the mistake of assuming the buffer really DOES
+need to be filled. */
+
+/* RDB:
+ * Added simple processing for EOF and errors
+ * As this is _only_ called from getc() the memory footprint is smaller
+ * if it pretends to be getc in the complex case.
+ */
+
+int
+__ffillbuf(stream)
+FILE *stream;
+{
+ int stat;
+
+ if( stream->fd < 0 || ferror(stream) ) return EOF;
+
+ stat = read(stream->fd, (char *) stream->bufstart, stream->bufend - stream->bufstart);
+ if( stat > 0 )
+ stream->bufread = stream->bufstart + stat;
+ else if( stat == 0 )
+ {
+ stream->fc_eof = 1;
+ return EOF;
+ }
+ else
+ {
+ stream->fc_err = 1;
+ return EOF;
+ }
+
+ stream->bufpos = stream->bufstart;
+
+ return getc(stream);
+}
diff --git a/libc/stdio1/__stdio_init.c b/libc/stdio1/__stdio_init.c
new file mode 100644
index 0000000..b49bb28
--- /dev/null
+++ b/libc/stdio1/__stdio_init.c
@@ -0,0 +1,66 @@
+/* simplified linux __stdio_init.c
+ 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 "stdio.h"
+
+/*
+ OK, Complete hackup here, I've removed the need for the init function.
+ Not also I've make the types into 'unsigned char' this is so it doesn't
+ return EOF when it really means '\377'
+ */
+
+static unsigned char __stdinbuf[BUFSIZ], __stdoutbuf[BUFSIZ], __stderrbuf[80];
+
+static FILE __the_stdin = {
+ 0,
+ __stdinbuf,
+ __stdinbuf,
+ __stdinbuf,
+ __stdinbuf+sizeof(__stdinbuf),
+ _IOLBF,
+ _MODE_READ,
+ 0, 0,
+ 0, 0, 1
+};
+
+static FILE __the_stdout = {
+ 1,
+ __stdoutbuf,
+ __stdoutbuf,
+ __stdoutbuf,
+ __stdoutbuf+sizeof(__stdoutbuf),
+ _IOLBF,
+ _MODE_WRITE,
+ 0, 0,
+ 0, 0, 1
+};
+
+static FILE __the_stderr = {
+ 2,
+ __stderrbuf,
+ __stderrbuf,
+ __stderrbuf,
+ __stderrbuf+sizeof(__stderrbuf),
+ _IOLBF,
+ _MODE_WRITE,
+ 0, 0,
+ 0, 0, 1
+};
+
+FILE *stdin = &__the_stdin,
+ *stdout = &__the_stdout,
+ *stderr = &__the_stderr;
diff --git a/libc/stdio1/fclose.c b/libc/stdio1/fclose.c
new file mode 100644
index 0000000..7ec233e
--- /dev/null
+++ b/libc/stdio1/fclose.c
@@ -0,0 +1,41 @@
+/* simplified linux fclose.c
+ 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 <unistd.h>
+#include "stdio.h"
+
+int fclose (stream)
+FILE *stream;
+{
+ /* only allow fclose() on what was fopen()ed. */
+ /*
+ This isn't right, there's nothing wrong with fclosing stdin
+ but the next fopen/open will be given fd 0 and so become stdin
+ Of course you do have to be a little careful :-)
+ RDB
+ */
+
+ if ((stream == stdin) || (stream == stdout) || (stream == stderr)) return EOF;
+
+ if (fflush(stream)) return EOF;
+
+ if (close(stream->fd)) return EOF;
+
+ free(stream->bufstart);
+ free(stream);
+ return 0;
+}
diff --git a/libc/stdio1/fcntl.h b/libc/stdio1/fcntl.h
new file mode 100644
index 0000000..69fdb90
--- /dev/null
+++ b/libc/stdio1/fcntl.h
@@ -0,0 +1,72 @@
+#ifndef __FCNTL_H
+#define __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__ */
+
+#if 0
+struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ pid_t l_pid;
+};
+#endif
+
+#endif
diff --git a/libc/stdio1/fflush.c b/libc/stdio1/fflush.c
new file mode 100644
index 0000000..c9cdac7
--- /dev/null
+++ b/libc/stdio1/fflush.c
@@ -0,0 +1,36 @@
+/* simplified linux fflush.c
+ 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 <unistd.h>
+#include "stdio.h"
+
+int fflush(stream)
+FILE *stream;
+{
+ if (stream == 0) return 0;
+ if ((stream->file_mode == _MODE_WRITE)
+ ||(stream->file_mode == (_MODE_WRITE & _MODE_RDWR))){
+ write(stream->fd, (char *) stream->bufstart,
+ stream->bufpos - stream->bufstart);
+ stream->bufpos = stream->bufstart;
+ }
+ return 0;
+}
+/* TODO: return EOF or 0; support NULL stream */
+/* The only place an error can come from is the write; you're not checking RDB
+ */
diff --git a/libc/stdio1/fgetc.c b/libc/stdio1/fgetc.c
new file mode 100644
index 0000000..2c41062
--- /dev/null
+++ b/libc/stdio1/fgetc.c
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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 "stdio.h"
+
+/*
+ * Make this not dependent on getc() then we can:
+ #define getc(fp) fgetc(fp)
+ * if memory is _really_ tight.
+ */
+
+int fgetc(stream)
+FILE *stream;
+{
+ if( stream->ungetted )
+ {
+ stream->ungetted = 0;
+ return stream->ungetchar;
+ }
+ if( stream->bufpos == stream->bufread )
+ return __ffillbuf(stream);
+ else
+ return *stream->bufpos++;
+}
diff --git a/libc/stdio1/fgets.c b/libc/stdio1/fgets.c
new file mode 100644
index 0000000..c085970
--- /dev/null
+++ b/libc/stdio1/fgets.c
@@ -0,0 +1,50 @@
+/* fgets.c for limited linux stdio
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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 "stdio.h"
+
+/*
+ RDB BZZZT! This should only read upto and including any newline!
+*/
+
+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;
+}
diff --git a/libc/stdio1/fopen.c b/libc/stdio1/fopen.c
new file mode 100644
index 0000000..1265ff5
--- /dev/null
+++ b/libc/stdio1/fopen.c
@@ -0,0 +1,80 @@
+/* simplified linux fopen.c
+ 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 "stdio.h"
+#include <malloc.h>
+
+FILE * fopen(name, openmode)
+char *name;
+char *openmode;
+{
+ FILE *new;
+ int openplus=0;
+ char basemode;
+
+ basemode = openmode[0];
+ while (openmode[0] != 0){
+ switch(openmode[0]){
+ case '+': openplus=1; break;
+ }
+ openmode++;
+ }
+
+ new = malloc(sizeof(new));
+ if( new == 0 ) return 0;
+ new->bufread = new->bufpos = new->bufstart = malloc(BUFSIZ);
+ if( new->bufstart == 0 ) { free(new) ; return 0; }
+
+ new->bufend = new->bufstart + BUFSIZ;
+ new->buffer_mode = _IOFBF;
+ new->iotrans = 0;
+ new->fd = -1;
+ if (openplus){
+ new->file_mode = _MODE_RDWR;
+ switch (basemode){
+ case 'a':
+ new->fd = open(name, O_RDWR | O_APPEND | O_CREAT);
+ break;
+ case 'r':
+ new->fd = open(name, O_RDWR);
+ break;
+ case 'w':
+ new->fd = open(name, O_RDWR | O_TRUNC | O_CREAT);
+ break;
+ }
+ } else switch (basemode){
+ case 'a':
+ new->fd = open(name, O_WRONLY | O_APPEND | O_CREAT);
+ new->file_mode = _MODE_WRITE;
+ break;
+ case 'r':
+ new->fd = open(name, O_RDONLY);
+ new->file_mode = _MODE_READ;
+ break;
+ case 'w':
+ new->fd = open(name, O_WRONLY | O_TRUNC | O_CREAT);
+ new->file_mode = _MODE_WRITE;
+ break;
+ }
+ if( new->fd < 0 )
+ {
+ free(new->bufstart);
+ free(new);
+ return 0;
+ }
+ return new;
+}
diff --git a/libc/stdio1/fputc.c b/libc/stdio1/fputc.c
new file mode 100644
index 0000000..939a721
--- /dev/null
+++ b/libc/stdio1/fputc.c
@@ -0,0 +1,53 @@
+/* simplified linux fputc.c
+ 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 "stdio.h"
+
+/*
+ * Make this not dependent on putc() then we can:
+ #define putc(c, fp) fputc(c, fp)
+ * if memory is _really_ tight.
+ */
+
+#undef putc
+#define putc(c, stream) \
+ (((stream)->bufpos[0] = (c)), \
+ ((stream)->bufpos++), \
+ ((((stream)->bufpos == (stream)->bufend) \
+ ||((stream)->buffer_mode == _IONBF) \
+ ||(((stream)->buffer_mode == _IOLBF) \
+ && ((stream)->bufpos != (stream)->bufstart) \
+ && ((stream)->bufpos[-1] == '\n'))) \
+ ? fflush(stream):0))
+
+#define new_putc(c, stream) \
+ ((unsigned char)( \
+ ((stream)->bufpos>=(stream)->bufread) ? fputc((c), (stream)) \
+ : *(stream)->bufpos++ = (c) \
+ ))
+
+int
+fputc(int c, FILE * stream)
+{
+#ifdef __MSDOS__
+ if( c == '\n' && stream->iotrans ) fputc('\r', stream);
+#endif
+ return putc(c, stream);
+}
+
+
+
diff --git a/libc/stdio1/fputs.c b/libc/stdio1/fputs.c
new file mode 100644
index 0000000..41e2998
--- /dev/null
+++ b/libc/stdio1/fputs.c
@@ -0,0 +1,32 @@
+/* simplified linux fputs.c
+ 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 <unistd.h>
+#include <string.h>
+#include "stdio.h"
+
+int
+fputs(__const char * string, FILE * stream)
+{
+ if (stream->buffer_mode != _IONBF){
+ while (string[0] != 0){
+ putc(string[0], stream);
+ string++;
+ }
+ } else write(stream->fd, string, strlen(string));
+ return 0;
+}
diff --git a/libc/stdio1/idealgetline.c b/libc/stdio1/idealgetline.c
new file mode 100644
index 0000000..7eacc9e
--- /dev/null
+++ b/libc/stdio1/idealgetline.c
@@ -0,0 +1,67 @@
+/* idealgetline.c -- my idea of an ideal getline function for stdio
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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.
+ */
+
+/* I actually intend to use this in 32 bit programs, unlike the other stuff
+ in this lib. IMHO GNU getline is broken. It is too hard to use.
+
+ Just pass this function a FILE * and it will retrieve a line for you using
+ getc(). It will realloc() exactly the amount of memory needed, and will
+ generate error messages for non-ascii characters on stderr.
+
+ This may not be your ideal. It probably generates far too many errors.
+ It doesn't work well for those who don't use English (but since
+ Linux-less-than-32 libc and kernels are each being produced by one
+ person in the US and one in the UK, this isn't a problem). It probably
+ is not what you (or I) want for interactive input.
+
+ You're welcome to modify this routine to meet your needs. However, if
+ you change the semantics significantly, please change the name.
+
+ (Maybe I should have put my own name on it so there will be no confusion
+ about who thought it was ideal). */
+
+#include <stdio.h>
+#include <malloc.h>
+
+char *idealgetline(f)
+FILE *f;
+{
+ char c;
+ char *ret;
+ int size = 0, bufsize = 256;
+
+ ret = malloc(256);
+ c = getc(f);
+ while ((c != EOF) && (c != '\n')){
+ if ((c >= ' ') && (c <= 126)){
+ ret[size] = c;
+ size++;
+ if (size == bufsize){
+ bufsize += 256;
+ ret = realloc(ret, bufsize);
+ }
+ } else {
+ fprintf(stderr, "Unexpected character 0x%x encountered in input", c);
+ free(ret);
+ return 0;
+ }
+ }
+ ret[size] = '\0';
+ size++;
+ return realloc(ret, size);
+}
diff --git a/libc/stdio1/old_printf.c b/libc/stdio1/old_printf.c
new file mode 100644
index 0000000..81d62ac
--- /dev/null
+++ b/libc/stdio1/old_printf.c
@@ -0,0 +1,230 @@
+/* fprintf.c for limited Linux libc
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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.
+ */
+/* Thanks Alan for writing the hard routine for me :-)
+ * Alan said that this works "most of the time". Something tells me I'm making
+ * it even worse! */
+/* The basic idea here is to make fprintf the core routine. printf obviously
+ can just call fprintf with stdout followed by all of its arguments.
+ sprintf() works using the fake file &the_sprintf. It's marked as fully
+ buffered, so that it will only write(2) when &the_sprintf->bufpos ==
+ &the_sprintf->bufend, which I doubt will happen since &the_sprintf->bufend
+ = 0. The trick is that sprintf must set &the_sprintf->bufstart =
+ &the_sprintf->bufpos = its first argument. Not as orthagonal (is that
+ the right word?) as glibc's facilities for non-files, but this isn't a
+ library for people who have unlimited RAM budgets. (not like the libc
+ I use on linux/i586 enjoys an unlimited RAM budget either; I only have
+ 8 MB
+
+ I'm not sure what the "correct" way to pass the variable arguments
+ from one function to the next is. Rather than pass the arguments
+ themselves, I'm passing a pointer to them. However, the following
+ explaination from Alan is probably a polite way of saying it will not
+ work on a 386 anyway.
+ Joel Weber
+
+ [ I've migrated all of this code over to the ELKS stdarg that I wrote.
+ The accepted way to do it is for the wrapper function to accept a
+ variable number of arguments, use stdarg to make an argument pointer,
+ and then pass the argument pointer on to the core function, as I've
+ done here. This should definitely work on a 386, as the arguments
+ are still passed in the stack, and stack order is maintained. -Nat ]
+ */
+
+/*
+ * This is NOT stunningly portable, but works
+ * for pretty dumb non ANSI compilers and is
+ * tight. Adjust the sizes to taste.
+ *
+ * Illegal format strings will break it. Only the
+ * following simple subset is supported
+ *
+ * %x - hex
+ * %d - decimal
+ * %s - string
+ * %c - char
+ *
+ * And the h/l length specifiers for %d/%x
+ *
+ * Alan Cox.
+ */
+
+#include <stdarg.h>
+#include "stdio.h"
+
+/* 17 to make sure that there's room for the trailing newline.
+ I'm not really sure if this is ideal... */
+static char nstring[17]="0123456789ABCDEF";
+
+static unsigned char *
+__numout(long i, int base)
+{
+ static unsigned char out[16];
+ int n;
+ int flg = 0;
+ unsigned long val;
+
+ if (i<0 && base==10)
+ {
+ flg = 1;
+ i = -i;
+ }
+ val = i;
+
+ for (n = 0; n < 15; n++)
+ out[n] = ' ';
+ out[15] = '\0';
+ n = 14;
+ do{
+ out[n] = nstring[val % base];
+ n--;
+ val /= base;
+ }
+ while(val);
+ if(flg) out[n--] = '-';
+ return &out[n+1];
+}
+
+static int
+internal_fprintf(FILE * stream, __const char * fmt, va_list ap)
+{
+ register int c;
+ int count = 0;
+ int type, base;
+
+ while(c=*fmt++)
+ {
+ if(c!='%')
+ {
+ putc(c, stream);
+ count++;
+ }
+ else
+ {
+ type=1;
+ do { c=*fmt++; } while( c=='.' || (c>='0' && c<='9'));
+ if( c == 0 ) break;
+ if(c=='h')
+ {
+ c=*fmt++;
+ type = 0;
+ }
+ else if(c=='l')
+ {
+ c=*fmt++;
+ type = 2;
+ }
+
+ switch(c)
+ {
+ case 'x':
+ case 'o':
+ case 'd':
+ if (c=='x') base=16;
+ if (c=='o') base=8;
+ if (c=='d') base=10;
+ {
+ long val=0;
+ switch(type)
+ {
+ case 0:
+ val=va_arg(ap, short);
+ break;
+ case 1:
+ val=va_arg(ap, int);
+ break;
+ case 2:
+ val=va_arg(ap, long);
+ break;
+ }
+ fputs((__const char *)__numout(val,base),stream);
+ }
+ break;
+ case 's':
+ {
+ char *cp;
+ cp=va_arg(ap, char *);
+ while(*cp)
+ putc(*cp++, stream);
+ break;
+ }
+ case 'c':
+ putc(va_arg(ap, int), stream);
+ break;
+ default:
+ putc(c, stream);
+ }
+ }
+ }
+ return count;
+}
+
+
+int
+fprintf(FILE * stream, __const char * fmt, ...)
+{
+ va_list ap;
+ int retval;
+ va_start(ap, fmt);
+ retval=internal_fprintf(stream, fmt, ap);
+ va_end(ap);
+ return(retval);
+}
+
+int
+printf(__const char * fmt, ...)
+{
+ va_list ap;
+ int retval;
+ va_start(ap, fmt);
+ retval=internal_fprintf(stdout, fmt, ap);
+ va_end(ap);
+ return(retval);
+}
+
+/* This is a strange way of doing sprintf, but it should work */
+int sprintf(char * s, __const char * fmt, ...)
+{
+ static FILE the_sprintf = {
+ -1,
+ 0,
+ 0,
+ 0,
+ 0,
+ _IOFBF,
+ _MODE_WRITE,
+ 0, 0,
+ 0, 0};
+ va_list ap;
+ int retval;
+
+ va_start(ap, fmt);
+ the_sprintf.bufstart = the_sprintf.bufpos = (unsigned char *) s;
+ the_sprintf.fc_err = 0;
+
+ retval = internal_fprintf(&the_sprintf, fmt, ap);
+ /* null-terminate the string */
+ putc('\0', &the_sprintf);
+
+ va_end(ap);
+ return retval;
+}
+
+
+
+
+
diff --git a/libc/stdio1/printf.c b/libc/stdio1/printf.c
new file mode 100644
index 0000000..f2a39bd
--- /dev/null
+++ b/libc/stdio1/printf.c
@@ -0,0 +1,649 @@
+/* fprintf.c for limited Linux libc
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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.
+ */
+/* Thanks Alan for writing the hard routine for me :-)
+ * Alan said that this works "most of the time". Something tells me I'm making
+ * it even worse! */
+/* The basic idea here is to make fprintf the core routine. printf obviously
+ can just call fprintf with stdout followed by all of its arguments.
+ sprintf() works using the fake file &the_sprintf. It's marked as fully
+ buffered, so that it will only write(2) when &the_sprintf->bufpos ==
+ &the_sprintf->bufend, which I doubt will happen since &the_sprintf->bufend
+ = 0. The trick is that sprintf must set &the_sprintf->bufstart =
+ &the_sprintf->bufpos = its first argument. Not as orthagonal (is that
+ the right word?) as glibc's facilities for non-files, but this isn't a
+ library for people who have unlimited RAM budgets. (not like the libc
+ I use on linux/i586 enjoys an unlimited RAM budget either; I only have
+ 8 MB
+
+ I'm not sure what the "correct" way to pass the variable arguments
+ from one function to the next is. Rather than pass the arguments
+ themselves, I'm passing a pointer to them. However, the following
+ explaination from Alan is probably a polite way of saying it will not
+ work on a 386 anyway.
+ Joel Weber
+
+ [ I've migrated all of this code over to the ELKS stdarg that I wrote.
+ The accepted way to do it is for the wrapper function to accept a
+ variable number of arguments, use stdarg to make an argument pointer,
+ and then pass the argument pointer on to the core function, as I've
+ done here. This should definitely work on a 386, as the arguments
+ are still passed in the stack, and stack order is maintained. -Nat ]
+ */
+
+/*
+ * This is NOT stunningly portable, but works
+ * for pretty dumb non ANSI compilers and is
+ * tight. Adjust the sizes to taste.
+ *
+ * Illegal format strings will break it. Only the
+ * following simple subset is supported
+ *
+ * %x - hex
+ * %d - decimal
+ * %s - string
+ * %c - char
+ *
+ * And the h/l length specifiers for %d/%x
+ *
+ * Alan Cox.
+ */
+
+#include <stdarg.h>
+#include "stdio.h"
+
+/* 17 to make sure that there's room for the trailing newline.
+ I'm not really sure if this is ideal... */
+static char nstring[17]="0123456789ABCDEF";
+
+static unsigned char *
+__numout(long i, int base)
+{
+ static unsigned char out[16];
+ int n;
+ int flg = 0;
+ unsigned long val;
+
+ if (i<0 && base==10)
+ {
+ flg = 1;
+ i = -i;
+ }
+ val = i;
+
+ for (n = 0; n < 15; n++)
+ out[n] = ' ';
+ out[15] = '\0';
+ n = 14;
+ do{
+ out[n] = nstring[val % base];
+ n--;
+ val /= base;
+ }
+ while(val);
+ if(flg) out[n--] = '-';
+ return &out[n+1];
+}
+
+int
+fprintf(FILE * stream, __const char * fmt, ...)
+{
+ va_list ap;
+ int retval;
+ va_start(ap, fmt);
+ retval=internal_fprintf(stream, fmt, ap);
+ va_end(ap);
+ return(retval);
+}
+
+int
+printf(__const char * fmt, ...)
+{
+ va_list ap;
+ int retval;
+ va_start(ap, fmt);
+ retval=internal_fprintf(stdout, fmt, ap);
+ va_end(ap);
+ return(retval);
+}
+
+/* This is a strange way of doing sprintf, but it should work */
+int sprintf(char * s, __const char * fmt, ...)
+{
+ static FILE the_sprintf = {
+ -1,
+ 0,
+ 0,
+ 0,
+ 0,
+ _IOFBF,
+ _MODE_WRITE,
+ 0, 0,
+ 0, 0};
+ va_list ap;
+ int retval;
+
+ va_start(ap, fmt);
+ the_sprintf.bufstart = the_sprintf.bufpos = (unsigned char *) s;
+ the_sprintf.fc_err = 0;
+
+ retval = internal_fprintf(&the_sprintf, fmt, ap);
+ /* null-terminate the string */
+ putc('\0', &the_sprintf);
+
+ va_end(ap);
+ return retval;
+}
+
+
+
+
+
+/*
+ * printf.c - This is the more complete fprintf() replacement for libc8086
+ * Copyright (C) 1996 Steven Huang <sthuang@hns.com>.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/*
+ * This decides if the little test main program gets included
+ */
+#undef TEST
+/*
+ * This decides if printf() should act like standard. When undefined,
+ * - prints out "(err)" if a bad format is encountered
+ * - supports the %b (binary) format
+ */
+#define STANDARD
+
+/*
+ * Shut bcc up about 'const', which doesn't seem to be handled right
+ * by unproto.
+ */
+#ifdef __BCC__
+#define const
+#endif
+
+#define BUF_SIZE 128
+#define OUTC(c) { putc(c, stream); n++; }
+#define max(a, b) ((a > b) ? a : b)
+/*
+ * if you change the ff, you need to change the order of characters in
+ * the string 'flagstr' defined in _printf()
+ */
+#define FLAG_PADZERO (1<<0)
+#define FLAG_LEFTJUST (1<<1)
+#define FLAG_SIGNED (1<<2)
+#define FLAG_ALT (1<<3)
+#define FLAG_SPACE (1<<4)
+
+static char *utoa(unsigned int val, char *buf, int radix)
+/*
+ * Converts an integer to a variable-radix string representation
+ *
+ * Note:
+ * Does not perform sanity checking for 'radix'
+ * Assumes 'buf' has memory allocated to it
+ */
+{
+ int divisor;
+ char *p = buf;
+ const char *digitstr = "0123456789abcdef";
+
+ for (divisor = 1; val / divisor >= radix; divisor *= radix);
+ do {
+ *p++ = digitstr[val / divisor];
+ val %= divisor;
+ divisor /= radix;
+ } while (divisor >= 1);
+ *p = '\0';
+ return(buf);
+}
+
+static
+internal_fprintf(FILE * stream, const char * fmt, char *args)
+
+/* static int _printf(FILE *stream, const char *fmt, char *args) */
+/*
+ * The one that does all the work.
+ * This is a fairly complete implementation of printf(), supporting
+ * everything EXCEPT:
+ * - floating point (eEDOUfg formats)
+ * - pointers (realizes them but doesn't understand how to print them)
+ * - short and long (h/l) modifiers (dunno what to do about them)
+ * It's even slightly faster than gcc's printf() on Linux. Can't beat
+ * HP-UX's printf() though ;)
+ *
+ * Supports:
+ * d, signed integer
+ * i
+ * o unsigned octal integer
+ * u unsigned integer
+ * x unsigned hex lowercase a-f
+ * X unsigned hex uppercase A-F
+ * c character
+ * s string (character pointer)
+ * p void pointer (ignores it)
+ * % % character
+ * n number of characters output so far
+ *
+ * Special feature: (no really, it's not a bug =) )
+ * b prints an integer in binary form (i think this might come
+ * in handy *somewhere*)
+ *
+ * # alternate format for octal (leading 0) and hex (0x/0X)
+ * 0 leading zeroes for d, i, o, u, x, and X
+ * - left justify, overrides '0'
+ * ' ' (space) force a blank in front of positive numbers
+ * + force a sign in front of any number
+ *
+ * width.precision, including support for '*' (reads value from
+ * the parameter list (MUST BE INT))
+ *
+ * h, short/long modifiers, recognized but ignored.
+ * l
+ *
+ * Warning:
+ * The way varargs is implemented in libc is evil. Don't think
+ * there's a better way, but misaligned or wrong parameters
+ * passed to printf() can break a lot of things. I've tried my
+ * best to handle errors in the format string, though.
+ *
+ * Each %something field cannot exceed 'BUF_SIZE' characters,
+ * which I set to 128 right now. %s fields are not subject to
+ * this limit.
+ *
+ * Note:
+ * The semicolon -looks- missing in a few places but that's
+ * because of the macro def of 'OUTC'. did it that way to
+ * save a few lines of source ;)
+ *
+ * Expects a 'char *' as varargs parameter, unlike libc8086's
+ * printf(), which takes a 'int *' then casts it to a 'char *'.
+ * Either has to change, but it should be trivial.
+ *
+ * This function aborts whenever it scans an illegal format, unlike
+ * gcc's libc which prints out the illegal format as if it's -not-
+ * a format string. The 'STANDARD' preprocessor flag controls if
+ * if just aborts (when defined) or prints out "(err)" (when undefined).
+ */
+{
+ /*
+ * the "0-+# " and "dcs..." strings are listed in my idea of their
+ * frequency of use, with the most popular in front. not terribly
+ * important but strchr() might have an easier time that way.
+ * if you change the ordering of 'flagstr', make sure you update
+ * the #define FLAG_* stuff on top of this file too.
+ */
+ char c, *s, *f;
+ const char *flagstr = "0-+# ",
+#ifdef STANDARD
+ *typestr = "dcsixXuop";
+#else
+ *typestr = "dcsixXuopb";
+#endif
+ int n = 0, flags, width, actwidth, prec, bad = 0, neg, i;
+ static char buf[BUF_SIZE];
+
+ for (c = *fmt++; c && !bad;) {
+ if (c != '%') { /* just copy */
+ OUTC(c);
+ c = *fmt++;
+ }
+ else {
+ c = *fmt++; /* chew the % sign */
+ flags = width = prec = 0;
+ /*
+ * Parse the "0-+# " flags
+ */
+ while ((f = strchr(flagstr, c)) != NULL) {
+ flags |= 1 << (f - flagstr);
+ c = *fmt++;
+ }
+ /*
+ * The '*' parameter says fetch width value from varargs
+ */
+ if (c == '*') {
+ width = *(int *) args;
+ args += sizeof(int);
+ if (width < 0) {
+ width = abs(width);
+ flags |= FLAG_LEFTJUST; /* set '-' flag */
+ }
+ c = *fmt++;
+ }
+ else
+ /*
+ * scan and convert the width parameter
+ */
+ if (isdigit(c))
+ while (isdigit(c)) {
+ width *= 10;
+ width += c - '0';
+ c = *fmt++;
+ }
+ /*
+ * a '.' means there may be a precision parameter
+ */
+ if (c == '.') {
+ c = *fmt++;
+ /*
+ * fetch precision value from varargs
+ */
+ if (c == '*') {
+ prec = *(int *) args;
+ if (prec < 0)
+ prec = 0;
+ args += sizeof(int);
+ c = *fmt++;
+ }
+ else
+ /*
+ * scan and convert precision field
+ */
+ if (isdigit(c))
+ while (isdigit(c)) {
+ prec *= 10;
+ prec += c - '0';
+ c = *fmt++;
+ }
+ }
+ /*
+ * short and long modifiers. ignored for the moment
+ */
+ if (c == 'h') {
+ c = *fmt++;
+ }
+ else
+ if (c == 'l') {
+ c = *fmt++;
+ }
+ /*
+ * check if it's a valid type "dioux..."
+ */
+ if (strchr(typestr, c) != NULL) {
+ neg = 0;
+ switch (c) {
+ case 'd':
+ case 'i': {
+ int val = *(int *) args;
+ args += sizeof(int);
+ neg = (val < 0);
+ val = abs(val);
+ actwidth = strlen(utoa(val, buf, 10)); }
+ /*
+ * if negative or '+'/' ' flags set
+ */
+ if (neg || (flags & FLAG_SIGNED) || (flags & FLAG_SPACE))
+ actwidth++;
+ break;
+ case 'u': {
+ unsigned int uval = *(unsigned int *) args;
+ args += sizeof(unsigned int);
+ actwidth = strlen(utoa(uval, buf, 10)); }
+ /*
+ * if '+'/' ' flags set
+ */
+ if ((flags & FLAG_SIGNED) || (flags & FLAG_SPACE))
+ actwidth++;
+ break;
+ case 'x':
+ case 'X': {
+ int val = *(int *) args;
+ args += sizeof(int);
+ actwidth = strlen(utoa(val, buf, 16)); }
+ if (flags & FLAG_ALT)
+ actwidth += 2;
+ break;
+ case 'o': {
+ int val = *(int *) args;
+ args += sizeof(int);
+ actwidth = strlen(utoa(val, buf, 8)); }
+ if (flags & FLAG_ALT)
+ actwidth++;
+ break;
+ case 's':
+ s = *(char **) args;
+ args += sizeof(char *);
+ actwidth = strlen(s);
+ break;
+ case 'c':
+ buf[0] = *(char *) args;
+ buf[1] = '\0';
+ args += sizeof(char);
+ actwidth = 1;
+ break;
+ /*
+ * dunno how to handle pointers - what's the format of
+ * linux86 pointers?! right now just prints "(ptr)"
+ */
+ case 'p':
+ strcpy(buf, "(ptr)");
+ args += sizeof(void *);
+ actwidth = strlen(buf);
+ s = buf; /* pretend we're a string */
+ c = 's';
+ break;
+#ifndef STANDARD
+ case 'b': {
+ int val = *(int *) args;
+ args += sizeof(int);
+ actwidth = strlen(utoa(val, buf, 2)); }
+ break;
+#endif
+ }
+ /*
+ * strings behave differently to the width.precision
+ * parameters, so handle separately. besides, we avoid
+ * an extra 'memcpy' to 'buf'
+ */
+ if (c == 's') {
+ if (prec == 0)
+ prec = actwidth;
+ width = max(width, prec);
+ /*
+ * pad to the left if not left justified
+ */
+ if (!(flags & FLAG_LEFTJUST)) {
+ for (i = width; i > prec; i--)
+ OUTC(' ');
+ }
+ /*
+ * print out entire string if no precision specified, otherwise
+ * that's our upper limit
+ */
+ if (prec == 0)
+ for (; *s; s++)
+ OUTC(*s) /* no semicolon here */
+ else
+ for (i = 0; i < prec; i++)
+ OUTC(s[i]);
+ }
+ else {
+ /*
+ * precision is as wide as width if it's not specified and
+ * the leading zero '0' flag is set, and left-justify is
+ * -not- set. c standard says left justify overrides the
+ * leading 0.
+ */
+ if (prec == 0 && (flags & FLAG_PADZERO) && !(flags & FLAG_LEFTJUST))
+ prec = width;
+ /*
+ * expand width.precision to fit the actual width. printf
+ * width specifies the -minimum-, and aside from the
+ * precision of %s fields, there's no way to specify maximum
+ */
+ prec = max(prec, actwidth);
+ width = max(width, prec);
+ /*
+ * pad to the left if we're not left justified
+ */
+ if (!(flags & FLAG_LEFTJUST)) {
+ for (i = width; i > prec; i--)
+ OUTC(' ');
+ }
+ /*
+ * check if we might need to print the sign
+ */
+ if (strchr("diu", c) != NULL) {
+ if (neg) /* print if negative */
+ OUTC('-') /* yes, no ';' here =) */
+ else
+ if (flags & FLAG_SIGNED) /* or '+' specified */
+ OUTC('+') /* nor here */
+ else
+ if (flags & FLAG_SPACE) /* or ' ' specified */
+ OUTC(' ') /* nor here */
+ }
+ /*
+ * the alternate '#' flag is set. doesn't affect all though
+ */
+ if (flags & FLAG_ALT) {
+ switch (c) {
+ case 'o':
+ OUTC('0'); /* leading zero for octals */
+ break;
+ case 'x':
+ case 'X': /* prints 0x or 0X */
+ OUTC('0');
+ OUTC(c);
+ break;
+ }
+ }
+ /*
+ * fill the precision field with either spaces or zeroes,
+ * depending if we're printing numbers
+ */
+ if (strchr("diuxXo", c) != NULL)
+ for (i = prec; i > actwidth; i--)
+ OUTC('0')
+ else
+ for (i = prec; i > actwidth; i--)
+ OUTC(' ');
+ /*
+ * print the field, except for 'X', which we convert to caps
+ */
+ if (c != 'X')
+ for (f = buf; *f; f++)
+ OUTC(*f) /* none here either */
+ else
+ for (f = buf; *f; f++)
+ OUTC(toupper(*f));
+ }
+ /*
+ * if we're left justified, we now need to pad spaces to the
+ * right so that width will be correct
+ */
+ if (flags & FLAG_LEFTJUST)
+ for (i = width; i > prec; i--)
+ OUTC(' ');
+ }
+ else {
+ /*
+ * miscellaneous %thingies
+ */
+ switch (c) {
+ case '%': /* %% -> % */
+ OUTC('%');
+ break;
+ case 'n': /* %n writes current output count */
+ *(*(int **) args) = n;
+ args += sizeof(int *);
+ break;
+ default: /* oops, got a bad %thingy */
+ bad = 1;
+ }
+ }
+ c = *fmt++;
+ }
+ }
+#ifndef STANDARD
+ /*
+ * dunno what the standard wants if the format string is badly
+ * formed, so i print (err) if the debug flag is set
+ */
+ if (bad) {
+ OUTC('(');
+ OUTC('e');
+ OUTC('r');
+ OUTC('r');
+ OUTC(')');
+ }
+#endif
+ return(n);
+}
+
+#ifdef TEST
+
+#include <time.h>
+
+int main()
+{
+ static unsigned char xbuf[128], *x;
+ char *fmt = "%s, %s %d, %.*d:%.*d\n";
+ int rv1, rv2, i, dt1, dt2;
+ clock_t t1, t2;
+
+ x = xbuf;
+ *(char **) x = "Sun";
+ x += sizeof(char *);
+ *(char **) x = "Feb";
+ x += sizeof(char *);
+ *(int *) x = 18;
+ x += sizeof(int);
+ *(int *) x = 2;
+ x += sizeof(int);
+ *(int *) x = 10;
+ x += sizeof(int);
+ *(int *) x = 2;
+ x += sizeof(int);
+ *(int *) x = 56;
+ x += sizeof(int);
+ t1 = clock();
+ for (i = 0; i < 1000; i++)
+ rv1 = _printf(stdout, fmt, xbuf);
+ t2 = clock();
+ dt1 = t2 - t1;
+
+ t1 = clock();
+ for (i = 0; i < 1000; i++)
+ rv2 = printf(fmt, "Sun", "Feb", 18, 2, 10, 2, 56);
+ t2 = clock();
+ dt2 = t2 - t1;
+
+ printf("\nrv1: %d, rv2: %d, dt1: %d, dt2: %d\n", rv1, rv2, dt1, dt2);
+ return(0);
+}
+
+#endif
diff --git a/libc/stdio1/puts.c b/libc/stdio1/puts.c
new file mode 100644
index 0000000..d9bb8d0
--- /dev/null
+++ b/libc/stdio1/puts.c
@@ -0,0 +1,26 @@
+/* simplified linux puts.c
+ 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 "stdio.h"
+
+int puts (string)
+char *string;
+{
+ fputs(string, stdout);
+ putc('\n', stdout);
+ return 0;
+}
diff --git a/libc/stdio1/scanf.c b/libc/stdio1/scanf.c
new file mode 100644
index 0000000..81900a1
--- /dev/null
+++ b/libc/stdio1/scanf.c
@@ -0,0 +1,151 @@
+/* scanf.c for limited Linux libc
+ Copyright (C) 1996 Joel N. Weber II <nemo@koa.iolani.honolulu.hi.us>
+
+ 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.
+ */
+
+/* This scanf code was derived from my printf code, which in turn was
+ * derived from Alan Cox's printk. It was tested by [no one so far...]
+ */
+
+/* Disclaimer: I haven't even THOUGHT about testing this. If you do decide
+ * to be brave and test it, and it doesn't work, you have the following
+ * options:
+ * o Send me mail telling me it doesn't work, which I will ignore
+ * since I already knew that.
+ * o Fix it yourself
+ * o isolate the problem and send it to the list, and maybe
+ * I'll fix it
+ */
+
+/* BTW, the above comment may be destroyed once this has been tested. It's
+ * not nessisary for my great great grandchildren to see it when they
+ * take Ancient Linux History...
+ */
+
+/* Incidentally, if it doesn't work, it may well be because I never bothered
+ * to learn how to use scanf()...I briefly tried it for the usaco qualification
+ * round, but had some wierd problems...ask me after mid February...BTW the
+ * problems had nothing to do with scanf(); it was still broken (hopelessly)
+ * when I went to getchar().
+ */
+
+/* Note, too that the current version probably assumes some things with
+ * variable argument handling that it shouldn't. Don't expect this to
+ * work on a 386 in 32 bit mode, don't expect this to work on a Z80,
+ * or anything other than an 8086. In fact, don't expect it to even
+ * work on an 8086 ;-)
+ */
+
+/* One of these days the headers will work painlessly... */
+/* #include <linuxmt/types.h> */
+/* #include <linuxmt/fcntl.h> */
+#include "stdio.h"
+
+/* note that we assume base == 10... */
+static int numin(int *num, int base, FILE *stream, int c)
+{
+ if ((c < '0') || (c > '9')) return 0;
+ *num = 0;
+ while ((c >= '0') && (c <= '9')) {
+ *num = *num * base + c - '0';
+ c = getc(stream);
+ }
+ ungetc(c, stream);
+}
+
+/* currently, the h/l specifications are ignored */
+static int internal_scanf(stream,fmt,a1)
+FILE *stream;
+char *fmt;
+int *a1;
+{
+ unsigned char *p=(char *)a1;
+ char c;
+ int inc;
+ int count = 0;
+
+ while(c=*fmt++)
+ {
+ do {
+ inc = getc(stream);
+ } while ((inc == ' ') || (inc == '\t') || (inc == '\n'));
+
+ if ((c == '\n') || (c == '\t') || (c == ' '))
+ ;
+ else if (c!='%') {
+ if (c != inc) {
+ ungetc(inc, stream);
+ return count;
+ }
+ } else {
+ int len=2;
+ c=*fmt++;
+ if(c=='h') c=*fmt++;
+ else if(c=='l') c=*fmt++;
+
+ switch(c)
+ {
+ case 'x':
+ if (numin(p, 16, stream, inc)) count++;
+ else return count;
+ p+=2;
+ break;
+ case 'd':
+ if (numin(p, 10, stream, inc)) count++;
+ else return count;
+ p+=2;
+ break;
+ case 's':
+ {
+ char *cp=*((char **)p);
+ p+=sizeof(char *);
+ while(*cp)
+ putc(cp++, stream);
+ while ((inc != ' ') && (inc != '\t')
+ && (inc != '\n') && (inc != EOF)) {
+ *cp++ = inc;
+ inc = getc(stream);
+ }
+ ungetc(inc, stream);
+ break;
+ }
+ case 'c':
+ *p++ = inc;
+ p++;
+ break;
+ default:
+ putc('?', stream);
+ }
+ }
+ }
+ return count;
+}
+
+
+int fscanf(stream,fmt,a1)
+FILE *stream;
+char *fmt;
+int a1;
+{
+ return internal_fscanf(stream,fmt,&a1);
+}
+
+int scanf(fmt,a1)
+char *fmt;
+int a1;
+{
+ return internal_fscanf(stdout,fmt,&a1);
+}
diff --git a/libc/stdio1/stdio.h b/libc/stdio1/stdio.h
new file mode 100644
index 0000000..4bd1989
--- /dev/null
+++ b/libc/stdio1/stdio.h
@@ -0,0 +1,135 @@
+/* simplified linux stdio.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 <fcntl.h>
+#include <sys/types.h>
+#include <malloc.h>
+
+#ifndef __STDIO_H
+#define __STDIO_H
+
+/* when you add or change fields here, be sure to change the initialization
+ * in stdio_init and fopen */
+struct __stdio_file {
+ int fd; /* the file descriptor associated with the stream */
+ unsigned char *bufstart; /* the start of the buffer */
+ 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 *bufend; /* the end of the buffer; ie the byte after the last
+ malloc()ed byte */
+ int buffer_mode;
+#define _IONBF 0xB111 /* no buffering */
+#define _IOLBF 0xB112 /* line buffering */
+#define _IOFBF 0xB113 /* full buffering */
+ int file_mode;
+#define _MODE_READ 0xB121
+#define _MODE_WRITE 0xB122
+#define _MODE_RDWR 0xB124 /* used when a file is readwrite and is ord with
+ what's in the buffer now */
+ unsigned char ungetted, ungetchar;
+ /* ungetted = 1 if there's data unread; else 0
+ ungetchar contains the character */
+ int fc_eof:1;
+ int fc_err:1; /* eof and error conditions */
+ int iotrans:1; /* Translate \n -> \r\n on MSDOS */
+};
+
+#define EOF (-1)
+
+typedef struct __stdio_file FILE;
+
+#define BUFSIZ 256
+
+extern FILE *stdin, *stdout, *stderr, *__stdsprintf;
+
+/* The following macros are used for all access to the buffers. If you
+ * know the file is unbuffered, however, you may write to it directly, as
+ * fputs.c does. However, be aware that sprintf assumes that by setting
+ * bufend to 0, no file writing will occur. Also, since NO streams use
+ * unbuffered mode by default and the function to change this behavior is
+ * not implemented yet, I'm considering disallowing raw access at the cost
+ * of having each byte of a string written individually. However, that
+ * IS what you're asking for with non-buffered mode.
+ *
+ * RDB: It's considered very bad form to use the raw read() & write()
+ * calls on the same files you use the stdio functions.
+ */
+#ifdef __MSDOS__
+#define putc(c, fp) fputc(c, fp)
+#define getc(fp) fgetc(fp)
+#else
+#define putc(c, stream) \
+ (((stream)->bufpos[0] = (c)), \
+ ((stream)->bufpos++), \
+ ((((stream)->bufpos == (stream)->bufend) \
+ ||((stream)->buffer_mode == _IONBF) \
+ ||(((stream)->buffer_mode == _IOLBF) \
+ && ((stream)->bufpos != (stream)->bufstart) \
+ && ((stream)->bufpos[-1] == '\n'))) \
+ ? fflush(stream):0))
+
+#define getc(stream) \
+ ((stream)->ungetted ? (((stream)->ungetted = 0), ((stream)->ungetchar)) : \
+ (((stream)->bufpos == (stream)->bufread)?__ffillbuf(stream): \
+ (*(stream)->bufpos++)))
+
+#endif
+
+#define putchar(c) putc((c), stdout)
+#define getchar() getc(stdin)
+#define ungetc(c, stream) (((stream)->ungetted = 1), ((stream)->ungetchar = c))
+
+#define ferror(fp) ((fp)->fc_err)
+#define feof(fp) ((fp)->fc_eof)
+
+#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
+ */
+
+#ifndef __P
+#define __P(x) ()
+#endif
+
+int setvbuf __P((FILE*, char*, int, size_t));
+int __ffillbuf __P((FILE*));
+void __stdio_init __P((void));
+int fclose __P((FILE*));
+int fflush __P((FILE*));
+int fgetc __P((FILE*));
+char *fgets __P((char*, size_t, FILE*));
+FILE *fopen __P((char*, char*));
+
+int fputc __P((int, FILE*));
+int fputs __P((__const char*, FILE*));
+char *idealgetline __P((FILE*));
+int puts __P((char*));
+
+int printf __P ((__const char *, ...));
+int fprintf __P ((FILE *, __const char *, ...));
+int sprintf __P ((char *, __const char *, ...));
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+
+#endif /* __STDIO_H */
+/* TODO: add scanf, fscanf */
diff --git a/libc/stdio1/test.sh b/libc/stdio1/test.sh
new file mode 100755
index 0000000..9d872dc
--- /dev/null
+++ b/libc/stdio1/test.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+echo 'rm -f *.o test *.a'
+rm -f *.o test *.a
+echo 'make'
+make
+echo 'ar r libnat.a *.o'
+ar r libnat.a *.o
+echo 'ranlib libnat.a'
+ranlib libnat.a
+echo 'gcc test.c -I- -I../include -fno-builtin -o test.o -L./ -lnat'
+gcc test.c -I- -I../include -fno-builtin -o test.o -L./ -lnat
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..56b9862
--- /dev/null
+++ b/libc/stdio2/Makefile
@@ -0,0 +1,39 @@
+
+TOP=..
+include $(TOP)/Make.defs
+
+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 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)
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+transfer:
+ -@rm -f ../include/stdio.h
+ cp -p stdio.h ../include/.
+
+clean:
+ rm -f *.o libc.a
+
+$(AOBJ): $(ASRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ASRC)
+
+$(POBJ): $(PSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(PSRC)
+
+$(SOBJ): $(SSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(SSRC)
+
diff --git a/libc/stdio2/printf.c b/libc/stdio2/printf.c
new file mode 100644
index 0000000..0d107a4
--- /dev/null
+++ b/libc/stdio2/printf.c
@@ -0,0 +1,362 @@
+/*
+ * 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>
+#include <stdarg.h>
+
+#include "stdio.h"
+
+#ifdef L_printf
+
+#ifdef __STDC__
+int printf(const char * fmt, ...)
+#else
+int printf(fmt)
+__const char *fmt;
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_start(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)
+char * sp;
+__const char *fmt;
+#endif
+{
+static FILE string[1] =
+{
+ {0, 0, (char*)(unsigned) -1, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_WRITE}
+};
+
+ va_list ptr;
+ int rv;
+ va_start(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)
+FILE * fp;
+__const char *fmt;
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_start(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
+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;
+#if FLOATS
+ double fx;
+#endif
+
+ /* 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;
+
+#if FLOATS
+ case 'e': /* float */
+ case 'f':
+ case 'g':
+ case 'E':
+ case 'G':
+ fx = va_arg(ap, double);
+ fp_print(fx, *fmt, preci, ptmp);
+ preci = -1;
+ goto printit;
+#endif
+
+ 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;
+
+ 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..c43320d
--- /dev/null
+++ b/libc/stdio2/scanf.c
@@ -0,0 +1,511 @@
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef L_scanf
+#ifdef __STDC__
+int scanf(const char * fmt, ...)
+#else
+int scanf(fmt)
+__const char *fmt;
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_start(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)
+char * sp;
+__const char *fmt;
+#endif
+{
+static FILE string[1] =
+{
+ {0, (char*)(unsigned) -1, 0, 0, (char*) (unsigned) -1, -1,
+ _IOFBF | __MODE_READ}
+};
+
+ va_list ptr;
+ int rv;
+ va_start(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)
+FILE * fp;
+__const char *fmt;
+#endif
+{
+ va_list ptr;
+ int rv;
+ va_start(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..062a982
--- /dev/null
+++ b/libc/stdio2/stdio.c
@@ -0,0 +1,739 @@
+/* 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 */
+
+#ifndef __AS386_16__
+#define Inline_init __io_init_vars()
+#else
+#define Inline_init
+#endif
+
+#ifdef L__stdio_init
+
+FILE *__IO_list = 0; /* For fflush at exit */
+
+static char bufin[BUFSIZ];
+static char bufout[BUFSIZ];
+static char buferr[BUFSIZ];
+
+/* #define buferr (stderr->unbuf) /* Stderr is unbuffered */
+
+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 */
+
+#ifndef __AS386_16__
+#define STATIC
+#else
+#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
+ .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
+
+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__
+ static int first_time = 1;
+ if( !first_time ) return ; first_time = 1;
+#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 */
+ /*
+ * TODO: if __MODE_READING and no ungetc ever done can just move
+ * pointer
+ */
+
+ 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_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;
+
+ 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..ba70b1d
--- /dev/null
+++ b/libc/stdio2/stdio.h
@@ -0,0 +1,125 @@
+
+#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;
+
+#define BUFSIZ (256)
+
+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..d72c2e0
--- /dev/null
+++ b/libc/string/Makefile
@@ -0,0 +1,31 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+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
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+transfer:
+ -@rm -f ../include/string.h
+ cp -p string.h ../include/.
+
+clean:
+ rm -f *.o libc.a
+
+$(SOBJ): $(SSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(SSRC)
+
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..fad6690
--- /dev/null
+++ b/libc/string/string.c
@@ -0,0 +1,667 @@
+/* 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
+#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(s);
+ 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
+#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..2cc4494
--- /dev/null
+++ b/libc/syscall/Makefile
@@ -0,0 +1,44 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+LSRC=syslibc.c
+LOBJ=__cstartup.o time.o lseek.o getpid.o getppid.o \
+ getuid.o geteuid.o getgid.o getegid.o \
+ dup2.o dup.o abort.o wait.o waitpid.o sleep.o
+
+ESRC=execve.c
+EOBJ=execve.o execl.o execv.o execle.o
+
+DSRC=dirent.c
+DOBJ=opendir.o closedir.o readdir.o
+
+ifeq ($(PLATFORM),i86-DOS)
+OBJ=setjmp.o
+else
+OBJ=$(LOBJ) $(DOBJ) $(EOBJ) signal.o setjmp.o execve.o
+endif
+
+all: mksyscall syscall.dat $(OBJ)
+ sh mksyscall
+
+clean:
+ rm -f *.o libc.a syscall.c syscall.mak call_tab.v defn_tab.v
+
+libc.a: mksyscall syscall.dat $(OBJ)
+ sh mksyscall libc.a
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+$(LOBJ): $(LSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC)
+
+$(DOBJ): $(DSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(DSRC)
+
+$(EOBJ): $(ESRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ESRC)
+
diff --git a/libc/syscall/TODO b/libc/syscall/TODO
new file mode 100644
index 0000000..90085d9
--- /dev/null
+++ b/libc/syscall/TODO
@@ -0,0 +1,7 @@
+It appears that a 386 version of the syscall libs is also wanted ...
+
+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..bbb3c13
--- /dev/null
+++ b/libc/syscall/dirent.c
@@ -0,0 +1,84 @@
+
+#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 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
diff --git a/libc/syscall/execve.c b/libc/syscall/execve.c
new file mode 100644
index 0000000..aee7182
--- /dev/null
+++ b/libc/syscall/execve.c
@@ -0,0 +1,114 @@
+
+#include <errno.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
diff --git a/libc/syscall/getinfo.c b/libc/syscall/getinfo.c
new file mode 100644
index 0000000..a5ab89a
--- /dev/null
+++ b/libc/syscall/getinfo.c
@@ -0,0 +1,32 @@
+
+#define PERM_GETINFO 0x100
+#define PERM_GETGROUP 0x200
+
+struct {
+ int pid;
+ int ppid;
+ int uid;
+ int gid;
+ int euid;
+ int egid;
+}
+ __info_safe;
+
+getgroups(count, locn)
+int count;
+void * locn;
+{
+ if( count < 0 ) {errno = EINVAL; return -1; }
+ return __permissions(PERM_GETGROUP, count, locn);
+}
+
+getpid()
+{
+ __permissions(PERM_GETINFO, 6, &__info_safe);
+ return __info_safe.pid;
+}
+
+getppid()
+{
+ return __permissions(PERM_GETITEM(1) /*, 0, 0 */);
+}
diff --git a/libc/syscall/mksyscall b/libc/syscall/mksyscall
new file mode 100644
index 0000000..1e98836
--- /dev/null
+++ b/libc/syscall/mksyscall
@@ -0,0 +1,300 @@
+# 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 <<\!
+
+TOP=..
+include $(TOP)/Make.defs
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+$(OBJ): syscall.dat mksyscall
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ syscall.c
+!
+
+rv=$?
+if [ "$rv" != 0 ]
+then exit $rv
+fi
+
+export MAKELEVEL
+MAKELEVEL=0
+exec make -f syscall.mak $1
diff --git a/libc/syscall/setjmp.c b/libc/syscall/setjmp.c
new file mode 100644
index 0000000..52c3ff1
--- /dev/null
+++ b/libc/syscall/setjmp.c
@@ -0,0 +1,50 @@
+
+#include <setjmp.h>
+
+#if __AS386_16__
+
+int
+setjmp(env)
+jmp_buf env;
+{
+#asm
+ 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
+ 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..dbeac4a
--- /dev/null
+++ b/libc/syscall/signal.c
@@ -0,0 +1,94 @@
+
+#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;
+
+ 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..d83be4f
--- /dev/null
+++ b/libc/syscall/syscall.dat
@@ -0,0 +1,147 @@
+#
+# 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 a ptr to long not a long.
+FSTAT 28 2
+IOCTL 54 3 . Make this and fcntl the same ?
+FCNTL 55 3
+FCHMOD 94 X
+FCHOWN 95 X
+FSYNC 118 1
+FCHDIR 133 X
+LLSEEK 140 X
+READV 145 X
+WRITEV 146 X
+FLOCK 143 X - 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 1
+PROF 44 X
+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
+PHYS 52 X
+LOCK 53 X
+MPX 56 X
+SETPGID 57 2
+ULIMIT 58 2
+UMASK 60 1
+CHROOT 61 1
+USTAT 62 2
+GETPGRP 65 X
+SETSID 66 X
+SIGACTION 67 X
+SGETMASK 68 X
+SSETMASK 69 X
+SETREUID 70 X
+SETREGID 71 X
+SIGSUSPEND 72 X
+SIGPENDING 73 X
+SETHOSTNAME 74 2
+SETRLIMIT 75 X
+GETRLIMIT 76 X
+REBOOT 76 3 . The magic number is 0xfee1,0xdead,...
+GETRUSAGE 77 X
+GETGROUPS 80 2
+SETGROUPS 81 2
+SYMLINK 83 2
+LSTAT 84 2
+READLINK 85 3
+SWAPON 87 X
+REBOOT 88 X
+MUNMAP 91 X
+TRUNCATE 92 X
+FTRUNCATE 93 X
+GETPRIORITY 96 X
+SETPRIORITY 97 X
+PROFIL 98 X
+STATFS 99 X
+FSTATFS 100 X
+SOCKETCALL 102 X
+SYSLOG 103 X
+SETITIMER 104 X
+GETITIMER 105 X
+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 X
+SETFSGID 139 X
+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/syslibc.c b/libc/syscall/syslibc.c
new file mode 100644
index 0000000..1e604e8
--- /dev/null
+++ b/libc/syscall/syslibc.c
@@ -0,0 +1,330 @@
+/* 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 <time.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
+#if __CALLER_SAVES__
+ .data
+loopy_safe:
+ .word 0
+#endif
+ .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
+ 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 si,#auto_start ! Pointer to first autostart function
+auto_run:
+#if __FIRST_ARG_IN_AX__
+ mov ax,[saved_arg1]
+#endif
+#if __CALLER_SAVES__
+ mov [loopy_safe],si
+#endif
+ call [si] ! Call the function
+#if __CALLER_SAVES__
+ mov si,[loopy_safe]
+#endif
+ 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.
+#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 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 lseek ************************************/
+
+#ifdef L_lseek
+off_t lseek(fd, posn, where)
+int fd;
+off_t posn;
+int where;
+{
+ off_t __lseek();
+ 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 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 waitpid ************************************/
+
+#ifdef L_waitpid
+int
+waitpid(pid, status, opts)
+int pid;
+int * status;
+int opts;
+{
+ return wait4(pid, status, opts, (void*)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
+
+/********************** THE END ********************************************/
+
+#endif /* __AS386_16__ */
+#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..5c6d3c1
--- /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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+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
+
+OBJ=$(TOBJ) ttyname.o
+
+all: $(OBJ)
+
+ifeq ($(PLATFORM),i86-DOS)
+libc.a:
+else
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+endif
+
+clean:
+ rm -f *.o libc.a
+
+$(TOBJ): $(TSRC)
+ $(CC) $(CFLAGS) -c -DL_$* -o $@ $(TSRC)
+
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..3789c38
--- /dev/null
+++ b/libc/termios/termios.c
@@ -0,0 +1,185 @@
+/* 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
+int cfgetospeed(tp)
+struct termios *tp;
+{
+ return (tp->c_cflag & CBAUD);
+}
+#endif
+
+#ifdef L_cfgetispeed
+int 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
+
+#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/tests/Config b/libc/tests/Config
new file mode 100644
index 0000000..4bdf884
--- /dev/null
+++ b/libc/tests/Config
@@ -0,0 +1,2 @@
+
+tools: These are tools to test libc - make directly
diff --git a/libc/tests/Makefile b/libc/tests/Makefile
new file mode 100644
index 0000000..37e57b8
--- /dev/null
+++ b/libc/tests/Makefile
@@ -0,0 +1,20 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+CFLAGS=$(CCFLAGS) -ansi
+
+default: all
+
+libc.a:
+ @echo -n
+
+include Real_make
+
+fetch_them:
+ cp -p $(SRC) Real_make $(TOPDIR)/tests/.
+
+clean:
+ rm -f $(OBJ) $(EXE) $(LINK_FILES)
diff --git a/libc/tests/README b/libc/tests/README
new file mode 100644
index 0000000..642e636
--- /dev/null
+++ b/libc/tests/README
@@ -0,0 +1,19 @@
+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.
+
+These are user level tools, they're being used to test libc routines.
+
+env.c Prints the environment and arguments (Plus some junk)
+compr.c Mini compression program (rather slow at times)
+ucomp.c Mini uncompression program (Very fast)
+ft.c Multiple simple file tools.
+hd.c Hex dump.
+line2.c Print lines from /etc/passwd (stdio)
+lines.c Print lines from /etc/passwd
+ouch.c Signal test
+size.c Size of executables and object files.
+sync.c :-)
+wc.c Word count.
+
+-Robert
diff --git a/libc/tests/Real_make b/libc/tests/Real_make
new file mode 100644
index 0000000..38c4232
--- /dev/null
+++ b/libc/tests/Real_make
@@ -0,0 +1,19 @@
+# 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.
+
+SRC=env.c ft.c hd.c size.c sync.c compr.c ucomp.c ouch.c lines.c \
+ wc.c line2.c rand.c grab.c
+OBJ=
+EXE=env ft hd size sync compr ucomp ouch lines wc line2 rand grab
+
+LINK_FILES=cat chgrp chmod chown cp install ln mkdir mkfifo mknod mv rm
+
+all: $(EXE)
+
+links:
+ for i in $(LINK_FILES) ; do ln -s ft $$i ; done
+
+no_links:
+ rm -f $(LINK_FILES)
+
diff --git a/libc/tests/compr.c b/libc/tests/compr.c
new file mode 100644
index 0000000..8e53443
--- /dev/null
+++ b/libc/tests/compr.c
@@ -0,0 +1,383 @@
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#define MAXNO 32767
+#define MAXLEN 127
+#define XXQSCAN /* Speed up scanning at the cost of not being optimal */
+
+unsigned char *fptr;
+unsigned short *vptr;
+FILE * fd;
+
+#define ITBSIZE 4096
+#define itbfunc() (ptr[mainscan]^(ptr[mainscan+1]<<4)^(ptr[mainscan+2]<<2))
+/*
+#define ITBSIZE 4001
+#define itbfunc() ((ptr[mainscan]+ptr[mainscan+1]*79+ptr[mainscan+2]*307)%4001)
+*/
+int * itb;
+
+int size;
+int maxno= 8000;
+long cnt=0;
+
+long icount = 0;
+long ocount = 0;
+
+unsigned char key;
+
+int fl;
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+ if( argc < 2 ) { fprintf(stderr, "Usage; ... \n"); exit(1); }
+
+ if( argc == 3 )
+ {
+ maxno = atoi(argv[2]);
+ if( maxno < 256 ) maxno = 256;
+ if( maxno > MAXNO) maxno = MAXNO;
+ }
+
+ if( strcmp(argv[1], "-") == 0 )
+ fd = stdin;
+ else
+ fd = fopen(argv[1], "r" );
+ if( fd == 0 ) { perror("Open failed\n"); exit(1); }
+
+ fptr = (unsigned char * ) malloc((unsigned)maxno*2);
+ itb = (int * ) malloc(ITBSIZE*sizeof(int));
+ if( itb )
+ vptr = (unsigned short * ) malloc((unsigned)maxno * sizeof(short)*2 );
+ else
+ vptr = 0;
+
+ if( fptr == 0 )
+ {
+ perror("Cannot allocate RAM");
+ exit(1);
+ }
+ if( vptr == 0 && itb ) free(itb);
+
+ fl = 0;
+ {
+ if( (size = fread(fptr, 1, (int)maxno, fd )) < 0 ) { fprintf(stderr, "\nRead failed\n"); exit(1); }
+
+ if( size )
+ {
+ icount += size;
+ if( fl == 0 )
+ {
+ key = scan_min();
+ putchar(key); ocount++;
+ fl = 1;
+ }
+ else
+ fprintf(stderr, "\rBlock %d \r", fl++ );
+ if( vptr) compress();
+ else slo_compress();
+ }
+ }
+
+ fprintf(stderr, "\n");
+ exit(0);
+}
+
+scan_min()
+{
+ long count[256];
+ long i;
+ int j, n;
+
+ for( j=0; j<256; j++ ) count[j] = 0;
+
+ for( i=0; i<size; i++) count[ fptr[i] & 0xFF ]++;
+
+ for( i= (((unsigned long) -1) >> 1), j=0; j<256; j++ )
+ if( count[j] < i )
+ {
+ i = count[j] ;
+ n = j;
+ }
+
+ fprintf(stderr, "Most unused in 0x%lx to 0x%lx is 0x%02x at %ld\n", cnt, cnt+size, n, i );
+ cnt+= size;
+
+ return n;
+}
+
+compress()
+{
+ register long mainscan;
+ register long secondscan;
+ register unsigned char * ptr = (unsigned char * ) fptr;
+ register int len;
+ register int matchlen;
+ long notepos;
+ long emark;
+#ifdef QSCAN
+ int count;
+#endif
+
+ for( mainscan=0; mainscan <ITBSIZE; itb[mainscan++] = -1 );
+
+ mainscan=0;
+ emark = size - 130 ;
+loopback:
+
+ for( ; mainscan < emark; )
+ {
+ matchlen = 3;
+ notepos = -1;
+#ifdef QSCAN
+ count = 0;
+#endif
+ for( secondscan=itb[itbfunc()];
+ secondscan >= 0 && mainscan - secondscan < maxno;
+ secondscan -= vptr[secondscan] )
+ {
+#ifdef DEBUG
+if( vptr[secondscan] == 0 )
+{
+ fprintf(stderr, "\nOh !!!!! mainsc %ld, sec-scan %ld\n", mainscan, secondscan);
+ vptr[secondscan] = secondscan+1;
+}
+#endif
+
+ for( len = 0; len < MAXLEN ; len++ )
+ if( mainscan+len >= size || ptr[mainscan+len] != ptr[secondscan+len] ) break;
+ if( len > matchlen && (len != 4 || mainscan - secondscan < 256 ) )
+ {
+ notepos = secondscan;
+ matchlen = len;
+ if( len == MAXLEN ) break;
+ }
+#ifdef QSCAN
+ if( matchlen > 20 && len > 3 && ++count > 5 )
+ break;
+#endif
+ }
+
+ if( notepos == -1 )
+ {
+ if( ptr[mainscan] == key )
+ {
+ ocount+=2;
+ putchar(key);
+ putchar(0);
+ }
+ else
+ {
+ ocount++;
+ putchar(ptr[mainscan]);
+ }
+ matchlen = 1;
+ }
+ else
+ {
+ long x = mainscan - notepos;
+ ocount+=3;
+ putchar(key);
+ if( x > 255 ) putchar(matchlen | 0x80);
+ else putchar(matchlen);
+ putchar((int)x);
+ if( x > 255 ) { putchar((int)x>>8); ocount++; }
+ }
+
+ while( matchlen-- )
+ {
+ len = itbfunc();
+ vptr[mainscan] = mainscan - itb[len];
+#if 1
+ if( vptr[mainscan] == 0 )
+ {
+ fprintf(stderr, "\nHumm.. ms=%ld, hash=%d, itb[hash]=%ld\n", mainscan, len, itb[len]);
+ vptr[mainscan] = mainscan+1;
+ }
+#endif
+ itb[len] = mainscan;
+ mainscan++;
+ }
+ }
+
+ fprintf(stderr, "\rBlock %d ..In:%ld Out:%ld \r", fl-1, icount, ocount );
+
+ if( emark < size-4 )
+ {
+ int cnt;
+ long l ;
+ if(mainscan > maxno )
+ {
+ for(cnt=0; cnt<ITBSIZE; cnt++)
+ {
+ if( itb[cnt] < maxno) itb[cnt] = -1;
+ else itb[cnt] -= maxno;
+ }
+ for(l=0; l<maxno; l++)
+ {
+ ptr[l] = ptr[l+maxno];
+ vptr[l] = vptr[l+maxno];
+ }
+ mainscan -= maxno;
+ size -= maxno;
+ }
+ if( size <= maxno )
+ {
+ if(( cnt = fread(ptr+size, 1, (int)maxno, fd)) < 0 )
+ { fprintf(stderr, "\nRead failed\n"); exit(1); }
+ size += cnt;
+ icount += cnt;
+ fprintf(stderr, "\rBlock %d \r", fl++ );
+ }
+ emark = size - 130;
+ if( mainscan >= emark )
+ emark = size -4;
+
+ goto loopback;
+ }
+
+ for( ; mainscan < size; )
+ {
+ if( ptr[mainscan] == key )
+ {
+ ocount+=2;
+ putchar(key);
+ putchar(0);
+ }
+ else
+ {
+ ocount++;
+ putchar(fptr[mainscan]);
+ }
+ mainscan++;
+ }
+ fprintf(stderr, "\rBlock %d ..In:%ld Out:%ld \r", fl-1, icount, ocount );
+ /* end */
+}
+
+slo_compress()
+{
+ register long mainscan;
+ register long secondscan;
+ register unsigned char * ptr = (unsigned char * ) fptr;
+ register int len;
+ register int matchlen;
+ long notepos;
+ long emark;
+#ifdef QSCAN
+ int count;
+#endif
+
+ mainscan=0;
+ emark = size - 130 ;
+loopback:
+
+ for( ; mainscan < emark; )
+ {
+ matchlen = 3;
+ notepos = -1;
+#ifdef QSCAN
+ count = 0;
+#endif
+ for( secondscan=mainscan-1;
+ secondscan >= 0 && mainscan - secondscan < maxno;
+ secondscan-- )
+ {
+ for( len = 0; len < MAXLEN ; len++ )
+ if( mainscan+len >= size || ptr[mainscan+len] != ptr[secondscan+len] ) break;
+ if( len > matchlen && (len != 4 || mainscan - secondscan < 256 ) )
+ {
+ notepos = secondscan;
+ matchlen = len;
+ if( len == MAXLEN ) break;
+ }
+#ifdef QSCAN
+ if( matchlen > 20 && len > 3 && ++count > 5 )
+ break;
+#endif
+ }
+
+ if( notepos == -1 )
+ {
+ if( ptr[mainscan] == key )
+ {
+ ocount+=2;
+ putchar(key);
+ putchar(0);
+ }
+ else
+ {
+ ocount++;
+ putchar(ptr[mainscan]);
+ }
+ matchlen = 1;
+ }
+ else
+ {
+ long x = mainscan - notepos;
+ ocount+=3;
+ putchar(key);
+ if( x > 255 ) putchar(matchlen | 0x80);
+ else putchar(matchlen);
+ putchar((int)x);
+ if( x > 255 ) { putchar((int)x>>8); ocount++; }
+ }
+
+ mainscan += matchlen;
+ }
+
+ fprintf(stderr, "\rBlock %d ..In:%ld Out:%ld \r", fl-1, icount, ocount );
+
+ if( emark < size-4 )
+ {
+ int cnt;
+ long l ;
+ if(mainscan > maxno )
+ {
+ for(l=0; l<maxno; l++)
+ {
+ ptr[l] = ptr[l+maxno];
+ }
+ mainscan -= maxno;
+ size -= maxno;
+ }
+ if( size <= maxno )
+ {
+ if(( cnt = fread(ptr+size, 1, (int)maxno, fd)) < 0 )
+ { fprintf(stderr, "\nRead failed\n"); exit(1); }
+ size += cnt;
+ icount += cnt;
+ fprintf(stderr, "\rBlock %d \r", fl++ );
+ }
+ emark = size - 130;
+ if( mainscan >= emark )
+ emark = size -4;
+
+ goto loopback;
+ }
+
+ for( ; mainscan < size; )
+ {
+ if( ptr[mainscan] == key )
+ {
+ ocount+=2;
+ putchar(key);
+ putchar(0);
+ }
+ else
+ {
+ ocount++;
+ putchar(fptr[mainscan]);
+ }
+ mainscan++;
+ }
+ fprintf(stderr, "\rBlock %d ..In:%ld Out:%ld \r", fl-1, icount, ocount );
+ /* end */
+}
+
diff --git a/libc/tests/env.c b/libc/tests/env.c
new file mode 100644
index 0000000..baeb8e9
--- /dev/null
+++ b/libc/tests/env.c
@@ -0,0 +1,82 @@
+
+char hex[] = "0123456789ABCDEF";
+
+char buf[20];
+main(argc, argv, envp)
+int argc;
+char ** argv;
+char ** envp;
+{
+ int i,j; char *p; char * str;
+ int * arg = &argc;
+
+ for(j=0; j<8; j++)
+ {
+ phex(arg);
+ putstr(":");
+ for(i=0; i<8; i++)
+ {
+ putstr(" ");
+ phex(*arg++);
+ }
+ putstr("\n");
+ }
+
+#if 0
+ str = alloca(sizeof(hex)+2);
+ putstr("Alloca = ");
+ phex(&str);
+ putstr(",");
+ phex(str);
+ putstr("\n");
+#endif
+
+ p = (char*) &argc;
+
+ putstr("ARGC="); phex(argc); putstr("\n");
+ for(i=0; i<argc; i++)
+ {
+ phex(argv[i]);
+ putstr(":");
+ putstr(argv[i]);
+ putstr("\n");
+ }
+ putstr("ENV=>\n");
+ for(; *envp; envp++)
+ {
+ phex(envp);
+ putstr(":");
+ phex(*envp);
+ putstr(":");
+ putstr(*envp);
+ putstr("\n");
+ }
+}
+
+phex(val)
+{
+ int i;
+ printf("%04x", val);
+}
+
+putstr(str)
+{
+ printf("%s", str);
+}
+
+#if 0
+int global_var_that_needs_init = 0x201;
+
+#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
+
+static void init_vars()
+{
+ global_var_that_needs_init = getuid();
+}
+#endif
diff --git a/libc/tests/ft.c b/libc/tests/ft.c
new file mode 100644
index 0000000..6456d0b
--- /dev/null
+++ b/libc/tests/ft.c
@@ -0,0 +1,1217 @@
+/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
+ * This program is distributed under the GNU General Public License.
+ */
+
+/*
+ * File Tool, This program is a collection of basic file tools
+ * it includes cat, cp, ln, mkdir, mknod, chmod, chown, mv, rm
+ *
+ * Links may be used to call it under any of these names.
+ */
+#include <stdio.h>
+#ifdef __STDC__
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/param.h>
+#include <utime.h>
+#include <pwd.h>
+#include <grp.h>
+
+#ifdef __BCC__X
+#undef S_IFLNK
+#undef S_IFSOCK
+#endif
+
+#ifdef S_IFSOCK
+#include <sys/socket.h>
+#endif
+#ifndef S_IFLNK
+#define lstat stat
+#endif
+
+/* Ansi prototypes */
+#ifdef __STDC__
+#define PR(x) x
+#else
+#define PR(x) ()
+#endif
+
+void main PR((int argc, char ** argv));
+int select_command PR((char * argv));
+void do_prep PR((void));
+void do_post PR((void));
+void execute PR((char * dname, char * fname));
+int exec_for_subdir PR((char * dname));
+void exec_for_item PR((int when, char * fname));
+void parse_perms PR((char * prefix, char * ustring));
+int edit_mode PR((int mode, char * mode_str));
+int cmd_ft PR((char * fname));
+int cmd_mkfifo PR((char * fname));
+int cmd_mksock PR((char * fname));
+int cmd_rm PR((char * fname));
+void build_dest PR((char * dest, char * name, char * newpath));
+int strisdigit PR((char * str));
+int cmd_mv PR((char * fname));
+int cmd_ln PR((char * fname));
+int cmd_cp PR((char * fname));
+int copy_modes PR((char * file));
+int copy_file PR((char * source, char * dest));
+void Usage PR((void));
+int cmd_mkdir PR((char * dirname));
+int cmd_mknod PR((void));
+int warn_func PR((int enumber, char * estr, char * eobj));
+int error_func PR((int enumber, char * estr, char * eobj));
+
+#define warning(x,y,z) ( Line_no = __LINE__, warn_func(x,y,z))
+#define error(x,y,z) ( Line_no = __LINE__, error_func(x,y,z))
+int Line_no = -1;
+
+#define DO_BDIR 0x0010 /* Do Dir before contents */
+#define DO_ADIR 0x0020 /* Do Dir after contents */
+#define DO_MCOPY 0x0040 /* Preserve modes flag forced */
+#define OK_DIR 0x0080 /* Directorys OK even if no flg_recurse */
+#define IGN_LNK 0x0100 /* Not interested in symlinks */
+#define NO_SOURCE 0x0200 /* Named files created */
+#define OK_NO_SOURCE 0x0400 /* Don't need the source */
+
+#define CMD_FT (0+OK_DIR+DO_BDIR)
+#define CMD_CAT (1+IGN_LNK)
+#define CMD_CHGRP (2+OK_DIR+IGN_LNK+DO_ADIR)
+#define CMD_CHMOD (3+OK_DIR+IGN_LNK+DO_ADIR)
+#define CMD_CHOWN (4+OK_DIR+IGN_LNK+DO_ADIR)
+#define CMD_CP (5+IGN_LNK)
+#define CMD_EXTAR (6+DO_MCOPY+DO_BDIR)
+#define CMD_INSTALL (7+DO_MCOPY)
+#define CMD_LN (8+IGN_LNK+DO_BDIR)
+#define CMD_MKDIR (9+NO_SOURCE)
+#define CMD_MKFIFO (10+NO_SOURCE)
+#define CMD_MKSOCK (11+NO_SOURCE)
+#define CMD_MKNOD (12+NO_SOURCE)
+#define CMD_MV (13+DO_MCOPY+OK_DIR+DO_BDIR)
+#define CMD_RM (14+DO_ADIR)
+
+struct {
+ char * name;
+ int cmd;
+ int argpat;
+ char * opts;
+} command_list[] =
+{
+ { "ft", CMD_FT, 0, "-Rv" },
+ { "cat", CMD_CAT, 0, "uR" },
+ { "chgrp", CMD_CHGRP, 1, "vfR" },
+ { "chmod", CMD_CHMOD, 1, "vfR" },
+ { "chown", CMD_CHOWN, 1, "vfR" },
+ { "cp", CMD_CP, -1, "vifRrpsd" },
+ { "extar", CMD_EXTAR, 1, "" },
+ { "install", CMD_INSTALL, -1, "cdso:g:m:" },
+ { "ln", CMD_LN, -1, "vifs" },
+ { "mkdir", CMD_MKDIR, 0, "m:" },
+ { "mkfifo", CMD_MKFIFO, 0, "m:" },
+#ifdef S_IFSOCK
+ { "mksock", CMD_MKSOCK, 0, "m:" },
+#endif
+ { "mknod", CMD_MKNOD, 4, "m:" },
+ { "mv", CMD_MV, -1, "vif" },
+ { "rm", CMD_RM, 0, "vifr" },
+ { 0 }
+};
+
+int cmd_arg = 0;
+int cmd_tok = CMD_FT;
+char * cmd_opt = "-";
+char * cmd_string = 0; /* the first (or last) arg where special */
+char * prog_name = "";
+
+char ** flist = 0;
+int fcount = 0;
+int add_base=0;
+char * or_name = 0;
+int or_offset = 0;
+
+int flg_recurse = 0;
+int flg_verbose = 1;
+int flg_preserve= 0;
+int flg_mkpdir = 0;
+int flg_noderef = 0;
+int flg_symlink = 0;
+int flg_exestrip= 0;
+
+int flg_r, flg_force;
+char *str_o, *str_g, *str_m;
+
+/* Things to set on the new file */
+int set_user = -1;
+int set_group = -1;
+int set_mode = -1;
+time_t set_time = -1;
+char mode_str[32] = "";
+int u_mask = 0; /* 07777 altered by umask() */
+
+struct stat cur_file_stat;
+struct stat dest_item;
+struct stat access_stat;
+
+int done_something = 0;
+
+void
+main(argc, argv)
+int argc; char ** argv;
+{
+ int ar;
+ (void) select_command(argv[0]);
+
+ for(ar=1;
+ argv[ar] && argv[ar][0] == '-' && argv[ar][1];
+ ar++)
+ {
+ char * p = argv[ar]+1;
+ /* For symbolic changes of the form -rwx */
+ if( cmd_tok == CMD_CHMOD && strchr("rwx", *p) != 0 ) break;
+ while(*p)
+ {
+ char * ap=0, *av=0;
+ char ch;
+ /* Is it a valid opt for this cmd */
+ if(*p == ':' || (ap=strchr(cmd_opt, *p)) == 0) Usage();
+
+ /* Got an argument ? */
+ if(ap[1] == ':')
+ {
+ if(!argv[ar+1]) Usage();
+ av = argv[++ar];
+ }
+
+ if( (ch = *p) == '-' )
+ {
+ if( (ch=select_command(p)) < 0 ) Usage();
+ }
+ switch(ch)
+ {
+ case '\0': break;
+ case 'r':
+ case 'R': flg_recurse++; break;
+ case 'v': flg_verbose++; break;
+ case 'p': if(cmd_tok == CMD_MKDIR) flg_mkpdir++;
+ else flg_preserve++;
+ break;
+ case 'd': if(cmd_tok == CMD_INSTALL)
+ { flg_mkpdir++; cmd_arg=0; } /* Special mkdir */
+ else flg_noderef++; /* cmd_copy */
+ break;
+
+ case 'f': flg_force++; flg_verbose=0; break;
+ case 'o': str_o = av; break;
+ case 'g': str_g = av; break;
+ case 'm': str_m = av; break;
+
+ case 's': flg_symlink++;
+ if( cmd_tok == CMD_LN) cmd_tok |= OK_DIR+OK_NO_SOURCE;
+ break;
+ }
+ if(*p == '-') break;
+ p++;
+ }
+ }
+
+ switch(cmd_arg)
+ {
+ case 1:
+ if( ar >= argc ) Usage();
+ cmd_string = argv[ar++];
+ fcount = argc-ar;
+ flist = argv+ar;
+ break;
+ case 0:
+ fcount = argc-ar;
+ flist = argv+ar;
+ break;
+ case -1:
+ if( ar >= argc ) Usage();
+ cmd_string = argv[argc-1];
+ fcount = argc-ar-1;
+ flist = argv+ar;
+ break;
+ default:
+ if( ar != argc-cmd_arg ) Usage();
+ fcount = argc-ar;
+ flist = argv+ar;
+ break;
+ }
+
+ do_prep();
+
+ for(ar=0; ar<fcount; ar++)
+ {
+ done_something=1;
+ or_name = flist[ar]; or_offset = strlen(or_name)+1;
+ execute(flist[ar], (char*)0);
+ }
+
+ do_post();
+
+ if( !done_something )
+ {
+ if( cmd_tok == CMD_CAT )
+ execute("-", (char*)0);
+ else
+ Usage();
+ }
+ exit(0);
+}
+
+int select_command(argv)
+char * argv;
+{
+ int ar;
+ char *p, *s;
+ prog_name = argv;
+ for(ar=0; command_list[ar].name; ar++)
+ {
+ p = strrchr(argv, '-'); if(p) p++; else p=argv;
+ s = strrchr(p, '/'); if(s) s++; else s=p;
+ if( strcmp(s, command_list[ar].name) == 0 )
+ {
+ cmd_arg = command_list[ar].argpat;
+ cmd_tok = command_list[ar].cmd;
+ cmd_opt = command_list[ar].opts;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+void do_prep()
+{
+ char * prefix = "::";
+
+ u_mask = umask(077);
+ umask(u_mask);
+ u_mask = (07777&(~u_mask));
+
+ if(cmd_tok&DO_MCOPY) flg_preserve++;
+ if(str_m) parse_perms(prefix, str_m);
+
+ switch(cmd_tok)
+ {
+ /* mknod is very different */
+ case CMD_MKNOD: cmd_mknod(); exit(0); break;
+
+ case CMD_CP:
+ if(strcmp(cmd_string, "-") == 0)
+ {
+ cmd_tok = CMD_CAT;
+ cmd_arg = 0;
+ break;
+ }
+ if(flg_symlink)
+ {
+ cmd_tok = CMD_LN+OK_DIR+OK_NO_SOURCE;
+ flg_preserve = 0;
+ }
+ break;
+
+ case CMD_CHOWN: prefix++;
+ case CMD_CHGRP: prefix++;
+ case CMD_CHMOD:
+ parse_perms(prefix, cmd_string);
+ set_time = 0;
+ break;
+ case CMD_INSTALL:
+ flg_exestrip = flg_symlink;
+ flg_symlink = 0;
+ if(str_o) parse_perms(prefix+2, str_o);
+ if(str_g) parse_perms(prefix+1, str_g);
+ if(flg_mkpdir) cmd_tok = CMD_MKDIR;
+ else
+ {
+ cmd_tok = CMD_CP;
+ flg_preserve = 1;
+ }
+ break;
+ }
+
+#ifndef S_IFLNK
+ if(flg_symlink)
+ {
+ error(0, "No support for symlinks available:", cmd_string);
+ exit(1);
+ }
+#endif
+
+ /* Are we transfering many to one ? Then it must be a directory */
+ if(cmd_arg == -1)
+ {
+ if( stat(cmd_string, &dest_item) == -1)
+ {
+ if( fcount > 1 )
+ {
+ if( cmd_mkdir(cmd_string) < 0 )
+ exit(1);
+ stat(cmd_string, &dest_item);
+ add_base = 1;
+ }
+ }
+ else
+ {
+ if( !S_ISDIR(dest_item.st_mode) )
+ {
+ if( fcount > 1 )
+ {
+ error(0, "Destination must be a directory:", cmd_string);
+ exit(1);
+ }
+ }
+ else add_base = 1;
+ }
+ }
+}
+
+void do_post()
+{
+ /* Oh! It seems there's nothing to do, ah well. */
+}
+
+void execute(dname, fname)
+char * dname; char * fname;
+{
+ char * buf;
+ if( strcmp(dname, "-") == 0 )
+ {
+ exec_for_item(0, dname);
+ return;
+ }
+ if( fname )
+ {
+ buf = alloca(strlen(dname) + strlen(fname) + 4);
+ if( buf == 0 )
+ {
+ error(errno, "Can't allocate memory for path beyond", dname);
+ return ;
+ }
+ strcpy(buf, dname);
+ if(strcmp(dname, "/")) strcat(buf, "/");
+ strcat(buf, fname);
+ }
+ else buf = dname;
+
+ if( lstat(buf, &cur_file_stat) == -1 )
+ {
+ if( cmd_tok&(NO_SOURCE|OK_NO_SOURCE) )
+ exec_for_item(0, buf);
+ else
+ warning(errno, "", buf);
+ return;
+ }
+ if( !flg_force && ( cmd_tok&NO_SOURCE ))
+ {
+ error(EEXIST, "", buf);
+ return;
+ }
+
+ if( S_ISDIR(cur_file_stat.st_mode))
+ {
+ if( (cmd_tok&OK_DIR) || flg_recurse )
+ (void) exec_for_subdir(buf);
+ else
+ error(EISDIR, "", buf);
+ return;
+ }
+
+#ifdef S_IFLNK
+ if( S_ISLNK(cur_file_stat.st_mode))
+ {
+ /* Links are special */
+ if( cmd_tok&IGN_LNK )
+ {
+ if( stat(buf, &cur_file_stat) == -1 )
+ {
+ warning(errno, "", buf);
+ return;
+ }
+ }
+ }
+#endif
+ exec_for_item(0, buf);
+}
+
+int exec_for_subdir(dname)
+char * dname;
+{
+ DIR * dfd;
+ struct dirent * ent;
+ int old_mode = -1;
+
+ if( cmd_tok&DO_BDIR ) exec_for_item(-1, dname);
+
+ if( flg_recurse )
+ {
+ dfd = opendir(dname);
+
+ if( dfd == 0 && errno == EACCES && flg_force )
+ {
+ old_mode = (cur_file_stat.st_mode & 07777);
+ if( chmod(dname, (0700|old_mode)) )
+ return error(errno, "Can't unlock", dname);
+
+ dfd = opendir(dname);
+ }
+ if( dfd == 0 ) return error(errno, "Can't open", dname);
+
+ while((ent=readdir(dfd)))
+ {
+ if( strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 )
+ continue;
+
+ alloca(0); /* Free up if using fake version */
+ execute(dname, ent->d_name);
+ }
+ closedir(dfd);
+ if( old_mode != -1 )
+ chmod(dname, old_mode);
+ }
+
+ if( cmd_tok&DO_ADIR )
+ {
+ lstat(dname, &cur_file_stat);
+ exec_for_item(1, dname);
+ }
+ return 0;
+}
+
+void exec_for_item(when, fname)
+int when; char * fname;
+{
+ int rv = -1;
+ switch(cmd_tok)
+ {
+ case CMD_FT: rv = cmd_ft(fname); break;
+
+ case CMD_CAT: rv = copy_file(fname, "-"); break;
+
+ case CMD_CHGRP: /* And fall */
+ case CMD_CHMOD: /* And fall */
+ case CMD_CHOWN: rv = copy_modes(fname); break;
+
+ case CMD_CP: rv = cmd_cp(fname); break;
+ case CMD_MV: rv = cmd_mv(fname); break;
+ case CMD_RM: rv = cmd_rm(fname); break;
+
+ case CMD_EXTAR: error(ENOSYS, "", ""); exit(1);
+
+ case CMD_LN+OK_DIR+OK_NO_SOURCE:
+ case CMD_LN: rv = cmd_ln(fname); break;
+
+ case CMD_INSTALL: error(EINVAL, "", "Bad program"); exit(1);
+
+ case CMD_MKDIR: rv = cmd_mkdir(fname); break;
+ case CMD_MKFIFO: rv = cmd_mkfifo(fname); break;
+#ifdef S_IFSOCK
+ case CMD_MKSOCK: rv = cmd_mksock(fname); break;
+#endif
+ case CMD_MKNOD: break;
+ }
+}
+
+void parse_perms(prefix, ustring)
+char * prefix; char * ustring;
+{
+ char * userstr;
+ char * groupstr;
+ char * modestr;
+ char * cp;
+ struct passwd * pwd = 0;
+ struct group * grp;
+
+ userstr = alloca(strlen(prefix) + strlen(ustring) + 2);
+ strcpy(userstr, prefix);
+ strcat(userstr, ustring);
+
+ /* Select User */
+ cp = strchr(userstr, ':');
+ if(!cp) cp = strchr(userstr, '.');
+ if(cp) *cp = '\0';
+
+ /* If there's a user */
+ if( *userstr != 0 )
+ {
+ pwd = getpwnam(userstr);
+ if(pwd == NULL)
+ {
+ if(!strisdigit(userstr) )
+ {
+ error(EINVAL, "Unknown user", userstr);
+ exit(1);
+ }
+ set_user = atoi(userstr);
+ }
+ else set_user = pwd->pw_uid;
+ endpwent();
+ }
+ if(cp)
+ {
+ groupstr = cp+1;
+ cp = strchr(groupstr, ':');
+ if(!cp) cp = strchr(groupstr, '.');
+ if(cp) *cp = '\0';
+ if( *groupstr != '\0' )
+ {
+ grp = getgrnam(groupstr);
+ if(grp == NULL)
+ {
+ if(!strisdigit(groupstr) )
+ {
+ error(EINVAL, "Unknown group", groupstr);
+ exit(1);
+ }
+ set_group = atoi(groupstr);
+ }
+ else set_group = grp->gr_gid;
+ endgrent();
+ }
+ else if( pwd )
+ set_group = pwd->pw_gid;
+ }
+ if(cp)
+ {
+ modestr = cp+1;
+ if(strisdigit(modestr))
+ set_mode = strtol(modestr, NULL, 8);
+ else
+ {
+ strncpy(mode_str, modestr, sizeof(mode_str)-1);
+ /* This is the time that the mode change will fail on syn error */
+ (void) edit_mode(u_mask, mode_str);
+ }
+ }
+
+ if( set_user < 0 && set_group < 0 && set_mode < 0 && *mode_str == 0)
+ {
+ error(EINVAL, "", "Permission string has no changes");
+ exit(1);
+ }
+}
+
+int edit_mode(mode, mode_str)
+int mode; char * mode_str;
+{
+ char * str=mode_str;
+static mtab[] = {0, 0111, 0222, 0333, 0444, 0555, 0666, 0777 };
+
+ int done_change = 0;
+ int isdir = S_ISDIR(mode);
+ int change_op = 0;
+ int change_mask = u_mask;
+ int v=0, s=0, nm=0;
+
+ for(; *mode_str; mode_str++)
+ {
+ switch(*mode_str)
+ {
+ case ',': change_op = 0;
+ change_mask=u_mask; continue;
+ case '=': change_op = 1; if(0) {
+ case '+': change_op = 2; } if(0) {
+ case '-': change_op = 3; }
+ v=0; nm=0;
+ if(strchr(",=+-", mode_str[1]) == 0 ) continue;
+ break;
+ case 'a': if(change_op) goto ch_error;
+ nm |= 07777; if(0) {
+ case 'u': nm |= 04700; s= 6; } if(0) {
+ case 'g': nm |= 02070; s= 3; } if(0) {
+ case 'o': nm |= 01007; s= 0; }
+ if(change_op==0) { change_mask=nm; continue; }
+ v |= mtab[(mode>>s)&7];
+ break;
+ case 'r': v |= 0444; break;
+ case 'w': v |= 0222; break;
+ case 'x': v |= 0111; break;
+ case 's': v |=06000; break;
+ case 't': v |=01000; break;
+ case 'X': v |= mtab[isdir]; break;
+ default: goto ch_error;
+ }
+ switch(change_op)
+ {
+ case 0: goto ch_error;
+ case 1: mode= ((mode&(~change_mask)) | (v&change_mask));
+ break;
+ case 2: mode= ( mode | (v&change_mask));
+ break;
+ case 3: mode= ( mode & ~(v&change_mask));
+ break;
+ }
+ done_change=1;
+ }
+ if(!done_change)
+ {
+ch_error:
+ error(EINVAL, "Invalid mode string", str);
+ exit(1);
+ }
+ return mode;
+}
+
+int
+cmd_ft(fname)
+char * fname;
+{
+static char oldpath[2048] = "~";
+static int last_uid=-1, last_gid=-1, last_mode=-1;
+ struct passwd * pptr;
+ struct group * gptr;
+
+ if( flg_verbose>1 )
+ {
+ char *p = 0;
+ if( fname[1] ) p = strrchr(fname, '/');
+ if( p )
+ {
+ *p = '\0';
+ if( strcmp(fname, oldpath) != 0 )
+ {
+ strcpy(oldpath, fname);
+ printf("%s/\n", oldpath);
+ }
+ *p = '/';
+ }
+ else if( *oldpath )
+ *oldpath = '\0';
+ if(p) printf("%s", p+1);
+ else printf("%s", fname);
+
+#ifdef S_IFLNK
+ if( S_ISLNK(cur_file_stat.st_mode))
+ {
+ char linkbuf[1024];
+ int v;
+ *linkbuf='\0';
+ v = readlink(fname, linkbuf, sizeof(linkbuf));
+ if(v>0) linkbuf[v] = '\0';
+ printf("\t+%s", linkbuf);
+ }
+ else
+#endif
+ if( cur_file_stat.st_mode != last_mode
+ || cur_file_stat.st_uid != last_uid
+ || cur_file_stat.st_gid != last_gid)
+ {
+ printf("\t");
+ if( cur_file_stat.st_uid != last_uid )
+ {
+ pptr = getpwuid(cur_file_stat.st_uid);
+ if( pptr )
+ printf("%s", pptr->pw_name);
+ else
+ printf("%d", cur_file_stat.st_uid);
+ }
+ printf(":");
+ if( cur_file_stat.st_gid != last_gid )
+ {
+ gptr = getgrgid(cur_file_stat.st_gid);
+ if( gptr )
+ printf("%s", gptr->gr_name);
+ else
+ printf("%d", cur_file_stat.st_gid);
+ }
+ if( (cur_file_stat.st_mode&07777) != (last_mode&07777) )
+ printf(":%03o", cur_file_stat.st_mode & 07777);
+
+ switch(cur_file_stat.st_mode & S_IFMT)
+ {
+ case S_IFDIR: printf("\td"); break;
+ case S_IFIFO: printf("\tp"); break;
+#ifdef S_IFSOCK
+ case S_IFSOCK: printf("\ts"); break;
+#endif
+ case S_IFBLK: printf("\tb,%d,%d", cur_file_stat.st_rdev>>8,
+ cur_file_stat.st_rdev&0xFF);
+ break;
+ case S_IFCHR: printf("\tc,%d,%d", cur_file_stat.st_rdev>>8,
+ cur_file_stat.st_rdev&0xFF);
+ break;
+ }
+ last_mode = ((cur_file_stat.st_mode&07777)|S_IFREG);
+ if( (cur_file_stat.st_mode&07000) ) last_mode = -1;
+ last_uid = cur_file_stat.st_uid;
+ last_gid = cur_file_stat.st_gid;
+ }
+ printf("\n");
+ }
+ else printf("%s\n", fname);
+
+ return 0;
+}
+
+int
+cmd_mkfifo(fname)
+char * fname;
+{
+ int rv;
+ int mode=0666;
+ if( set_mode >= 0 ) mode=set_mode;
+ rv = mknod(fname, S_IFIFO|mode, 0);
+ if(rv<0)
+ warning(errno, "Cannot create fifo", fname);
+ return rv;
+}
+
+#ifdef S_IFSOCK
+int
+cmd_mksock(fname)
+char * fname;
+{
+ int rv, fd, len;
+ struct sockaddr *adr;
+
+ len = strlen(fname)+1 + sizeof(*adr) - sizeof(adr->sa_data);
+ if( len < sizeof(*adr) ) len = sizeof(*adr);
+
+ adr = alloca(len+2);
+ adr->sa_family = AF_UNIX;
+ strcpy(adr->sa_data, fname);
+
+ rv = fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if( fd>=0 ) rv = bind(fd, adr, len);
+ if( fd>=0 ) close(fd);
+ if(set_mode >= 0 && chmod(fname, set_mode&07777) < 0 )
+ warning(errno, "Chmod", fname);
+
+ if(rv<0)
+ warning(errno, "Cannot create socket", fname);
+ return rv;
+}
+#endif
+
+int
+cmd_rm(fname)
+char * fname;
+{
+ struct stat dirstat;
+ int rv;
+ char * buf, * p;
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ if( !flg_recurse ) return error(EISDIR, "", fname);
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ {
+ if( rmdir(fname) >= 0 ) return 0;
+ }
+ else
+ {
+ if( unlink(fname) >= 0 ) return 0;
+ }
+
+ if( !flg_force )
+ return error(errno, "", fname);
+
+ /* Try VERY hard */
+ buf = alloca(strlen(fname)+4);
+ strcpy(buf, fname);
+ p = strrchr(buf, '/');
+ if( p ) strcpy(p+1, "."); else strcpy(buf, ".");
+
+ if( stat(buf, &dirstat) < 0 ) return -1;
+ if( chmod(buf, dirstat.st_mode|0700) < 0 ) return -1;
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ rv = rmdir(fname);
+ else
+ rv = unlink(fname);
+
+ chmod(buf, dirstat.st_mode);
+
+ return rv;
+}
+
+void
+build_dest(dest, name, newpath)
+char * dest; char * name; char * newpath;
+{
+ char * p;
+ strcpy(dest, newpath);
+ if( add_base )
+ {
+ strcat(dest, "/");
+ p = strrchr(or_name, '/');
+ if(p==0) strcat(dest, or_name);
+ else strcat(dest, p+1);
+ }
+ if(strlen(name) <= or_offset) return;
+ strcat(dest, name+or_offset);
+}
+
+int
+strisdigit(str)
+char * str;
+{
+ if( str==0 || *str == 0 ) return 0;
+
+ for(;*str; str++)
+ if(*str>'9'|| *str<'0') return 0;
+ return 1;
+}
+
+int
+cmd_mv(fname)
+char * fname;
+{
+ char * destfile;
+ destfile = alloca(strlen(fname)+strlen(cmd_string)+4);
+
+ build_dest(destfile, fname, cmd_string);
+
+ if( !flg_force && lstat(destfile, &access_stat) == 0 )
+ return error(EEXIST, "", destfile);
+
+ if( rename(fname, destfile) == 0 ) return 0;
+
+ if( errno != EXDEV )
+ return error(errno, "", fname);
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ return error(EISDIR, "Can't rename across devices", fname);
+
+ if( copy_file(fname, destfile) != 0 ) return -1;
+ copy_modes(destfile);
+ return unlink(fname);
+}
+
+int
+cmd_ln(fname)
+char * fname;
+{
+ char * destfile;
+ destfile = alloca(strlen(fname)+strlen(cmd_string)+4);
+
+ build_dest(destfile, fname, cmd_string);
+
+ if( lstat(destfile, &access_stat) != -1 )
+ {
+ if( !flg_force ) return error(EEXIST, "", destfile);
+ cmd_rm(destfile);
+ }
+
+#ifdef S_IFLNK
+ if( flg_symlink )
+ {
+ if( symlink(fname, destfile) == 0 ) return 0;
+ }
+ else
+ {
+#endif
+ if( link(fname, destfile) == 0 ) return 0;
+#ifdef S_IFLNK
+ }
+#endif
+
+ return error(errno, "", destfile);
+}
+
+int
+cmd_cp(fname)
+char * fname;
+{
+ struct stat dest_stat;
+ char * destfile;
+ int no_dest = 0;
+
+ destfile = alloca(strlen(fname)+strlen(cmd_string)+4);
+
+ build_dest(destfile, fname, cmd_string);
+
+ if( stat(destfile, &dest_stat) >= 0 )
+ {
+ if( dest_stat.st_ino == cur_file_stat.st_ino
+ && dest_stat.st_dev == cur_file_stat.st_dev )
+ {
+ warning(EPERM, "Can't copy file to itself", fname);
+ return -1;
+ }
+ }
+ else no_dest = 1;
+
+ if( S_ISDIR(cur_file_stat.st_mode) )
+ {
+ if( !no_dest )
+ {
+ if( S_ISDIR(dest_stat.st_mode) ) return 0;
+ if( unlink(destfile) < 0 )
+ return error(errno, "Can't delete", destfile);
+ }
+ return cmd_mkdir(destfile);
+ }
+ else if( S_ISDIR(dest_stat.st_mode) )
+ return error(EPERM, "Can't copy non-directory to directory", destfile);
+ else if( S_ISREG(cur_file_stat.st_mode) )
+ {
+ /* Copy_ok - do we want to force a real file */;
+ if( flg_force && !no_dest && !S_ISREG(dest_stat.st_mode) )
+ cmd_rm(destfile);
+ }
+ else if( flg_recurse ) /* Don't copy other things while recursing */
+ {
+ return error(EPERM, "Can't copy", fname);
+ }
+
+ if( copy_file(fname, destfile) != 0 ) return -1;
+ if( flg_preserve ) copy_modes(destfile);
+ return 0;
+}
+
+int
+copy_modes(file)
+char * file;
+{
+ int user, group, mode;
+ /* chown turns off set[ug]id bits for non-root,
+ so do the chmod last. */
+
+ /* Try to copy the old file's modtime and access time. */
+ if(set_time)
+ {
+ struct utimbuf tv;
+
+ tv.actime = cur_file_stat.st_atime;
+ tv.modtime = cur_file_stat.st_mtime;
+ if( set_time != -1 )
+ tv.modtime = set_time;
+ if (utime (file, &tv) && !flg_force)
+ return error (errno, "", file);
+ }
+
+ /* Try to preserve ownership. For non-root it might fail, but that's ok.
+ But root probably wants to know, e.g. if NFS disallows it. */
+ user = cur_file_stat.st_uid; if(set_user>=0) user = set_user;
+ group = cur_file_stat.st_gid; if(set_group>=0) group = set_group;
+
+ if (chown (file, user, group)
+ && (errno != EPERM || geteuid() == 0 || (flg_preserve==0 && flg_force==0)))
+ error (errno, "Can't change perms for", file);
+
+ mode = cur_file_stat.st_mode;
+ if(set_mode>=0) mode=set_mode;
+ else if(*mode_str)
+ mode = edit_mode(mode, mode_str);
+
+ if (chmod (file, mode & 07777))
+ return error (errno, "", file);
+
+ return 0;
+}
+
+/* This copies from something to a file or stdout */
+/* If the source has zero blocks (possibly holes) the destination
+ * is built with holes (assuming it's a normal file) */
+
+int
+copy_file(source, dest)
+char * source; char * dest;
+{
+ char * buf;
+ int sfd, dfd;
+ struct stat st;
+ int blksz = BUFSIZ;
+ int cc;
+ char * ptr;
+ int hole_flag = 0;
+ int retv = 0;
+ int no_seek;
+ int mmode = 0666;
+
+ if(flg_verbose>1) printf("%s -> %s\n", source, dest);
+ if( strcmp(source, "-") == 0 )
+ sfd = 0;
+ else
+ {
+ sfd = open(source, O_RDONLY);
+ if(sfd<0) return error(errno, "", source);
+ mmode = (cur_file_stat.st_mode&0777);
+ }
+
+ if( strcmp(dest, "-") == 0 )
+ dfd = 1;
+ else
+ {
+ dfd = open(dest, O_WRONLY|O_TRUNC|O_CREAT, mmode);
+ if(dfd<0)
+ {
+ close(sfd);
+ return error(errno, "Cannot create", source);
+ }
+ }
+
+ if( fstat(dfd, &st) )
+ {
+ retv = error(errno, "", dest);
+ no_seek = 1;
+ }
+ else
+ {
+#ifndef __BCC__
+ blksz = st.st_blksize;
+#endif
+ no_seek = !S_ISREG(st.st_mode);
+ }
+ buf = alloca(blksz + sizeof(int));
+ if( buf == 0 ) return error(0, "Out of memory", "");
+
+ for(;;)
+ {
+ cc = read(sfd, buf, blksz);
+ if(cc<0)
+ {
+ retv = error(errno, "", source);
+ goto exit_now;
+ }
+ if(cc==0) break;
+ buf[cc] = 1;
+ for(ptr=buf; *ptr==0 ; ptr++) ;
+ if((hole_flag = (ptr == buf+cc)))
+ { /* Make a hole */
+ if( lseek(dfd, (off_t) cc, SEEK_CUR) < 0 )
+ {
+ retv = error(errno, "", dest);
+ goto exit_now;
+ }
+ }
+ else
+ {
+ if( cc != write(dfd, buf, cc))
+ {
+ retv = error(errno, "", dest);
+ goto exit_now;
+ }
+ }
+ }
+ if( hole_flag )
+ {
+ if( lseek(dfd, (off_t) -1, SEEK_CUR) < 0
+ || write(dfd, "", 1) != 1 )
+ {
+ retv = error(errno, "", dest);
+ goto exit_now;
+ }
+ }
+
+exit_now:
+ if(sfd>2) close(sfd);
+ if(dfd>2) close(dfd);
+ return retv;
+}
+
+void
+Usage()
+{
+ int i;
+
+ printf("FileTool Usage: %s%s", prog_name[0]=='-'?"ft -":"", prog_name);
+ if( cmd_tok == CMD_FT )
+ {
+ printf(" --[com_name] [-options] [files]\n");
+ printf("\nAvailable commands are:\n");
+ }
+
+ for(i=1; command_list[i].name; i++)
+ {
+ if( cmd_tok == CMD_FT )
+ printf(" %s --%s", prog_name, command_list[i].name);
+ else if( cmd_tok != command_list[i].cmd )
+ continue;
+
+ if( *command_list[i].opts )
+ printf(" [-%s]", command_list[i].opts);
+ switch(command_list[i].argpat)
+ {
+ case 1: printf(" <info> [files]"); break;
+ case -1: printf(" [files] [dest]"); break;
+ case 0: printf(" [files]"); break;
+ default: printf(" path [bcu] major minor"); break;
+ }
+ printf("\n");
+ }
+
+ exit(99);
+}
+
+int
+cmd_mkdir(dirname)
+char * dirname;
+{
+ int retv;
+ int mode = 0777;
+ if( set_mode >= 0 ) mode = set_mode;
+
+ retv = mkdir(dirname, mode);
+ if(retv<0)
+ {
+ if(flg_mkpdir && errno == ENOENT)
+ {
+ /* Create parents */
+ }
+ }
+ if( retv>=0 && cmd_tok == CMD_MKDIR )
+ {
+ if( set_user > 0 || set_group > 0 )
+ {
+ if( chown(dirname, set_user, set_group) < 0)
+ warning(errno, "Cannot change directory owner", dirname);
+ else if( chmod (dirname, mode & 07777) )
+ warning(errno, "", dirname);
+ }
+ }
+
+ if(retv<0) error(errno, "Cannot create directory", dirname);
+ return retv;
+}
+
+int
+cmd_mknod()
+{
+ int device;
+ int rv = -1;
+ int mode=0666;
+ if( set_mode >= 0 ) mode=set_mode;
+
+ device = (atoi(flist[2])<<8) + atoi(flist[3]);
+
+ if(flist[1][0] == 'b')
+ rv = mknod(flist[0], S_IFBLK|mode, device);
+ else if(flist[1][0] == 'c' || flist[1][0] == 'u')
+ rv = mknod(flist[0], S_IFCHR|mode, device);
+ else Usage();
+
+ if(rv<0)
+ {
+ error(errno, "", flist[0]);
+ exit(1);
+ }
+ return rv;
+}
+
+int
+warn_func(enumber, estr, eobj)
+int enumber; char * estr; char * eobj;
+{
+ if(flg_verbose)
+ return error_func(enumber, estr, eobj);
+ return 0;
+}
+
+int
+error_func(enumber, estr, eobj)
+int enumber; char * estr; char * eobj;
+{
+ fprintf(stderr, "%s%s(%d): ", prog_name[0]=='-'?"ft":"", prog_name, Line_no);
+ fprintf(stderr, "%s%s%s: %s\n", estr, (*estr?" ":""), eobj, strerror(enumber));
+ return -1;
+}
diff --git a/libc/tests/grab.c b/libc/tests/grab.c
new file mode 100755
index 0000000..bd62a0f
--- /dev/null
+++ b/libc/tests/grab.c
@@ -0,0 +1,80 @@
+
+#include <stdio.h>
+#include <malloc.h>
+
+struct s
+{
+ struct s * n;
+ char v[1];
+};
+
+#define M ((unsigned)-1>>1)
+#define V (M^(M>>1))
+
+main (argc,argv)
+int argc;
+char ** argv;
+{
+ struct s * ptr1 = 0;
+ struct s * ptr2;
+ struct s * ptr3;
+ int i,sz;
+ long total = 0;
+
+ for(i=0, sz=256 ; i<32; i++, sz = ((sz << 1) | (sz & V)) & M)
+ {
+ ptr2 = (struct s *) malloc(sz-sizeof(int));
+ printf("%2d(%8u)..%08lx..%ld\n",i,sz,(long)ptr2,(long)ptr2);
+ if(ptr2==0) break;
+ total+=sz;
+ if(ptr1==0)
+ {
+ ptr1 = ptr3 = ptr2;
+ ptr3->n = 0;
+ }
+ else
+ {
+ ptr3->n = ptr2;
+ ptr3 = ptr2;
+ ptr3->n = 0;
+ }
+ }
+ for(sz>>=1; sz>255; )
+ {
+ ptr2 = (struct s *) malloc(sz-sizeof(int));
+ if(ptr2==0) { sz >>=1; continue; }
+ printf("%2d(%8u)..%08lx..%ld\n",i++,sz,(long)ptr2,(long)ptr2);
+ total+=sz;
+ if(ptr1==0)
+ {
+ ptr1 = ptr3 = ptr2;
+ ptr3->n = 0;
+ }
+ else
+ {
+ ptr3->n = ptr2;
+ ptr3 = ptr2;
+ ptr3->n = 0;
+ }
+ }
+ printf("Free all - total was %ldK bytes\n", total/1024);
+ while( ptr1 )
+ {
+ ptr3 = ptr1->n;
+ free(ptr1);
+ ptr1 = ptr3;
+ }
+ ptr2 = (struct s *) malloc(200);
+ printf("%2d(%8u)..%08lx..%ld\n",i++,200,(long)ptr2,(long)ptr2);
+ ptr2 = (struct s *) malloc(30000);
+ printf("%2d(%8u)..%08lx..%ld\n",i++,30000,(long)ptr2,(long)ptr2);
+ ptr2 = (struct s *) malloc(20000);
+ printf("%2d(%8u)..%08lx..%ld\n",i++,20000,(long)ptr2,(long)ptr2);
+ sz = (256<<sizeof(int));
+ do
+ {
+ ptr2 = (struct s *) malloc(sz-sizeof(int));
+ printf("%2d(%8u)..%08lx..%ld\n",i++,sz,(long)ptr2,(long)ptr2);
+ }
+ while(ptr2 && i < 100);
+}
diff --git a/libc/tests/hd.c b/libc/tests/hd.c
new file mode 100644
index 0000000..f6af1f9
--- /dev/null
+++ b/libc/tests/hd.c
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <ctype.h>
+
+int lastnum[16] = { -1 };
+long lastaddr = -1;
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+ FILE * fd;
+ int j, ch;
+ char buf[20];
+ int num[16];
+ long offset = 0;
+
+#ifndef MSDOS
+ if( argc == 1 )
+ {
+ fd = stdin;
+ }
+ else
+#endif
+ {
+ if( argc == 3 ) offset = strtol(argv[2], (char*)0, 16);
+ else if( argc != 2 )
+ {
+ fprintf(stderr, "Usage: hd file [hexoffset]\n");
+ exit(1);
+ }
+ fd = fopen(argv[1], "rb");
+ if( fd == 0 )
+ {
+ fprintf(stderr, "Cannot open file '%s'\n", argv[1]);
+ exit(1);
+ }
+ }
+
+ /* if( offset ) fseek(fd, offset, 0); */
+
+ for(ch=0; ch!=EOF; offset+=16)
+ {
+ memset(buf, '\0', 16);
+ for(j=0; j<16; j++) num[j] = -1;
+ for(j=0; j<16; j++)
+ {
+ ch = fgetc(fd);
+ if( ch == EOF ) break;
+
+ num[j] = ch;
+ if( isascii(ch) && isprint(ch) ) buf[j] = ch;
+ else buf[j] = '.';
+ }
+ printline(offset, num, buf, ch==EOF);
+ }
+ fclose(fd);
+}
+
+printline(address, num, chr, eofflag)
+long address;
+int * num;
+char * chr;
+int eofflag;
+{
+ int j;
+
+ if( lastaddr >= 0 )
+ {
+ for(j=0; j<16; j++)
+ if( num[j] != lastnum[j] )
+ break;
+ if( j == 16 && !eofflag ) return;
+ if( lastaddr+16 != address )
+ printf("*\n");
+ }
+
+ lastaddr = address;
+ printf("%06lx:", address);
+ for(j=0; j<16; j++)
+ {
+ if( num[j] >= 0 )
+ printf(" %02x", num[j]);
+ else
+ printf(" ");
+ lastnum[j] = num[j];
+ num[j] = -1;
+ }
+
+ printf(" %.16s\n", chr);
+}
diff --git a/libc/tests/line2.c b/libc/tests/line2.c
new file mode 100644
index 0000000..6cc11ff
--- /dev/null
+++ b/libc/tests/line2.c
@@ -0,0 +1,15 @@
+
+#include <stdio.h>
+
+char buf[256];
+
+main()
+{
+ FILE * fd;
+ fd = fopen("/etc/passwd", "r");
+
+ while(fgets(buf, sizeof(buf), fd) != NULL)
+ {
+ printf(">>%s", buf);
+ }
+}
diff --git a/libc/tests/lines.c b/libc/tests/lines.c
new file mode 100644
index 0000000..6f3afb0
--- /dev/null
+++ b/libc/tests/lines.c
@@ -0,0 +1,36 @@
+
+#include <string.h>
+#include <fcntl.h>
+
+char *
+readline(fd)
+{
+static char linebuf[256];
+ int cc;
+ char * p;
+
+ cc = read(fd, linebuf, sizeof(linebuf)-1);
+ if( cc <= 0 ) return 0;
+ p = strchr(linebuf, '\n');
+ if( p == 0 ) p = linebuf+sizeof(linebuf)-1;
+ else
+ {
+ p++; lseek(fd, (long)(p-linebuf)-cc, 1);
+ }
+ *p = 0;
+ return linebuf;
+}
+
+main()
+{
+ int fd = open("/etc/passwd", O_RDONLY);
+ char * p;
+
+ if(fd<0) exit(1);
+
+ while( p=readline(fd) )
+ {
+ write(1, ">>", 2);
+ write(1, p, strlen(p));
+ }
+}
diff --git a/libc/tests/ls.c b/libc/tests/ls.c
new file mode 100755
index 0000000..8cae4d0
--- /dev/null
+++ b/libc/tests/ls.c
@@ -0,0 +1,1049 @@
+/* ls 3.2 - List files. Author: Kees J. Bot
+ *
+ * About the amount of bytes for heap + stack under Minix:
+ * Ls needs a average amount of 42 bytes per unserviced directory entry, so
+ * scanning 10 directory levels deep in an ls -R with 100 entries per directory
+ * takes 42000 bytes of heap. So giving ls 10000 bytes is tight, 20000 is
+ * usually enough, 40000 is pessimistic.
+ */
+
+/* Compile with the proper -D flag for your system:
+ *
+ * _MINIX Minix (1.5 or later)
+ * BSD BSD derived (has st_blocks)
+ * AMOEBA Amoeba's emulation of UNIX
+ */
+
+/* The array _ifmt[] is used in an 'ls -l' to map the type of a file to a
+ * letter. This is done so that ls can list any future file or device type
+ * other than symlinks, without recompilation. (Yes it's dirty.)
+ */
+char _ifmt[] = "0pcCd?bB-?l?s???";
+
+#define ifmt(mode) _ifmt[((mode) >> 12) & 0xF]
+
+#define nil 0
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef AMOEBA
+#undef S_IFLNK /* Liars */
+#endif
+#include <dirent.h>
+#include <time.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <fcntl.h>
+#if BSD || __minix_vmd
+#include <termios.h>
+#endif
+#if __minix_vmd
+#include <sys/ioctl.h>
+#endif
+
+#ifndef major
+#define major(dev) ((int) (((dev) >> 8) & 0xFF))
+#define minor(dev) ((int) (((dev) >> 0) & 0xFF))
+#endif
+
+#if !_MINIX
+#define SUPER_ID uid /* Let -A flag be default for SUPER_ID == 0. */
+#else
+#define SUPER_ID gid
+#endif
+
+#ifdef S_IFLNK
+int (*status)(const char *file, struct stat *stp);
+#else
+#define status stat
+#endif
+
+/* Basic disk block size is 512 except for one niche O.S. */
+#if _MINIX
+#define BLOCK 1024
+#else
+#define BLOCK 512
+#endif
+
+/* Some terminals ignore more than 80 characters on a line. Dumb ones wrap
+ * when the cursor hits the side. Nice terminals don't wrap until they have
+ * to print the 81st character. Wether we like it or not, no column 80.
+ */
+#ifdef TIOCGWINSZ
+int ncols= 79;
+#else
+#define ncols 79
+#endif
+
+#define NSEP 2 /* # spaces between columns. */
+
+#ifdef TIOCGWINSZ
+#define MAXCOLS 150
+#else
+#define MAXCOLS (1 + (ncols / (1+NSEP))) /* Max # of files per line. */
+#endif
+
+char *arg0; /* Last component of argv[0]. */
+int uid, gid; /* callers id. */
+int ex= 0; /* Exit status to be. */
+int istty; /* Output is on a terminal. */
+
+/* Safer versions of malloc and realloc: */
+
+void heaperr(void)
+{
+ fprintf(stderr, "%s: Out of memory\n", arg0);
+ exit(-1);
+}
+
+void *allocate(size_t n)
+/* Deliver or die. */
+{
+ void *a;
+
+ if ((a= malloc(n)) == nil) heaperr();
+ return a;
+}
+
+#define reallocate rllct /* Same as realloc under some compilers. */
+
+void *reallocate(void *a, size_t n)
+{
+ if ((a= realloc(a, n)) == nil) heaperr();
+ return a;
+}
+
+char allowed[] = "acdfgilnqrstu1ACFLMRTX";
+char flags[sizeof(allowed)];
+
+char arg0flag[] = "cfmrtx"; /* These in argv[0] go to upper case. */
+
+void setflags(char *flgs)
+{
+ int c;
+
+ while ((c= *flgs++) != 0) {
+ if (strchr(allowed, c) == nil) {
+ fprintf(stderr, "Usage: %s -[%s] [file ...]\n",
+ arg0, allowed);
+ exit(1);
+ } else
+ if (strchr(flags, c) == nil)
+ flags[strlen(flags)] = c;
+ }
+}
+
+int present(int f)
+{
+ return f == 0 || strchr(flags, f) != nil;
+}
+
+void report(char *f)
+/* Like perror(3), but in the style: "ls: junk: No such file or directory. */
+{
+ fprintf(stderr, "%s: %s: %s\n", arg0, f, strerror(errno));
+ ex= 1;
+}
+
+/* Two functions, uidname and gidname, translate id's to readable names.
+ * All names are remembered to avoid searching the password file.
+ */
+#define NNAMES (1 << (sizeof(int) + sizeof(char *)))
+enum whatmap { PASSWD, GROUP };
+
+struct idname { /* Hash list of names. */
+ struct idname *next;
+ char *name;
+ uid_t id;
+} *uids[NNAMES], *gids[NNAMES];
+
+char *idname(unsigned id, enum whatmap map)
+/* Return name for a given user/group id. */
+{
+ struct idname *i;
+ struct idname **ids= &(map == PASSWD ? uids : gids)[id % NNAMES];
+
+ while ((i= *ids) != nil && id < i->id) ids= &i->next;
+
+ if (i == nil || id != i->id) {
+ /* Not found, go look in the password or group map. */
+ char *name= nil;
+ char noname[3 * sizeof(uid_t)];
+
+ if (!present('n')) {
+ if (map == PASSWD) {
+ struct passwd *pw= getpwuid(id);
+
+ if (pw != nil) name= pw->pw_name;
+ } else {
+ struct group *gr= getgrgid(id);
+
+ if (gr != nil) name= gr->gr_name;
+ }
+ }
+ if (name == nil) {
+ /* Can't find it, weird. Use numerical "name." */
+ sprintf(noname, "%u", id);
+ name= noname;
+ }
+
+ /* Add a new id-to-name cell. */
+ i= allocate(sizeof(*i));
+ i->id= id;
+ i->name= allocate(strlen(name) + 1);
+ strcpy(i->name, name);
+ i->next= *ids;
+ *ids= i;
+ }
+ return i->name;
+}
+
+#define uidname(uid) idname((uid), PASSWD)
+#define gidname(gid) idname((gid), GROUP)
+
+/* Path name construction, addpath adds a component, delpath removes it.
+ * The string path is used throughout the program as the file under examination.
+ */
+
+char *path; /* Path name constructed in path[]. */
+int plen= 0, pidx= 0; /* Lenght/index for path[]. */
+
+void addpath(int *didx, char *name)
+/* Add a component to path. (name may also be a full path at the first call)
+ * The index where the current path ends is stored in *pdi.
+ */
+{
+ if (plen == 0) path= (char *) allocate((plen= 32) * sizeof(path[0]));
+
+ if (pidx == 1 && path[0] == '.') pidx= 0; /* Remove "." */
+
+ *didx= pidx; /* Record point to go back to for delpath. */
+
+ if (pidx > 0 && path[pidx-1] != '/') path[pidx++]= '/';
+
+ do {
+ if (*name != '/' || pidx == 0 || path[pidx-1] != '/') {
+ if (pidx == plen)
+ path= (char *) reallocate((void *) path,
+ (plen*= 2) * sizeof(path[0]));
+ path[pidx++]= *name;
+ }
+ } while (*name++ != 0);
+
+ --pidx; /* Put pidx back at the null. The path[pidx++]= '/'
+ * statement will overwrite it at the next call.
+ */
+}
+
+#define delpath(didx) (path[pidx= didx]= 0) /* Remove component. */
+
+int field = 0; /* (used to be) Fields that must be printed. */
+ /* (now) Effects triggered by certain flags. */
+
+#define F_INODE 0x001 /* -i */
+#define F_BLOCKS 0x002 /* -s */
+#define F_EXTRA 0x004 /* -X */
+#define F_MODE 0x008 /* -lMX */
+#define F_LONG 0x010 /* -l */
+#define F_GROUP 0x020 /* -g */
+#define F_BYTIME 0x040 /* -tuc */
+#define F_ATIME 0x080 /* -u */
+#define F_CTIME 0x100 /* -c */
+#define F_MARK 0x200 /* -F */
+#define F_TYPE 0x400 /* -T */
+#define F_DIR 0x800 /* -d */
+
+struct file { /* A file plus stat(2) information. */
+ struct file *next; /* Lists are made of them. */
+ char *name; /* Null terminated name. */
+ ino_t ino;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ nlink_t nlink;
+ dev_t rdev;
+ off_t size;
+ time_t mtime;
+ time_t atime;
+ time_t ctime;
+#if BSD
+ long blocks;
+#endif
+};
+
+void setstat(struct file *f, struct stat *stp)
+{
+ f->ino= stp->st_ino;
+ f->mode= stp->st_mode;
+ f->nlink= stp->st_nlink;
+ f->uid= stp->st_uid;
+ f->gid= stp->st_gid;
+ f->rdev= stp->st_rdev;
+ f->size= stp->st_size;
+ f->mtime= stp->st_mtime;
+ f->atime= stp->st_atime;
+ f->ctime= stp->st_ctime;
+#if BSD
+ f->blocks= stp->st_blocks;
+#endif
+}
+
+#define PAST (26*7*24*3600L) /* Half a year ago. */
+/* Between PAST and FUTURE from now a time is printed, otherwise a year. */
+#define FUTURE (15*60L) /* Fifteen minutes. */
+
+static char *timestamp(struct file *f)
+/* Transform the right time field into something readable. */
+{
+ struct tm *tm;
+ time_t t;
+ static time_t now;
+ static int drift= 0;
+ static char date[] = "Jan 19 2038";
+ static char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+ t= f->mtime;
+ if (field & F_ATIME) t= f->atime;
+ if (field & F_CTIME) t= f->ctime;
+
+ tm= localtime(&t);
+ if (--drift < 0) { time(&now); drift= 50; } /* limit time() calls */
+
+ if (t < now - PAST || t > now + FUTURE) {
+ sprintf(date, "%.3s %2d %4d",
+ month + 3*tm->tm_mon,
+ tm->tm_mday,
+ 1900 + tm->tm_year);
+ } else {
+ sprintf(date, "%.3s %2d %02d:%02d",
+ month + 3*tm->tm_mon,
+ tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ }
+ return date;
+}
+
+char *permissions(struct file *f)
+/* Compute long or short rwx bits. */
+{
+ static char rwx[] = "drwxr-x--x";
+
+ rwx[0] = ifmt(f->mode);
+ /* Note that rwx[0] is a guess for the more alien file types. It is
+ * correct for BSD4.3 and derived systems. I just don't know how
+ * "standardized" these numbers are.
+ */
+
+ if (field & F_EXTRA) { /* Short style */
+ int mode = f->mode, ucase= 0;
+
+ if (uid == f->uid) /* What group of bits to use. */
+ /* mode<<= 0, */
+ ucase= (mode<<3) | (mode<<6);
+ /* Remember if group or others have permissions. */
+ else
+ if (gid == f->gid)
+ mode<<= 3;
+ else
+ mode<<= 6;
+
+ rwx[1]= mode&S_IRUSR ? (ucase&S_IRUSR ? 'R' : 'r') : '-';
+ rwx[2]= mode&S_IWUSR ? (ucase&S_IWUSR ? 'W' : 'w') : '-';
+
+ if (mode&S_IXUSR) {
+ static char sbit[]= { 'x', 'g', 'u', 's' };
+
+ rwx[3]= sbit[(f->mode&(S_ISUID|S_ISGID))>>10];
+ if (ucase&S_IXUSR) rwx[3] += 'A'-'a';
+ } else
+ rwx[3]= f->mode&(S_ISUID|S_ISGID) ? '=' : '-';
+ rwx[4]= 0;
+ } else { /* Long form. */
+ char *p= rwx+1;
+ int mode= f->mode;
+
+ do {
+ p[0] = (mode & S_IRUSR) ? 'r' : '-';
+ p[1] = (mode & S_IWUSR) ? 'w' : '-';
+ p[2] = (mode & S_IXUSR) ? 'x' : '-';
+ mode<<= 3;
+ } while ((p+=3) <= rwx+7);
+
+ if (f->mode&S_ISUID) rwx[3]= f->mode&(S_IXUSR>>0) ? 's' : '=';
+ if (f->mode&S_ISGID) rwx[6]= f->mode&(S_IXUSR>>3) ? 's' : '=';
+ if (f->mode&S_ISVTX) rwx[9]= f->mode&(S_IXUSR>>6) ? 't' : '=';
+ }
+ return rwx;
+}
+
+void numeral(int i, char **pp)
+{
+ char itoa[3*sizeof(int)], *a=itoa;
+
+ do *a++ = i%10 + '0'; while ((i/=10) > 0);
+
+ do *(*pp)++ = *--a; while (a>itoa);
+}
+
+#define K 1024L /* A kilobyte counts in multiples of K */
+#define T 1000L /* A megabyte in T*K, a gigabyte in T*T*K */
+
+char *cxsize(struct file *f)
+/* Try and fail to turn a 32 bit size into 4 readable characters. */
+{
+ static char siz[] = "1.2m";
+ char *p= siz;
+ off_t z;
+
+ siz[1]= siz[2]= siz[3]= 0;
+
+ if (f->size <= 5*K) { /* <= 5K prints as is. */
+ numeral((int) f->size, &p);
+ return siz;
+ }
+ z= (f->size + K-1) / K;
+
+ if (z <= 999) { /* Print as 123k. */
+ numeral((int) z, &p);
+ *p = 'k'; /* Can't use 'K', looks bad */
+ } else
+ if (z*10 <= 99*T) { /* 1.2m (Try ls -X /dev/at0) */
+ z= (z*10 + T-1) / T; /* Force roundup */
+ numeral((int) z / 10, &p);
+ *p++ = '.';
+ numeral((int) z % 10, &p);
+ *p = 'm';
+ } else
+ if (z <= 999*T) { /* 123m */
+ numeral((int) ((z + T-1) / T), &p);
+ *p = 'm';
+ } else { /* 1.2g */
+ z= (z*10 + T*T-1) / (T*T);
+ numeral((int) z / 10, &p);
+ *p++ = '.';
+ numeral((int) z % 10, &p);
+ *p = 'g';
+ }
+ return siz;
+}
+
+/* Transform size of file to number of blocks. This was once a function that
+ * guessed the number of indirect blocks, but that nonsense has been removed.
+ */
+#if BSD
+#define nblocks(f) ((f)->blocks)
+#else
+#define nblocks(f) (((f)->size + BLOCK-1) / BLOCK)
+#endif
+
+/* From number of blocks to kilobytes. */
+#if BLOCK < 1024
+#define nblk2k(nb) (((nb) + (1024 / BLOCK - 1)) / (1024 / BLOCK))
+#else
+#define nblk2k(nb) ((nb) * (BLOCK / 1024))
+#endif
+
+static int (*CMP)(struct file *f1, struct file *f2);
+static int (*rCMP)(struct file *f1, struct file *f2);
+
+static void mergesort(struct file **al)
+/* This is either a stable mergesort, or thermal noise, I'm no longer sure.
+ * It must be called like this: if (L != nil && L->next != nil) mergesort(&L);
+ */
+{
+ /* static */ struct file *l1, **mid; /* Need not be local */
+ struct file *l2;
+
+ l1= *(mid= &(*al)->next);
+ do {
+ if ((l1= l1->next) == nil) break;
+ mid= &(*mid)->next;
+ } while ((l1= l1->next) != nil);
+
+ l2= *mid;
+ *mid= nil;
+
+ if ((*al)->next != nil) mergesort(al);
+ if (l2->next != nil) mergesort(&l2);
+
+ l1= *al;
+ for (;;) {
+ if ((*CMP)(l1, l2) <= 0) {
+ if ((l1= *(al= &l1->next)) == nil) {
+ *al= l2;
+ break;
+ }
+ } else {
+ *al= l2;
+ l2= *(al= &l2->next);
+ *al= l1;
+ if (l2 == nil) break;
+ }
+ }
+}
+
+int namecmp(struct file *f1, struct file *f2)
+{
+ return strcmp(f1->name, f2->name);
+}
+
+int mtimecmp(struct file *f1, struct file *f2)
+{
+ return f1->mtime == f2->mtime ? 0 : f1->mtime > f2->mtime ? -1 : 1;
+}
+
+int atimecmp(struct file *f1, struct file *f2)
+{
+ return f1->atime == f2->atime ? 0 : f1->atime > f2->atime ? -1 : 1;
+}
+
+int ctimecmp(struct file *f1, struct file *f2)
+{
+ return f1->ctime == f2->ctime ? 0 : f1->ctime > f2->ctime ? -1 : 1;
+}
+
+int typecmp(struct file *f1, struct file *f2)
+{
+ return ifmt(f1->mode) - ifmt(f2->mode);
+}
+
+int revcmp(struct file *f1, struct file *f2) { return (*rCMP)(f2, f1); }
+
+static void sort(struct file **al)
+/* Sort the files according to the flags. */
+{
+ if (!present('f') && *al != nil && (*al)->next != nil) {
+ CMP= namecmp;
+
+ if (!(field & F_BYTIME)) {
+ /* Sort on name */
+
+ if (present('r')) { rCMP= CMP; CMP= revcmp; }
+ mergesort(al);
+ } else {
+ /* Sort on name first, then sort on time. */
+
+ mergesort(al);
+ if (field & F_CTIME)
+ CMP= ctimecmp;
+ else
+ if (field & F_ATIME)
+ CMP= atimecmp;
+ else
+ CMP= mtimecmp;
+
+ if (present('r')) { rCMP= CMP; CMP= revcmp; }
+ mergesort(al);
+ }
+ /* Separate by file type if so desired. */
+
+ if (field & F_TYPE) {
+ CMP= typecmp;
+ mergesort(al);
+ }
+ }
+}
+
+struct file *newfile(char *name)
+/* Create file structure for given name. */
+{
+ struct file *new;
+
+ new= (struct file *) allocate(sizeof(*new));
+ new->name= strcpy((char *) allocate(strlen(name)+1), name);
+ return new;
+}
+
+void pushfile(struct file **flist, struct file *new)
+/* Add file to the head of a list. */
+{
+ new->next= *flist;
+ *flist= new;
+}
+
+void delfile(struct file *old)
+/* Release old file structure. */
+{
+ free((void *) old->name);
+ free((void *) old);
+}
+
+struct file *popfile(struct file **flist)
+/* Pop file off top of file list. */
+{
+ struct file *f;
+
+ f= *flist;
+ *flist= f->next;
+ return f;
+}
+
+int dotflag(char *name)
+/* Return flag that would make ls list this name: -a or -A. */
+{
+ if (*name++ != '.') return 0;
+
+ switch (*name++) {
+ case 0: return 'a'; /* "." */
+ case '.': if (*name == 0) return 'a'; /* ".." */
+ default: return 'A'; /* ".*" */
+ }
+}
+
+int adddir(struct file **aflist, char *name)
+/* Add directory entries of directory name to a file list. */
+{
+ DIR *d;
+ struct dirent *e;
+
+ if (access(name, 0) < 0) {
+ report(name);
+ return 0;
+ }
+
+ if ((d= opendir(name)) == nil) {
+ report(name);
+ return 0;
+ }
+ while ((e= readdir(d)) != nil) {
+ if (e->d_ino != 0 && present(dotflag(e->d_name))) {
+ pushfile(aflist, newfile(e->d_name));
+ aflist= &(*aflist)->next;
+ }
+ }
+ closedir(d);
+ return 1;
+}
+
+off_t countblocks(struct file *flist)
+/* Compute total block count for a list of files. */
+{
+ off_t cb = 0;
+
+ while (flist != nil) {
+ switch (flist->mode & S_IFMT) {
+ case S_IFDIR:
+ case S_IFREG:
+#ifdef S_IFLNK
+ case S_IFLNK:
+#endif
+ cb += nblocks(flist);
+ }
+ flist= flist->next;
+ }
+ return cb;
+}
+
+void printname(char *name)
+/* Print a name with control characters as '?' (unless -q). The terminal is
+ * assumed to be eight bit clean.
+ */
+{
+ int c, q= present('q');
+
+ while ((c= *name++) != 0) {
+ if (q && (c <= ' ' || c == 0177)) c= '?';
+ putchar(c);
+ }
+}
+
+int mark(struct file *f, int doit)
+{
+ int c;
+
+ if (!(field & F_MARK)) return 0;
+
+ switch (f->mode & S_IFMT) {
+ case S_IFDIR: c= '/'; break;
+#ifdef S_IFIFO
+ case S_IFIFO: c= '|'; break;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK: c= '@'; break;
+#endif
+#ifdef S_IFSOCK
+ case S_IFSOCK: c= '='; break;
+#endif
+ case S_IFREG:
+ if (f->mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+ c= '*';
+ break;
+ }
+ default:
+ c= 0;
+ }
+ if (doit && c != 0) putchar(c);
+ return c;
+}
+
+int colwidth[MAXCOLS]; /* Need colwidth[i] spaces to print column i. */
+int sizwidth[MAXCOLS]; /* Spaces for the size field in a -X print. */
+int namwidth[MAXCOLS]; /* Name field. */
+
+int maxise(int *aw, int w)
+/* Set *aw to the larger of it and w. Then return it. */
+{
+ if (w > *aw) *aw= w;
+ return *aw;
+}
+
+static int nsp= 0; /* This many spaces have not been printed yet. */
+#define spaces(n) (nsp= (n))
+#define terpri() (nsp= 0, putchar('\n')) /* No trailing spaces */
+
+void print1(struct file *f, int col, int doit)
+/* Either compute the number of spaces needed to print file f (doit == 0) or
+ * really print it (doit == 1).
+ */
+{
+ int width= 0, n;
+ char *p;
+
+ while (nsp>0) { putchar(' '); nsp--; }/* Fill gap between two columns */
+
+ if (field & F_INODE) {
+ if (doit) printf("%5d ", f->ino); else width+= 6;
+ }
+ if (field & F_BLOCKS) {
+ if (doit) printf("%4ld ", nblk2k(nblocks(f))); else width+= 5;
+ }
+ if (field & F_MODE) {
+ if (doit)
+ printf("%s ", permissions(f));
+ else
+ width+= (field & F_EXTRA) ? 5 : 11;
+ }
+ if (field & F_EXTRA) {
+ p= cxsize(f);
+ n= strlen(p)+1;
+
+ if (doit) {
+ n= sizwidth[col] - n;
+ while (n > 0) { putchar(' '); --n; }
+ printf("%s ", p);
+ } else
+ width+= maxise(&sizwidth[col], n);
+ }
+ if (field & F_LONG) {
+ if (doit) {
+ printf("%2d %-8s ", f->nlink, uidname(f->uid));
+ if (field & F_GROUP) printf("%-8s ", gidname(f->gid));
+
+ switch (f->mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+#ifdef S_IFMPB
+ case S_IFMPB:
+#endif
+#ifdef S_IFMPC
+ case S_IFMPC:
+#endif
+ printf("%3d, %3d ",
+ major(f->rdev), minor(f->rdev));
+ break;
+ default:
+ printf("%8ld ", (long) f->size);
+ }
+ printf("%s ", timestamp(f));
+ } else
+ width += (field & F_GROUP) ? 43 : 34;
+ }
+ n= strlen(f->name);
+ if (doit) {
+ printname(f->name);
+ if (mark(f, 1) != 0) n++;
+#ifdef S_IFLNK
+ if ((field & F_LONG) && (f->mode & S_IFMT) == S_IFLNK) {
+ char *buf;
+ int r, didx;
+
+ buf= (char *) allocate(((size_t) f->size + 1)
+ * sizeof(buf[0]));
+ addpath(&didx, f->name);
+ r= readlink(path, buf, (int) f->size);
+ delpath(didx);
+ if (r > 0) buf[r] = 0; else r=1, strcpy(buf, "?");
+ printf(" -> ");
+ printname(buf);
+ free((void *) buf);
+ n+= 4 + r;
+ }
+#endif
+ spaces(namwidth[col] - n);
+ } else {
+ if (mark(f, 0) != 0) n++;
+#ifdef S_IFLNK
+ if ((field & F_LONG) && (f->mode & S_IFMT) == S_IFLNK) {
+ n+= 4 + (int) f->size;
+ }
+#endif
+ width+= maxise(&namwidth[col], n + NSEP);
+ maxise(&colwidth[col], width);
+ }
+}
+
+int countfiles(struct file *flist)
+/* Return number of files in the list. */
+{
+ int n= 0;
+
+ while (flist != nil) { n++; flist= flist->next; }
+
+ return n;
+}
+
+struct file *filecol[MAXCOLS]; /* filecol[i] is list of files for column i. */
+int nfiles, nlines; /* # files to print, # of lines needed. */
+
+int columnise(struct file *flist, int nplin)
+/* Chop list of files up in columns. Note that 3 columns are used for 5 files
+ * even though nplin may be 4, filecol[3] will simply be nil.
+ */
+{
+ int i, j;
+
+ nlines= (nfiles + nplin - 1) / nplin; /* nlines needed for nfiles */
+
+ filecol[0]= flist;
+
+ for (i=1; i<nplin; i++) { /* Give nlines files to each column. */
+ for (j=0; j<nlines && flist != nil; j++) flist= flist->next;
+
+ filecol[i]= flist;
+ }
+}
+
+int print(struct file *flist, int nplin, int doit)
+/* Try (doit == 0), or really print the list of files over nplin columns.
+ * Return true if it can be done in nplin columns or if nplin == 1.
+ */
+{
+ register struct file *f;
+ register int i, totlen;
+
+ columnise(flist, nplin);
+
+ if (!doit) {
+ if (nplin==1 && !(field & F_EXTRA))
+ return 1; /* No need to try 1 column. */
+
+ for (i=0; i<nplin; i++)
+ colwidth[i]= sizwidth[i]= namwidth[i]= 0;
+ }
+ while (--nlines >= 0) {
+ totlen=0;
+
+ for (i=0; i<nplin; i++) {
+ if ((f= filecol[i]) != nil) {
+ filecol[i]= f->next;
+ print1(f, i, doit);
+ }
+ if (!doit && nplin>1) {
+ /* See if this line is not too long. */
+ totlen+= colwidth[i];
+ if (totlen > ncols+NSEP) return 0;
+ }
+ }
+ if (doit) terpri();
+ }
+ return 1;
+}
+
+enum depth { SURFACE, SURFACE1, SUBMERGED };
+enum state { BOTTOM, SINKING, FLOATING };
+
+void listfiles(struct file *flist, enum depth depth, enum state state)
+/* Main workhorse of ls, it sorts and prints the list of files. Flags:
+ * depth: working with the command line / just one file / listing dir.
+ * state: How "recursive" do we have to be.
+ */
+{
+ struct file *dlist= nil, **afl= &flist, **adl= &dlist;
+ int nplin;
+ static int white = 1; /* Nothing printed yet. */
+
+ /* Flush everything previously printed, so new error output will
+ * not intermix with files listed earlier.
+ */
+ fflush(stdout);
+
+ if (field != 0 || state != BOTTOM) { /* Need stat(2) info. */
+ while (*afl != nil) {
+ static struct stat st;
+ int r, didx;
+
+ addpath(&didx, (*afl)->name);
+
+ if ((r= status(path, &st)) < 0
+#ifdef S_IFLNK
+ && (status == lstat || lstat(path, &st) < 0)
+#endif
+ ) {
+ if (depth != SUBMERGED || errno != ENOENT)
+ report((*afl)->name);
+ delfile(popfile(afl));
+ } else {
+ setstat(*afl, &st);
+ afl= &(*afl)->next;
+ }
+ delpath(didx);
+ }
+ }
+ sort(&flist);
+
+ if (depth == SUBMERGED && (field & (F_BLOCKS | F_LONG)))
+ printf("total %ld\n", nblk2k(countblocks(flist)));
+
+ if (state == SINKING || depth == SURFACE1) {
+ /* Don't list directories themselves, list their contents later. */
+ afl= &flist;
+ while (*afl != nil) {
+ if (((*afl)->mode & S_IFMT) == S_IFDIR) {
+ pushfile(adl, popfile(afl));
+ adl= &(*adl)->next;
+ } else
+ afl= &(*afl)->next;
+ }
+ }
+
+ if ((nfiles= countfiles(flist)) > 0) {
+ /* Print files in how many columns? */
+ nplin= !present('C') ? 1 : nfiles < MAXCOLS ? nfiles : MAXCOLS;
+
+ while (!print(flist, nplin, 0)) nplin--; /* Try first */
+
+ print(flist, nplin, 1); /* Then do it! */
+ white = 0;
+ }
+
+ while (flist != nil) { /* Destroy file list */
+ if (state == FLOATING && (flist->mode & S_IFMT) == S_IFDIR) {
+ /* But keep these directories for ls -R. */
+ pushfile(adl, popfile(&flist));
+ adl= &(*adl)->next;
+ } else
+ delfile(popfile(&flist));
+ }
+
+ while (dlist != nil) { /* List directories */
+ if (dotflag(dlist->name) != 'a' || depth != SUBMERGED) {
+ int didx;
+
+ addpath(&didx, dlist->name);
+
+ flist= nil;
+ if (adddir(&flist, path)) {
+ if (depth != SURFACE1) {
+ if (!white) putchar('\n');
+ printf("%s:\n", path);
+ white = 0;
+ }
+ listfiles(flist, SUBMERGED,
+ state == FLOATING ? FLOATING : BOTTOM);
+ }
+ delpath(didx);
+ }
+ delfile(popfile(&dlist));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct file *flist= nil, **aflist= &flist;
+ enum depth depth;
+ char *lsflags;
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+#endif
+
+ uid= geteuid();
+ gid= getegid();
+
+ if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
+ argv++;
+
+ if (strcmp(arg0, "ls") != 0) {
+ char *p= arg0+1;
+
+ while (*p != 0) {
+ if (strchr(arg0flag, *p) != nil) *p += 'A' - 'a';
+ p++;
+ }
+ setflags(arg0+1);
+ }
+ while (*argv != nil && (*argv)[0] == '-') {
+ if ((*argv)[1] == '-' && (*argv)[2] == 0) {
+ argv++;
+ break;
+ }
+ setflags(*argv++ + 1);
+ }
+
+ istty= isatty(1);
+
+ if (istty && (lsflags= getenv("LSOPTS")) != nil) {
+ if (*lsflags == '-') lsflags++;
+ setflags(lsflags);
+ }
+
+ if (!present('1') && !present('C') && !present('l')
+ && (istty || present('M') || present('X') || present('F'))
+ ) setflags("C");
+
+ if (istty) setflags("q");
+
+ if (SUPER_ID == 0 || present('a')) setflags("A");
+
+ if (present('i')) field|= F_INODE;
+ if (present('s')) field|= F_BLOCKS;
+ if (present('M')) field|= F_MODE;
+ if (present('X')) field|= F_EXTRA|F_MODE;
+ if (present('t')) field|= F_BYTIME;
+ if (present('u')) field|= F_ATIME;
+ if (present('c')) field|= F_CTIME;
+ if (present('l')) {
+ field= (field | F_MODE | F_LONG) & ~F_EXTRA;
+ if (present('g')) field|= F_GROUP;
+ }
+ if (present('F')) field|= F_MARK;
+ if (present('T')) field|= F_TYPE;
+ if (present('d')) field|= F_DIR;
+
+#ifdef S_IFLNK
+ status= present('L') ? stat : lstat;
+#endif
+
+#ifdef TIOCGWINSZ
+ if (present('C')) {
+ int t= istty ? 1 : open("/dev/tty", O_WRONLY);
+
+ if (t >= 0 && ioctl(t, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0)
+ ncols= ws.ws_col - 1;
+
+ if (t != 1) close(t);
+ }
+#endif
+
+ depth= SURFACE;
+
+ if (*argv == nil) {
+ if (!(field & F_DIR)) depth= SURFACE1;
+ pushfile(aflist, newfile("."));
+ } else {
+ if (argv[1] == nil && !(field & F_DIR)) depth= SURFACE1;
+
+ do {
+ pushfile(aflist, newfile(*argv++));
+ aflist= &(*aflist)->next;
+ } while (*argv!=nil);
+ }
+ listfiles(flist, depth,
+ (field & F_DIR) ? BOTTOM : present('R') ? FLOATING : SINKING);
+ exit(ex);
+}
+/* Kees J. Bot 25-4-89. */
diff --git a/libc/tests/ouch.c b/libc/tests/ouch.c
new file mode 100644
index 0000000..c2925c6
--- /dev/null
+++ b/libc/tests/ouch.c
@@ -0,0 +1,27 @@
+
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+
+void trap()
+{
+ write(1, "Ouch!!\n", 7);
+}
+
+main()
+{
+ char buf[2];
+ int cc;
+
+ signal(SIGINT, trap);
+ while( (cc=read(0, buf, 1)) > 0 || (cc == -1 && errno == EINTR) )
+ {
+ if( cc < 0 )
+ fprintf(stderr, "INTR\n");
+ else
+ fprintf(stderr, "%x\n", buf[0]);
+ }
+
+
+ write(1, "\nExit!\n", 7);
+}
diff --git a/libc/tests/rand.c b/libc/tests/rand.c
new file mode 100644
index 0000000..c4fc6d2
--- /dev/null
+++ b/libc/tests/rand.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+FILE * popen();
+
+main()
+{
+ FILE * fd = popen("./hd", "w");
+ int ch;
+
+ srand(time((void*)0));
+
+ for(ch=0; ch<256; ch++)
+ putc(rand(), fd);
+
+ pclose(fd);
+}
diff --git a/libc/tests/size.c b/libc/tests/size.c
new file mode 100644
index 0000000..2d6676b
--- /dev/null
+++ b/libc/tests/size.c
@@ -0,0 +1,51 @@
+#include <fcntl.h>
+#include <a.out.h>
+
+void size(filename)
+ char *filename;
+{
+ int f;
+ struct exec ex;
+ long total;
+ int cc;
+
+ if ((f = open(filename, O_RDONLY)) < 0 )
+ {
+ perror(filename);
+ return;
+ }
+ cc = read(f, &ex, sizeof(ex));
+
+ if (cc == sizeof(ex) && !BADMAG(ex))
+ {
+ total = ex.a_text + ex.a_data + ex.a_bss;
+ printf("%-ld\t%-ld\t%-ld\t%-ld\t%-lx\t%s\n",
+ ex.a_text, ex.a_data, ex.a_bss, total, total,
+ filename);
+ }
+ else if( cc > 16 && memcmp(&ex, "\243\206\001\000*", 5) == 0 )
+ { /* *.o file */
+ total = ((unsigned char*)&ex)[9] +
+ ((unsigned char*)&ex)[10] * 256;
+ printf("\t\t\t%-ld\t%-lx\t%s\n",
+ total, total, filename);
+ }
+ else
+ printf("%s: Not an a.out file\n", filename);
+ close(f);
+}
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc < 2)
+ {
+ printf("Usage: %s file\n", argv[0]);
+ exit(1);
+ }
+ printf("text\tdata\tbss\tdec\thex\tfilename\n");
+ for (--argc, ++argv; argc > 0; --argc, ++argv)
+ size(*argv);
+ exit(0);
+}
diff --git a/libc/tests/sync.c b/libc/tests/sync.c
new file mode 100644
index 0000000..03ca096
--- /dev/null
+++ b/libc/tests/sync.c
@@ -0,0 +1 @@
+int main() { return sync(); }
diff --git a/libc/tests/ucomp.c b/libc/tests/ucomp.c
new file mode 100644
index 0000000..cc3eef8
--- /dev/null
+++ b/libc/tests/ucomp.c
@@ -0,0 +1,108 @@
+
+/*
+ * Uncompress program this is very very fast
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#define MAXLEN 255
+
+#define maxno 61000U
+#define USE_BSS
+
+#ifdef USE_BSS
+unsigned char fptr[maxno];
+#else
+unsigned char *fptr;
+#endif
+FILE * fd;
+int key;
+
+main(argc, argv)
+int argc;
+char ** argv;
+{
+#ifndef USE_BSS
+ fptr = (unsigned char * ) malloc(maxno);
+
+ if( fptr == 0 )
+ {
+ perror("Cannot allocate memory");
+ exit(1);
+ }
+#endif
+
+ if( argc < 2 )
+ {
+ fd = stdin;
+ key = getc(fd);
+ uncompress();
+ }
+ else
+ {
+ fd = fopen(argv[1], "r" );
+ if( fd == 0 ) { perror("Open failed"); exit(1); }
+
+ key = getc(fd);
+ uncompress();
+ }
+}
+
+/*
+
+ Uncompression routine -- v.v.fast
+*/
+
+uncompress()
+{
+ register unsigned char * mainscan;
+ register unsigned char * secondscan;
+ register unsigned char * ptr = (unsigned char * ) fptr;
+ register unsigned char * eptr = ptr+maxno;
+ register unsigned int len;
+ register int ch;
+
+ mainscan = ptr;
+
+ for(;;)
+ {
+ ch = getc(fd);
+ if(ch == EOF) break;
+ ch &= 0xFF;
+ if(ch == key)
+ {
+ ch = getc(fd);
+ if( ch == 0 )
+ *mainscan++ = key;
+ else
+ {
+ len = (unsigned char) getc(fd);
+ if( ch & 0x80 )
+ len += ((unsigned char) getc(fd)) << 8;
+ secondscan = mainscan - len;
+ if(len > mainscan - ptr) secondscan += maxno;
+ len = (unsigned char) ch & 0x7F;
+ for( ; len>0; len-- )
+ {
+ *mainscan++ = *secondscan++;
+ if( secondscan == eptr ) secondscan = ptr;
+ if( mainscan == eptr )
+ { write(1, ptr, (int)(mainscan-ptr)); mainscan = ptr; }
+ }
+ }
+ }
+ else
+ *mainscan++ = ch;
+
+ if( mainscan == eptr )
+ { write(1, ptr, (int)(mainscan-ptr)); mainscan = ptr; }
+ }
+ if( mainscan != ptr )
+ { write(1, ptr, (int)(mainscan-ptr)); mainscan = ptr; }
+}
+
diff --git a/libc/tests/wc.c b/libc/tests/wc.c
new file mode 100644
index 0000000..08b93ca
--- /dev/null
+++ b/libc/tests/wc.c
@@ -0,0 +1,133 @@
+
+#include <stdio.h>
+#include <ctype.h>
+
+int lflag; /* Want count lines */
+int wflag; /* Want count words */
+int cflag; /* Want count characters */
+
+long lcount; /* File count of lines */
+long wcount; /* File count of words */
+long ccount; /* File count of characters */
+
+long ltotal; /* Total count of lines */
+long wtotal; /* Total count of words */
+long ctotal; /* Total count of characters */
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ char *p;
+ int ar;
+
+ if (argc > 1 && argv[1][0] == '-')
+ {
+ for (p = argv[1] + 1; *p; p++)
+ {
+ switch (*p)
+ {
+ case 'l':
+ lflag++;
+ break;
+ case 'w':
+ wflag++;
+ break;
+ case 'c':
+ cflag++;
+ break;
+ default:
+ Usage();
+ }
+ }
+ argc--;
+ argv++;
+ }
+
+ /* If no flags are set, treat as wc -lwc. */
+ if (!lflag && !wflag && !cflag)
+ lflag = wflag = cflag = 1;
+
+ /* No filename, use stdin */
+ if (argc == 1)
+ {
+ count(stdin, "");
+ exit(0);
+ }
+
+ /* There is an explicit list of files. Loop on files. */
+ for (ar = 1; ar < argc; ar++)
+ {
+ FILE *f;
+
+ if ((f = fopen(argv[ar], "r")) == NULL)
+ fprintf(stderr, "wc: cannot open %s\n", argv[ar]);
+ else
+ {
+ count(f, argv[ar]);
+ fclose(f);
+ }
+ }
+
+ if (argc > 2)
+ {
+ if (lflag)
+ printf("%7ld ", ltotal);
+ if (wflag)
+ printf("%7ld ", wtotal);
+ if (cflag)
+ printf("%7ld ", ctotal);
+ printf("total\n");
+ }
+ exit(0);
+}
+
+count(f, fname)
+FILE *f;
+char *fname;
+{
+ register int c;
+ register int inword = 0;
+
+ lcount = 0;
+ wcount = 0;
+ ccount = 0;
+
+ while ((c = getc(f)) != EOF)
+ {
+ ccount++;
+
+ if (isspace(c))
+ {
+ if (inword)
+ wcount++;
+ inword = 0;
+ }
+ else
+ inword = 1;
+
+ if (c == '\n' || c == '\f')
+ lcount++;
+ }
+
+ ltotal += lcount;
+ wtotal += wcount;
+ ctotal += ccount;
+
+ if (lflag)
+ printf("%7ld ", lcount);
+ if (wflag)
+ printf("%7ld ", wcount);
+ if (cflag)
+ printf("%7ld ", ccount);
+ if (fname && *fname)
+ printf("%s", fname);
+ printf("\n");
+}
+
+Usage()
+{
+ fprintf(stderr, "Usage: wc [-lwc] [name ...]\n");
+ exit(1);
+}
diff --git a/libc/utmp/Makefile b/libc/utmp/Makefile
new file mode 100644
index 0000000..cbb16a8
--- /dev/null
+++ b/libc/utmp/Makefile
@@ -0,0 +1,24 @@
+# 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.
+
+TOP=..
+include $(TOP)/Make.defs
+
+OBJ=utent.o
+
+all: $(OBJ)
+
+libc.a: $(OBJ)
+ ar r ../$(LIBC) $(OBJ)
+ @touch libc.a
+
+%.o:%.c
+ifeq ($(PLATFORM),i386-Linux)
+ $(CC) $(CFLAGS) $< -c -o $@ $(WALL)
+else
+ $(CC) $(CFLAGS) $< -c -o $@ -ansi
+endif
+
+clean:
+ rm -f *.o libc.a
diff --git a/libc/utmp/utent.c b/libc/utmp/utent.c
new file mode 100644
index 0000000..7f9e19a
--- /dev/null
+++ b/libc/utmp/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);
+}
+
+