diff options
Diffstat (limited to 'libc')
288 files changed, 26833 insertions, 0 deletions
diff --git a/libc/COPYING b/libc/COPYING new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/libc/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/libc/Config_sh b/libc/Config_sh new file mode 100644 index 0000000..6c93784 --- /dev/null +++ b/libc/Config_sh @@ -0,0 +1,145 @@ +#!/bin/sh - +# Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> +# This file is part of the Linux-8086 C library and is distributed +# under the GNU Library General Public License. + +main() +{ + rm -f .config.tmp + ALLON=no + + if [ -f .config.lst ] + then grep '^[^:]*:+:' .config.lst > .config.tmp + if [ ! -s .config.tmp ] + then ALLON=yes + fi + else ALLON=yes + fi + + egrep -v '^#|^$' /dev/null */[Cc]onfig | \ + sed -e 's./.:.' -e 's/[ ]*:[ ]*/:/g' >> .config.tmp 2>/dev/null + ls */Makefile | sed 's-/Makefile-:+:+-' >> .config.tmp + sort .config.tmp > .config.lst + + unset_dups + + if [ ! -s .config.lst ] + then echo 'No configuration options' + exit 0 + fi + + CHANGED=0 + RUNNING=1 + [ "$DIST" != "" ] && { + RUNNING=0 + echo 'Using default configuration' + } + while [ $RUNNING = 1 ] + do + display + echo + echo -n 'Option to flip [or quit] >' + read n + v="" + case "$n" in + [qQ]* ) RUNNING=0 + ;; + [0-9] ) v=$n ;; + [0-9][0-9] ) v=$n ;; + * ) echo '\007' + ;; + esac + + if [ "$v" != "" ] + then set_option $v + fi + done + + if [ "$CHANGED" = 1 -a \( -f libc.a -o -f crt0.o \) ] + then echo ' + You should now run a "make clean" to clean out the libc.a +' + exit 1 + fi + + exit 0 +} + +display() +{ + clear + echo 'Configuration options' + echo + awk -F: < .config.lst '{ + if( $3 == "+" ) next; + if( $2 == "+" ) { flags[$1] = 1; next; } + + printf("%2d) ", ++count); + if( $1 in flags ) printf("(ON) "); + else printf("(OFF) "); + if( $2 == "Config" ) printf(" "); else printf("* "); + printf("%s\n", $4); + }' +} + +unset_dups() +{ + awk -F: < .config.lst '{ + if( $2 == "+" && $3 == "+") { if( noco[$1] != 1 ) noco[$1] = 2; next; } + if( $2 == "+" ) { flags[$1] = 1; next; } + if( "'$ALLON'" == "yes" && $2 == "Config" ) flags[$1] = 1; + + if( $1 in flags ) + { + if( $3 in gottype ) + ; + else + { + printf("%s:+:\n", $1); + gottype[$3] = 1; + } + } + noco[$1] = 1; + printf("%s\n", $0); + } END { + for(i in noco) + if( noco[i] == 2 ) + printf("%s:+:+\n", i); + }' | sort > .config.tmp + ALLON=no + mv -f .config.tmp .config.lst +} + +set_option() +{ + rm -f .config.tmp1 + awk -F: < .config.lst '{ + if( $2 == "+" && $3 == "+" ) { print $0; next; } + if( $2 == "+" ) { flags[$1] = 1; next; } + + if( ++cnt == '$1' ) + { + if( $1 in flags ) + ; + else + printf("%s:+:\n", $1) > ".config.tmp1"; + printf("%s\n", $0) > ".config.tmp1"; + } + else + { + if( $1 in flags ) + printf("%s:+:\n", $1); + printf("%s\n", $0); + } + }' > .config.tmp2 + if [ -f .config.tmp1 ] + then CHANGED=1 + else echo 'Cannot change that option!' + sleep 2 + fi + cat .config.tmp[12] > .config.lst + rm .config.tmp[12] + unset_dups +} + +main diff --git a/libc/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..319751e --- /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 +>28 long !0 not stripped +0 string \01\03\040\04 Linux-8086 executable +>28 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 +>28 long !0 not stripped +0 string \01\03\040\20 Minix-386 executable +>28 long !0 not stripped +# +#------------------------------------------------------------------------------ diff --git a/libc/Make.defs b/libc/Make.defs new file mode 100644 index 0000000..ff571d7 --- /dev/null +++ b/libc/Make.defs @@ -0,0 +1,108 @@ +# 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-BCC PLATFORM=i386-Linux + +PLATFORM=$(shell if [ -f $(TOP)/.config.otype ] ; \ + then cat $(TOP)/.config.otype ; \ + else echo i86-ELKS ; fi) +export PLATFORM +endif + +VERMAJOR=0 +VERMINOR=0 +VERPATCH=8 +VER=$(VERMAJOR).$(VERMINOR).$(VERPATCH) + +LIBDEFS='-D__LIBC__="$(VER)"' +LIBC=libc.a + +############################################################################## + +# Normal standard 8086 code +ifeq ($(PLATFORM),i86-ELKS) +ARCH= +LIB_CPU=i86 +LIB_OS=ELKS +endif + +# 8086 elks code With "Caller saves" and "First arg in AX" +ifeq ($(PLATFORM),i86-FAST) +ARCH=-Mf +LIBC=libc_f.a +LIB_CPU=i86 +LIB_OS=ELKS +endif + +# Standalone executable +ifeq ($(PLATFORM),i86-BIOS) +ARCH=-Ms +LIBC=libc_s.a +LIB_CPU=i86 +LIB_OS=BIOS +endif + +# MSDOS COM file (msdos libs don't support "First arg in AX") +ifeq ($(PLATFORM),i86-DOS) +ARCH=-Md +LIBC=libdos.a +LIB_CPU=i86 +LIB_OS=DOS +endif + +############################################################################## + +# BCC 386. +ifeq ($(PLATFORM),i386-BCC) +ARCH=-3 -N +LIB_CPU=i386 +LIB_OS=ELKS + +CC=bcc $(ARCH) +CCFLAGS=-I -I$(TOP)/include +LKFLAGS=-L -L$(TOP)/ +endif + +ifeq ($(PLATFORM),i386-Linux) +LIB_CPU=g386 +LIB_OS=ELKS + +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 ($(LIB_CPU),i86) +CC=bcc $(ARCH) +CCFLAGS=-I -I$(TOP)/include # -O +LKFLAGS=-L -L$(TOP)/ -s +endif + +ifeq ($(LIB_CPU),) +LIB_CPU=Unknown +LIB_OS=Unknown +LIBC=libc_X.a +CCFLAGS=-I$(TOP)/include +LKFLAGS= +endif + +CFLAGS=$(CCFLAGS) $(LIBDEFS) +LDFLAGS=$(LKFLAGS) + +.PRECIOUS: $(LIBC) diff --git a/libc/Makefile b/libc/Makefile new file mode 100644 index 0000000..d533320 --- /dev/null +++ b/libc/Makefile @@ -0,0 +1,103 @@ +# 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 KERNEL COPYING Contributors MAGIC \ + New_subdir Pre_main Config_sh + +all: .config.dir .config.otype $(TARGETS) + +install: all install_incl + install -d $(BCCHOME) + install -d $(LIBDIR)/$(LIB_CPU) + install -m 644 crt0.o $(LIBDIR)/$(LIB_CPU) + install -m 644 $(LIBC) $(LIBDIR)/$(LIB_CPU) + -install -d $(DIST)/usr/lib + -install -m 644 error/liberror.txt $(DIST)/usr/lib/liberror.txt + +# I've changed this so it'll be easier to make a binary dist. +old_install_incl: + rm -rf $(BCCHOME)/include + ln -s $(TOPDIR)/libc/include $(BCCHOME)/include + +install_incl: + rm -rf $(BCCHOME)/include + cp -pr include $(BCCHOME)/include + if [ -f kinclude/Used ] ; \ + then cp -pr kinclude/arch $(BCCHOME)/include/arch ; \ + else rm -rf $(BCCHOME)/include/linuxmt ; \ + ln -s $(ELKSSRC)/include/linuxmt $(BCCHOME)/include ; \ + fi + -chown -R root:root $(BCCHOME)/include 2>/dev/null + -chmod -R u=rwX,og=rX $(BCCHOME)/include + +tests: dummy + $(MAKE) -C tests + +dummy: + +$(LIBC): transfer .config.dir + @for i in `cat .config.dir` ; do \ + echo $(MAKE) -C $$i libc.a ; $(MAKE) -C $$i libc.a || exit 1 ; \ + done + +transfer: .config.dir + @echo Checking for transfers + @for i in `cat .config.dir`; do \ + grep -q '^transfer' $$i/Makefile && $(MAKE) -s -C $$i $@ ; \ + done ; echo -n + @[ -f kinclude/Used ] || \ + { rm -f include/linuxmt ; \ + ln -s $(ELKSSRC)/include/linuxmt include ; } + +realclean: noconfig clean dellib + +clean: + rm -f $(OBJ) $(LIBC) + @for i in */Makefile ; do \ + $(MAKE) -C `dirname $$i` $@ || exit 1 ; \ + done + +dellib: + rm -f libc*.a libdos.a + +############################################################################## + +.config.lst: Makefile Make.defs Config_sh + sh Config_sh + +config: + sh Config_sh + +noconfig: + rm -f .config.dir .config.lst .config.otype + +.config.dir: .config.lst + @grep '^[^:]*:+:' < .config.lst | sed 's/:.*//' > .config.dir + +.config.otype: dummy + @[ -f .config.otype ] || echo $(PLATFORM) > .config.otype + @[ "$(PLATFORM)" = "`cat .config.otype `" ] || $(MAKE) -$(MAKEFLAGS) clean + @rm -f .config.otype + @echo $(PLATFORM) > .config.otype + +dist: clean + -rm -f include/linuxmt + tar cf temp.tar \ + $(TXT) $(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 diff --git a/libc/New_subdir b/libc/New_subdir new file mode 100755 index 0000000..a28a5ec --- /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..0b3bec2 --- /dev/null +++ b/libc/Pre_main @@ -0,0 +1,66 @@ + +There is now support for calling functions before main and from inside the +exit() function. + +The exit processing uses the standard 'atexit' and 'on_exit' functions +see the normal man pages. + +Execution of code before main is Linux-8086 (actually BCC) specific; the +method works like this: + +/**********************/ +long global_var_that_needs_init; + +#ifdef __AS386_16__ +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word _init_vars ! Pointer to the autorun function + .word no_op ! Space filler cause segs are padded to 4 bytes. + .text ! So the function after is also in the correct seg. +#endasm +#endif + +#ifdef __AS386_32__ +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .long _init_vars ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +static void init_vars() +{ + time(&global_var_that_needs_init); +} +/**********************/ + +The most important part is that the asm code _MUST_ be compiled into the +same object file as the variable that is being initialised. + +If this is not so the init_vars function will not be linked in and will +not be executed. + +Also do note that the init functions are called in essentially random order +(It's actually the order that they appear in the executable) so you must be +careful not to call any routines that have their own autostart from inside +your autostart. Nevertheless you should try to ensure that your routines +will fail gracefully if they are called before the initilisation routine. + +If you do not know if a routine has an autostart create a test program +calling the routine and compile with: + + bcc -0 [other_stuff] -M test.c | sort +2 | more + +Look down the list for lines like this: + + crt0 ZP_safety 1 00000000 R + crt0 auto_start 1 00000008 R + objname auto_func 1 00000008 R <<**** + crt0 data_start 2 00000010 R + crt0 _environ 3 00000010 R + +The line marked is an autostart function call. + +Robert. diff --git a/libc/README b/libc/README new file mode 100644 index 0000000..0b65f99 --- /dev/null +++ b/libc/README @@ -0,0 +1,72 @@ +The lib can be compiled six different ways for Linux-8086 standard, +Linux-8086 with 'First arg in AX', Linx-8086 standalone, MS-DOS, BCC-386 +or for GNU-386. At the moment the 386 GNU version will NOT work, the +BCC-386 is just barely working. + +This can be done by running one of. + make PLATFORM=i86-FAST clean all + make PLATFORM=i86-DOS clean all + make PLATFORM=i86-BIOS clean all + make PLATFORM=i386-BCC clean all + +SYSTEM CALLS +The system call table (syscalls/syscall.dat) is constantly changing, using +skewed versions is _very_ likely to give you segfaults and strange behaviour. +For this lib you should use the same version of elksemu. +The system call table will only be frozen when the linux-86 kernel is +running and reasonably stable. The 386 version is using a distinct list +that matches the Linux-i386 syscall list. + +THE COMPILER +You should use the versions of bcc, unproto, as86, ld86 and elksemu that +are in this version of the combined development environment. Some other +versions will work but often they'll just appear to work or not work at +all. The standard bcc-cc1 won't pickup the right header files, the +standard ld86 won't generate COM files or 386-Linux files and looks in +the wrong place for crt0.o and libc.a. + +Main Subdirectories. + +bcc Lots of BCC helper functions +bios Minimal 'system' calls for standalone executables. +error The C error functions. +grp Routines for /etc/group, from Nat +i386fp BCC's floating point routines for 386 code. +include Some include files, some new others Glib or Glib hacked. +kinclude Kernel include files, here for now. +malloc1 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 +stdio2 My standard I/O +string The functions for string.h +syscall All the system call functions, and some tied lib ones. +termios Termimal mode control. +utmp /etc/utmp updating +time Unix time related functions. +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. + + The exit(rv) function is already defined. It will call the contents + of the function pointer (*__cleanup)() before it calls _exit(); + This pointer should be used through the 'atexit' or 'on_exit' lib + functions. (See standard man pages) + + If you need to call something before main see the file 'Pre_main'. + +-Robert + +-=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- -=*=- diff --git a/libc/bcc/Config b/libc/bcc/Config new file mode 100644 index 0000000..0bfed09 --- /dev/null +++ b/libc/bcc/Config @@ -0,0 +1,2 @@ + +bcclib: Library of bcc helper functions diff --git a/libc/bcc/Makefile b/libc/bcc/Makefile new file mode 100644 index 0000000..991b50e --- /dev/null +++ b/libc/bcc/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 +CFLAGS=$(CCFLAGS) + +# Support for integer arithmetic +ifeq ($(LIB_CPU),i86) +IOBJ=__idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o +ISRC=bcc_int.c +endif + +# Support for integer arithmetic when compiling for the i386 +ifeq ($(LIB_CPU),i386) +ISRC=bcc_i386.c +IOBJ=__idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o \ + __divsi3.o +endif + +# Support for long arithmetic on little-endian (normal) longs +LSRC=bcc_long.c +LOBJ=__laddl.o __landl.o __lcmpl.o __lcoml.o __ldecl.o __ldivl.o __ldivul.o \ + __leorl.o __lincl.o __lmodl.o __lmodul.o __lmull.o __lnegl.o __lorl.o \ + __lsll.o __lsrl.o __lsrul.o __lsubl.o __ltstl.o + +# Memory allocation primitives +AOBJ=errno.o __brk_addr.o sbrk.o brk.o +ASRC=heap.c + +# Support for long arithmetic on big-endian (words-swapped) longs +RSRC=bcc_bsw.c +ROBJ=__laddb.o __landb.o __lcmpb.o __lcomb.o __ldecb.o __ldivb.o __ldivub.o \ + __leorb.o __lincb.o __lmodb.o __lmodub.o __lmulb.o __lnegb.o __lorb.o \ + __lslb.o __lsrb.o __lsrub.o __lsubb.o __ltstb.o + +# Miscellaneous I/O and far access junk +PSRC=bcc_io.c +POBJ=__inport.o __inportb.o __outport.o __outportb.o __peekb.o __peekw.o \ + __pokeb.o __pokew.o + +ifeq ($(LIB_CPU),i86) +OBJ=__ldivmod.o $(IOBJ) $(LOBJ) $(AOBJ) +endif +ifeq ($(LIB_CPU),i386) +OBJ=$(IOBJ) $(AOBJ) +endif + +OLDOBJ=$(ROBJ) $(POBJ) + +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_i386.c b/libc/bcc/bcc_i386.c new file mode 100644 index 0000000..d994628 --- /dev/null +++ b/libc/bcc/bcc_i386.c @@ -0,0 +1,149 @@ +/************************************************************************/ +/* This file contains the BCC compiler helper functions */ +/* Support for 386 integer arithmetic + * __divsi3.o __idiv.o __idivu.o __imod.o __imodu.o __imul.o + * __isl.o __isr.o __isru.o + */ + +#ifdef __AS386_32__ +#asm + .text ! This is common to all. + .align 4 +#endasm + +#ifdef L___divsi3 +#asm +! divsi3.s + .globl ___divsi3 + ___divsi3: + push edx + mov eax,[esp+4+4] + cdq + idiv [esp+4+4+4] + pop edx + ret + + .globl ___udivsi3 + .text + .align 4 + + ___udivsi3: + push edx + mov eax,[esp+4+4] + sub edx,edx + div [esp+4+4+4] + pop edx + ret +#endasm +#endif + +#ifdef L___idiv +#asm +! idiv.s +! idiv_ doesn`t preserve edx (returns remainder in it) + + .globl idiv_ +idiv_: + cdq + idiv ebx + ret +#endasm +#endif + +#ifdef L___idivu +#asm +! idivu.s +! idiv_u doesn`t preserve edx (returns remainder in it) + + .globl idiv_u +idiv_u: + xor edx,edx + div ebx + ret +#endasm +#endif + +#ifdef L___imod +#asm +! imod.s +! imod doesn`t preserve edx (returns quotient in it) + + .globl imod +imod: + cdq + idiv ebx + mov eax,edx ! instruction queue full so xchg slower + ret +#endasm +#endif + +#ifdef L___imodu +#asm +! imodu.s +! imodu doesn`t preserve edx (returns quotient in it) + + .globl imodu +imodu: + xor edx,edx + div ebx + mov eax,edx ! instruction queue full so xchg slower + ret +#endasm +#endif + +#ifdef L___imul +#asm +! imul.s +! imul_, imul_u don`t preserve edx + + .globl imul_ + .globl imul_u +imul_: +imul_u: + imul ebx + ret +#endasm +#endif + +#ifdef L___isl +#asm +! isl.s +! isl, islu don`t preserve cl + + .globl isl + .globl islu +isl: +islu: + mov cl,bl + shl eax,cl + ret +#endasm +#endif + +#ifdef L___isr +#asm +! isr.s +! isr doesn`t preserve cl + + .globl isr +isr: + mov cl,bl + sar eax,cl + ret +#endasm +#endif + +#ifdef L___isru +#asm +! isru.s +! isru doesn`t preserve cl + + .globl isru +isru: + mov cl,bl + shr eax,cl + ret +#endasm +#endif + +#endif diff --git a/libc/bcc/bcc_int.c b/libc/bcc/bcc_int.c new file mode 100644 index 0000000..abdb7b4 --- /dev/null +++ b/libc/bcc/bcc_int.c @@ -0,0 +1,162 @@ +/************************************************************************/ +/* This file contains the BCC compiler helper functions */ +/* Support for integer arithmetic + * __idiv.o __idivu.o __imod.o __imodu.o __imul.o __isl.o __isr.o __isru.o + */ + +#ifdef __AS386_16__ +#asm + .text ! This is common to all. + .even +#endasm + +/************************************************************************/ +/* Function idiv */ + +#ifdef L___idiv +#asm + +| idiv.s +| idiv_ doesn`t preserve dx (returns remainder in it) + + .globl idiv_ + +idiv_: + cwd + idiv bx + ret +#endasm +#endif + +/************************************************************************/ +/* Function idivu */ + +#ifdef L___idivu +#asm + +| idivu.s +| idiv_u doesn`t preserve dx (returns remainder in it) + + .globl idiv_u + +idiv_u: + xor dx,dx + div bx + ret +#endasm +#endif + +/************************************************************************/ +/* Function imod */ + +#ifdef L___imod +#asm + +| imod.s +| imod doesn`t preserve dx (returns quotient in it) + + .globl imod + +imod: + cwd + idiv bx + mov ax,dx + ret +#endasm +#endif + +/************************************************************************/ +/* Function imodu */ + +#ifdef L___imodu +#asm + +| imodu.s +| imodu doesn`t preserve dx (returns quotient in it) + + .globl imodu + +imodu: + xor dx,dx + div bx + mov ax,dx ! instruction queue full so xchg slower + ret +#endasm +#endif + +/************************************************************************/ +/* Function imul */ + +#ifdef L___imul +#asm + +| imul.s +| imul_, imul_u don`t preserve dx + + .globl imul_ + .globl imul_u + +imul_: +imul_u: + imul bx + ret +#endasm +#endif + +/************************************************************************/ +/* Function isl */ + +#ifdef L___isl +#asm + +| isl.s +| isl, islu don`t preserve cl + + .globl isl + .globl islu + +isl: +islu: + mov cl,bl + shl ax,cl + ret +#endasm +#endif + +/************************************************************************/ +/* Function isr */ + +#ifdef L___isr +#asm + +| isr.s +| isr doesn`t preserve cl + + .globl isr + +isr: + mov cl,bl + sar ax,cl + ret +#endasm +#endif + +/************************************************************************/ +/* Function isru */ + +#ifdef L___isru +#asm + +| isru.s +| isru doesn`t preserve cl + + .globl isru + +isru: + mov cl,bl + shr ax,cl + ret +#endasm +#endif + +#endif diff --git a/libc/bcc/bcc_io.c b/libc/bcc/bcc_io.c new file mode 100644 index 0000000..af5dfd2 --- /dev/null +++ b/libc/bcc/bcc_io.c @@ -0,0 +1,189 @@ +/************************************************************************/ +/* This file contains the BCC compiler helper functions */ +/* Miscellaneous obsolete junk + * __inport.o __inportb.o __outport.o __outportb.o __peekb.o __peekw.o + * __pokeb.o __pokew.o + */ + +#ifdef __AS368_16__ +#if !__FIRST_ARG_IN_AX__ +#asm + .text ! This is common to all. + .even +#endasm + +/************************************************************************/ +/* Function inport */ + +#ifdef L___inport +#asm + +| int inport( int port ); +| reads a word from the i/o port port and returns it + + .globl _inport +_inport: + pop bx + pop dx + dec sp + dec sp + inw + jmp bx +#endasm +#endif + +/************************************************************************/ +/* Function inportb */ + +#ifdef L___inportb +#asm + +| int inportb( int port ); +| reads a byte from the i/o port port and returns it + + .globl _inportb +_inportb: + pop bx + pop dx + dec sp + dec sp + in + sub ah,ah + jmp bx +#endasm +#endif + +/************************************************************************/ +/* Function outport */ + +#ifdef L___outport +#asm + +| void outport( int port, int value ); +| writes the word value to the i/o port port + + .globl _outport +_outport: + pop bx + pop dx + pop ax + sub sp,*4 + outw + jmp bx +#endasm +#endif + +/************************************************************************/ +/* Function outportb */ + +#ifdef L___outportb +#asm + +| void oportb( int port, char value ); +| writes the byte value to the i/o port port +| this would be outportb except for feeble linkers + + .globl _oportb +_oportb: + pop bx + pop dx + pop ax + sub sp,*4 + out + jmp bx +#endasm +#endif + +/************************************************************************/ +/* Function peekb */ + +#ifdef L___peekb +#asm + +| int peekb( unsigned segment, char *offset ); +| returns the (unsigned) byte at the far pointer segment:offset + + .define _peekb +_peekb: + mov cx,ds + pop dx + pop ds + pop bx + sub sp,*4 + movb al,(bx) + subb ah,ah + mov ds,cx + jmp dx +#endasm +#endif + +/************************************************************************/ +/* Function peekw */ + +#ifdef L___peekw +#asm + +| int peekw( unsigned segment, int *offset ); +| returns the word at the far pointer segment:offset + + .define _peekw +_peekw: + mov cx,ds + pop dx + pop ds + pop bx + sub sp,*4 + mov ax,(bx) + mov ds,cx + jmp dx +#endasm +#endif + +/************************************************************************/ +/* Function pokeb */ + +#ifdef L___pokeb +#asm + +| void pokeb( unsigned segment, char *offset, char value ); +| writes the byte value at the far pointer segment:offset + + .define _pokeb +_pokeb: + mov cx,ds + pop dx + pop ds + pop bx + pop ax + sub sp,*6 + movb (bx),al + mov ds,cx + jmp dx +#endasm +#endif + +/************************************************************************/ +/* Function pokew */ + +#ifdef L___pokew +#asm + +| void pokew( unsigned segment, int *offset, int value ); +| writes the word value at the far pointer segment:offset + + .define _pokew +_pokew: + mov cx,ds + pop dx + pop ds + pop bx + pop ax + sub sp,*6 + mov (bx),ax + mov ds,cx + jmp dx +#endasm +#endif + +#endif /* !__FIRST_ARG_IN_AX__ */ +#endif diff --git a/libc/bcc/bcc_long.c b/libc/bcc/bcc_long.c new file mode 100644 index 0000000..4b6ceae --- /dev/null +++ b/libc/bcc/bcc_long.c @@ -0,0 +1,479 @@ +/************************************************************************/ +/* This file contains the BCC compiler helper functions */ +/* Support for long arithmetic on little-endian (normal) longs + * __laddl.o __landl.o __lcmpl.o __lcoml.o __ldecl.o __ldivl.o __ldivul.o + * __leorl.o __lincl.o __lmodl.o __lmodul.o __lmull.o __lnegl.o __lorl.o + * __lsll.o __lsrl.o __lsrul.o __lsubl.o __ltstl.o + */ + +#ifdef __AS386_16__ +#asm + .text ! This is common to all. + .even +#endasm + +/************************************************************************/ +/* Function laddl */ + +#ifdef L___laddl +#asm + +| laddl.s + + .globl laddl + .globl laddul + +laddl: +laddul: + add ax,[di] + adc bx,2[di] + ret +#endasm +#endif + +/************************************************************************/ +/* Function landl */ + +#ifdef L___landl +#asm + +| landl.s + + .globl landl + .globl landul + +landl: +landul: + and ax,[di] + and bx,2[di] + ret +#endasm +#endif + +/************************************************************************/ +/* Function lcmpl */ + +#ifdef L___lcmpl +#asm + +| lcmpl.s +| lcmpl, lcmpul don`t preserve bx + + .globl lcmpl + .globl lcmpul + +lcmpl: +lcmpul: + sub bx,2[di] + je LCMP_NOT_SURE + ret + + .even + +LCMP_NOT_SURE: + cmp ax,[di] + jb LCMP_B_AND_LT + jge LCMP_EXIT + + inc bx +LCMP_EXIT: + ret + + .even + +LCMP_B_AND_LT: + dec bx + ret +#endasm +#endif + +/************************************************************************/ +/* Function lcoml */ + +#ifdef L___lcoml +#asm + +| lcoml.s + + .globl lcoml + .globl lcomul + +lcoml: +lcomul: + not ax + not bx + ret +#endasm +#endif + +/************************************************************************/ +/* Function ldecl */ + +#ifdef L___ldecl +#asm + +| ldecl.s + + .globl ldecl + .globl ldecul + +ldecl: +ldecul: + cmp word ptr [bx],*0 + je LDEC_BOTH + dec word ptr [bx] + ret + + .even + +LDEC_BOTH: + dec word ptr [bx] + dec word ptr 2[bx] + ret +#endasm +#endif + +/************************************************************************/ +/* Function ldivl */ + +#ifdef L___ldivl +#asm + +| ldivl.s +| bx:ax / 2(di):(di), quotient bx:ax, remainder di:cx, dx not preserved + + .globl ldivl + .extern ldivmod + +ldivl: + mov cx,[di] + mov di,2[di] + call ldivmod + xchg ax,cx + xchg bx,di + ret + +#endasm +#endif + +/************************************************************************/ +/* Function ldivul */ + +#ifdef L___ldivul +#asm + +| ldivul.s +| unsigned bx:ax / 2(di):(di), quotient bx:ax,remainder di:cx, dx not preserved + + .globl ldivul + .extern ludivmod + +ldivul: + mov cx,[di] + mov di,2[di] + call ludivmod + xchg ax,cx + xchg bx,di + ret +#endasm +#endif + +/************************************************************************/ +/* Function leorl */ + +#ifdef L___leorl +#asm + +| leorl.s + + .globl leorl + .globl leorul + +leorl: +leorul: + xor ax,[di] + xor bx,2[di] + ret +#endasm +#endif + +/************************************************************************/ +/* Function lincl */ + +#ifdef L___lincl +#asm + +| lincl.s + + .globl lincl + .globl lincul + +lincl: +lincul: + inc word ptr [bx] + je LINC_HIGH_WORD + ret + + .even + +LINC_HIGH_WORD: + inc word ptr 2[bx] + ret +#endasm +#endif + +/************************************************************************/ +/* Function lmodl */ + +#ifdef L___lmodl +#asm + +| lmodl.s +| bx:ax % 2(di):(di), remainder bx:ax, quotient di:cx, dx not preserved + + .globl lmodl + .extern ldivmod + +lmodl: + mov cx,[di] + mov di,2[di] + call ldivmod + ret +#endasm +#endif + +/************************************************************************/ +/* Function lmodul */ + +#ifdef L___lmodul +#asm + +| lmodul.s +| unsigned bx:ax / 2(di):(di), remainder bx:ax,quotient di:cx, dx not preserved + + .globl lmodul + .extern ludivmod + +lmodul: + mov cx,[di] + mov di,2[di] + call ludivmod + ret +#endasm +#endif + +/************************************************************************/ +/* Function lmull */ + +#ifdef L___lmull +#asm + +| lmull.s +| lmull, lmulul don`t preserve cx, dx + + .globl lmull + .globl lmulul + +lmull: +lmulul: + mov cx,ax + mul word ptr 2[di] + xchg ax,bx + mul word ptr [di] + add bx,ax + mov ax,ptr [di] + mul cx + add bx,dx + ret +#endasm +#endif + +/************************************************************************/ +/* Function lnegl */ + +#ifdef L___lnegl +#asm + +| lnegl.s + + .globl lnegl + .globl lnegul + +lnegl: +lnegul: + neg bx + neg ax + sbb bx,*0 + ret +#endasm +#endif + +/************************************************************************/ +/* Function lorl */ + +#ifdef L___lorl +#asm + +| lorl.s + + .globl lorl + .globl lorul + +lorl: +lorul: + or ax,[di] + or bx,2[di] + ret +#endasm +#endif + +/************************************************************************/ +/* Function lsll */ + +#ifdef L___lsll +#asm + +| lsll.s +| lsll, lslul don`t preserve cx + + .globl lsll + .globl lslul + +lsll: +lslul: + mov cx,di + jcxz LSL_EXIT + cmp cx,*32 + jae LSL_ZERO +LSL_LOOP: + shl ax,*1 + rcl bx,*1 + loop LSL_LOOP +LSL_EXIT: + ret + + .even + +LSL_ZERO: + xor ax,ax + mov bx,ax + ret +#endasm +#endif + +/************************************************************************/ +/* Function lsrl */ + +#ifdef L___lsrl +#asm + +| lsrl.s +| lsrl doesn`t preserve cx + + .globl lsrl + +lsrl: + mov cx,di + jcxz LSR_EXIT + cmp cx,*32 + jae LSR_SIGNBIT +LSR_LOOP: + sar bx,*1 + rcr ax,*1 + loop LSR_LOOP +LSR_EXIT: + ret + + .even + +LSR_SIGNBIT: + mov cx,*32 + j LSR_LOOP +#endasm +#endif + +/************************************************************************/ +/* Function lsrul */ + +#ifdef L___lsrul +#asm + +| lsrul.s +| lsrul doesn`t preserve cx + + .globl lsrul + +lsrul: + mov cx,di + jcxz LSRU_EXIT + cmp cx,*32 + jae LSRU_ZERO +LSRU_LOOP: + shr bx,*1 + rcr ax,*1 + loop LSRU_LOOP +LSRU_EXIT: + ret + + .even + +LSRU_ZERO: + xor ax,ax + mov bx,ax + ret +#endasm +#endif + +/************************************************************************/ +/* Function lsubl */ + +#ifdef L___lsubl +#asm + +| lsubl.s + + .globl lsubl + .globl lsubul + +lsubl: +lsubul: + sub ax,[di] + sbb bx,2[di] + ret +#endasm +#endif + +/************************************************************************/ +/* Function ltstl */ + +#ifdef L___ltstl +#asm + +| ltstl.s +| ltstl, ltstul don`t preserve bx + + .globl ltstl + .globl ltstul + +ltstl: +ltstul: + test bx,bx + je LTST_NOT_SURE + ret + + .even + +LTST_NOT_SURE: + test ax,ax + js LTST_FIX_SIGN + ret + + .even + +LTST_FIX_SIGN: + inc bx + ret +#endasm +#endif + +#endif diff --git a/libc/bcc/heap.c b/libc/bcc/heap.c new file mode 100644 index 0000000..6a6ce2c --- /dev/null +++ b/libc/bcc/heap.c @@ -0,0 +1,184 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <errno.h> + +/****************************************************************************/ + +#ifdef L_errno +int errno = 0; /* libc error value */ +#endif + +/****************************************************************************/ + +#ifdef __AS386_16__ + +#ifdef L___brk_addr +#asm +.data +export brk_addr +brk_addr: .word __end ! This holds the current return for sbrk(0) +.text +#endasm +#endif + +/****************************************************************************/ + +#ifdef L_sbrk +int sbrk(brk_off) +int brk_off; +{ +#asm + mov bx,sp +#if !__FIRST_ARG_IN_AX__ + mov ax,[bx+2] ! Fetch the requested value +#endif + test ax,ax + jnz has_change + mov ax,[brk_addr] ! Simple one, read current - can`t fail. + jmp eof + +has_change: + js go_down + add ax,[brk_addr] ! Goin up! + jc Enomem + sub bx,#512 ! Safety space 512 bytes + 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 + +/****************************************************************************/ + +#ifdef L_brk +int +brk(new_brk) +char * new_brk; +{ +#asm + mov bx,sp +#if !__FIRST_ARG_IN_AX__ + mov ax,[bx+2] ! Fetch the requested value +#endif + sub bx,#512 ! Safety space 512 bytes + cmp bx,ax ! Too close ? + jb Enomem + cmp ax,#__end + jae brk_ok +Enomem: + mov ax,#12 ! This should be ENOMEM not a magic. + mov [_errno],ax + mov ax,#-1 + ret +brk_ok: +#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 + +/****************************************************************************/ + +#ifdef __AS386_32__ +extern char * __brk_addr; +extern char * __brk(); + +#ifdef L___brk_addr +char * __brk_addr = 0; /* This holds the current return for sbrk(0) */ + +char * +__brk(val) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov ebx,eax +#else + mov ebx,[esp+4] +#endif + mov eax,#45 + int $80 +#endasm +} + +__brk_addr_init() +{ + if( __brk_addr == 0 && (__brk_addr = __brk(0)) == 0 ) + { + errno = ENOMEM; + return -1; + } + return 0; +} +#endif + +#ifdef L_sbrk +char * +sbrk(brk_off) +int brk_off; +{ + char * new_brk; + if( __brk_addr_init() ) return (char*)-1; + if( brk_off == 0 ) return __brk_addr; + + new_brk = __brk_addr + brk_off; + __brk_addr = __brk(new_brk); + if( __brk_addr != new_brk ) + { + errno = ENOMEM; + return (char*)-1; + } + return __brk_addr - brk_off; +} +#endif + +#ifdef L_brk +int +brk(new_brk) +char * new_brk; +{ + if( __brk_addr_init() ) return -1; + + __brk_addr = __brk(new_brk); + if( __brk_addr == new_brk ) return 0; + errno = ENOMEM; + return -1; +} +#endif + +#endif diff --git a/libc/bcc/ldiv.c b/libc/bcc/ldiv.c new file mode 100644 index 0000000..aab0701 --- /dev/null +++ b/libc/bcc/ldiv.c @@ -0,0 +1,30 @@ + +#ifdef __AS386_16__ +#asm +.text +export _ldiv +_ldiv: + push bp + mov bp,sp + push di + push si + mov ax,[bp+6] + mov bx,[bp+8] + mov cx,[bp+10] + mov di,[bp+12] + call ldivmod + mov si,[bp+4] + mov [si],cx + mov [si+2],di + mov [si+4],ax + mov [si+6],bx + mov ax,si + pop si + pop di + pop bp + ret +.data +.bss +#endasm +#endif + diff --git a/libc/bios/Config b/libc/bios/Config new file mode 100644 index 0000000..e7f1971 --- /dev/null +++ b/libc/bios/Config @@ -0,0 +1 @@ +bios: Minimal syscalls for BIOS level diff --git a/libc/bios/Makefile b/libc/bios/Makefile new file mode 100644 index 0000000..934ec07 --- /dev/null +++ b/libc/bios/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 + +ifeq ($(LIB_OS),BIOS) +ASRC=bios.c +AOBJ=bios_start.o bios_isatty.o \ + bios_open.o bios_read.o bios_write.o bios_lseek.o bios_close.o + +BSRC=bios_vid.c +BOBJ=bios_putc.o bios_getc.o bios_rdline.o +endif + +all: $(AOBJ) $(BOBJ) + +libc.a: $(AOBJ) $(BOBJ) + ar r ../$(LIBC) $(AOBJ) $(BOBJ) + @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/bios/README b/libc/bios/README new file mode 100644 index 0000000..cc883e1 --- /dev/null +++ b/libc/bios/README @@ -0,0 +1,10 @@ +Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk> +This file is part of the Linux-8086 C library and is distributed +under the GNU Library General Public License. + +This is a very simple set of functions for standalone executables. + +There is a choice as to which console type you want to use, I think +the VT52 clone is best. + +-Robert diff --git a/libc/bios/bios.c b/libc/bios/bios.c new file mode 100644 index 0000000..18e2448 --- /dev/null +++ b/libc/bios/bios.c @@ -0,0 +1,205 @@ +/* Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#if !__FIRST_ARG_IN_AX__ +#ifdef __AS386_16__ +#ifdef __STANDALONE__ + +#include <dos.h> +#include <fcntl.h> +#include <errno.h> +int errno; + +#ifdef L_bios_start +char ** environ = { 0 }; + +void (*__cleanup)() = 0; + +#asm + .data +export ___argr +___argr: + .word 0,0,0,0,0,0,0 ! A struct REGS +defarg: + .word boot_str, 0 +boot_str: + .asciz "boot" + + .text +export ___cstartup ! Crt0 startup +___cstartup: + mov ___argr+0,ax + mov ___argr+2,bx + mov ___argr+4,cx + mov ___argr+6,dx + mov ___argr+8,si + mov ___argr+10,di + +zap_bss: ! Clear the BSS + mov ax,ds + mov es,ax ! ES now data seg + mov di,#__edata + mov cx,#__end + sub cx,di + xor ax,ax + cld + rep + stosb + + push [_environ] + mov ax,#defarg ! Don`t define __mkargv, standalone programs don`t + push ax ! get any arguments. + mov ax,#1 + push ax + + mov si,#auto_start ! Pointer to first autostart function +auto_run: + mov bx,[si] + test bx,bx + jz no_entry + call bx ! Call the function +no_entry: + inc si ! SI at next + inc si + jmp auto_run ! And round for the next. + +call_exit: ! Last item called by above. + pop bx ! Be tidy. + push ax ! At the end the last called was main() push it`s + call _exit ! return val and call exit(); +bad_exit: + jmp bad_exit ! Exit returned !! + + loc 2 + .word _main ! Segment 2 is the trailing pointers, main and the + .word call_exit ! routine to call exit. +data_start: + + .text +export _exit +_exit: ! exit(rv) function + mov bx,sp + push [bx+2] ! Copy the `rv` for the exit fuctions. + mov bx,[___cleanup] ! Call exit, normally this is `__do_exit` + test bx,bx + je no_clean ! But it`s default is null + call bx +no_clean: + inc sp + inc sp + +export __exit +__exit: + xor ax,ax + mov es,ax + mov ax,cs + seg es + mov [$E6*4+2],ax + mov ax,#reti_ins + seg es + mov [$E6*4],ax + mov ax,#$FFFF + int $E6 ! Try to exit DOSEMU + ! If we get here we`re not in dosemu. + seg es + mov [$472],#$1234 ! Warm reboot. + jmpi $0000,$FFFF +reti_ins: + reti + +#endasm + +#endif + +/****************************************************************************/ + +#ifdef L_bios_write +write(fd,buf,len) +int fd,len; +char * buf; +{ + register int v, c; + if(fd == 1 || fd == 2) + { + for(v=len; v>0; v--) + { + c= *buf++; + if( c == '\n') bios_putc('\r'); + bios_putc(c); + } + return len; + } + errno = EBADF; + return -1; +} +#endif + +/****************************************************************************/ + +#ifdef L_bios_read +read(fd,buf,len) +int fd,len; +char * buf; +{ + if(fd == 0) return bios_rdline(buf, len); + errno = EBADF; + return -1; +} +#endif + +/****************************************************************************/ + +#ifdef L_bios_lseek +long +lseek(fd, offt, whence) +int fd, whence; +long offt; +{ + if( fd >= 0 && fd <= 2 ) errno = ESPIPE; + else errno = EBADF; + return -1L; +} +#endif + +/****************************************************************************/ + +#ifdef L_bios_open +open(name, flags, mode) +char * name; +int flags, mode; +{ + errno = ENOENT; + return -1; +} +#endif + +/****************************************************************************/ + +#ifdef L_bios_close +close(fd) +int fd; +{ + if( fd >= 0 && fd <= 2 ) errno = ENOSYS; + else errno = EBADF; + return -1; +} +#endif + +/****************************************************************************/ + +#ifdef L_bios_isatty +isatty(fd) +int fd; +{ + if( fd >= 0 && fd <= 2 ) return 1; + return 0; +} +#endif + +/****************************************************************************/ + +#endif +#endif +#endif diff --git a/libc/bios/bios_vid.c b/libc/bios/bios_vid.c new file mode 100644 index 0000000..0d891a0 --- /dev/null +++ b/libc/bios/bios_vid.c @@ -0,0 +1,465 @@ +/* Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* Various possible console types */ +#define VT52_CON /* IMO the best, no clear to EOS/EOL yet */ +#define XANSI_CON /* Largest but still not complete */ +#define XDUMB_CON /* Can't do much */ +#define XSPEC_CON /* Incomplete, best for slow links */ + +#if !__FIRST_ARG_IN_AX__ +#ifdef __AS386_16__ +#ifdef __STANDALONE__ + +#include <dos.h> +#include <errno.h> +int errno; + +#ifdef L_bios_putc +#define CTRL(x) ((x)&0x1F) +static int last_attr = 0x07; +static int con_mode; +static unsigned char con_height = 24, con_width = 79; + +static int con_colour = 0; +static unsigned char con_row, con_col; + +#ifdef VT52_CON +bios_putc(c) +int c; +{ +static int ctrl = 0; + int new_attr; + if( con_mode==0 ) asm_coninit(); + + switch( ctrl ) + { + case 1: + ctrl=0; + switch(c) + { + case 'A': if( con_row ) con_row--; asm_cpos(con_row, con_col); break; + case 'B': if( con_row != con_height ) con_row++; + asm_cpos(con_row, con_col); break; + case 'C': if( con_col != con_height ) con_col++; + asm_cpos(con_row, con_col); break; + case 'D': if( con_col ) con_col--; asm_cpos(con_row, con_col); break; + case 'E': last_attr = 0x07; asm_cls(); + case 'H': asm_cpos(0,0); break; + case 'J': asm_cls(); break; + case 'K': break; + case 'R': ctrl = 2; break; /* Foreground */ + case 'S': ctrl = 3; break; /* Background */ + case 'Y': ctrl = 4; break; /* ttypos */ + } + break; + case 2: ctrl=0; new_attr = (last_attr & 0xF0) + (c&0xF); + if(0) { + case 3: ctrl=0; new_attr = (last_attr & 0x0F) + (c<<4); + } + switch(c) + { + case '_': if( !con_colour ) last_attr = (last_attr&0x88) + 1; + break; + case '!': last_attr = (last_attr&0x88) + 0x70; break; + case ' ': last_attr = 0x07; break; + case '+': last_attr |= 0x08; break; + case '*': last_attr |= 0x80; break; + + default: if( con_colour ) + last_attr = new_attr; + } + break; + case 4: ctrl=5; con_col = c-' '; break; + case 5: ctrl=0; con_row = c-' '; asm_cpos(con_row, con_col); break; + break; + + default: + if( c & 0xE0 ) + { asm_colour(last_attr) ; asm_putc(c); } + else switch(c) + { + default: + asm_putc(c); + break; + case CTRL('L'): + asm_cpos(0,0); + asm_cls(); + break; + case CTRL('['): + ctrl = 1; + asm_gpos(); + break; + } + break; + } +} +#endif + +#ifdef ANSI_CON +#define MAX_ARGS 8 +static int colconv[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; +static int vidcnt = 0; +static int ansi_2 = 0; +static int ansi_argc = 0; +static int ansi_argv[MAX_ARGS]; + +bios_putc(c) +int c; +{ + if( con_mode==0 ) asm_coninit(); + + if( vidcnt == 0 || c < ' ' || c > '~' ) + { + switch(c & 0xFF) + { + default: + asm_colour(last_attr); + asm_putc(c); + break; + case CTRL('L'): + asm_cpos(0,0); + asm_cls(); + break; + case CTRL('['): + vidcnt=1; + break; + } + return; + } + + /* ... ansi/vt100 interpretation, this collects _all_ ansi control strings */ + switch(vidcnt) + { + case 1: for(ansi_argc=0; ansi_argc<MAX_ARGS; ansi_argc++) + ansi_argv[ansi_argc] = 0; + ansi_2 = 0; + ansi_argc = 0; + vidcnt++; + + if( c != '[' ) + { + do_ansi(c + 0x1B00, ansi_argc, ansi_argv); + vidcnt = 0; + } + break; + + case 2: if( c == ';' ) + { + if( ansi_argc < MAX_ARGS ) + ansi_argc++; + } + else if( c >= '0' && c <= '9' ) + ansi_argv[ansi_argc] = ansi_argv[ansi_argc] * 10 + c - '0'; + else if( c >= '@' ) + { + do_ansi(c+ansi_2, ++ansi_argc, ansi_argv); + vidcnt = 0; + } + else + ansi_2 = (c<<8); + break; + + default: vidcnt = 0; /* This definitly won't happen ... definitly ... */ + } +} + +do_ansi(ctrl, argc, argv) +int ctrl, argc, *argv; +{ + switch(ctrl) + { + case 'A': + case 'B': + case 'C': + case 'D': + asm_gpos(); + if( argv[0] < 1 ) argv[0] = 1; + switch(ctrl) + { + case 'A': if( argv[0]>con_row ) con_row=0; else con_row-=argv[0]; break; + case 'B': if( argv[0]+con_row>con_height ) + con_row = con_height; + else + con_row += argv[0]; + break; + case 'C': if( argv[0]+con_col>con_width ) + con_col = con_width; + else + con_col += argv[0]; + break; + case 'D': if( argv[0]>con_col ) con_col=0; else con_col-=argv[0]; break; + } + asm_cpos(con_row, con_col); + break; + + case 'H': + if( --argv[0] < 0 ) argv[0] = 0; + if( --argv[1] < 0 ) argv[1] = 0; + asm_cpos(argv[0],argv[1]); + break; + case 'J': if( argv[0] == 2 ) asm_cls(); + break; + case 'm': + { + int ar; + for(ar=0; ar<argc; ar++) switch(argv[ar]) + { + case 0: last_attr = 0x07; break; + case 1: last_attr |= 0x08; break; + case 5: last_attr |= 0x80; break; + case 7: last_attr = 0x70; break; + case 30: case 31: case 32: case 33: + case 34: case 35: case 36: case 37: + if( con_colour ) + last_attr = ((last_attr&0xF8)|(colconv[argv[ar]-30])); + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + if( con_colour ) + last_attr = ((last_attr&0x8F)|((colconv[argv[ar]-40])<<4)); + break; + default: break; + } + } + } +} +#endif + +#ifdef SPEC_CON +static char vidbuf[3]; +static int vidcnt=0; + +bios_putc(c) +int c; +{ + if( con_mode==0 ) asm_coninit(); + if( vidcnt == 0 ) + { + if( c & 0xE0 ) + { asm_colour(last_attr) ; asm_putc(c); } + else switch(c) + { + default: + asm_putc(c); + break; + case CTRL('L'): + asm_cpos(0,0); + asm_cls(); + break; + case CTRL('P'): + case CTRL(']'): + vidbuf[vidcnt++] = c; + break; + } + } + else + { + vidbuf[vidcnt++] = c; + if( vidcnt < 3 && + (vidbuf[0] != CTRL(']') || vidbuf[1] < '`' || vidbuf[1] > 'p')) + return; + + if( vidbuf[0] == CTRL('P') ) + { + if( vidbuf[1] >= 32 && vidbuf[1] <= 56 + && vidbuf[2] >= 32 && vidbuf[2] <= 111 ) + asm_cpos((vidbuf[1]-32), (vidbuf[2]-32)); + } + else + { + if( vidbuf[1] >= '`' ) + last_attr = ( (vidbuf[1]&0xF) | (last_attr&0xF0)); + else + last_attr = ( (vidbuf[2]&0xF) | ((vidbuf[1]&0xF)<<4)); + + if( !con_colour ) + last_attr = (last_attr&0x88) + ((last_attr&7)?0x07:0x70); + } + vidcnt=0; + } +} +#endif + +#ifdef DUMB_CON +bios_putc(c) +int c; +{ + if( con_mode==0 ) asm_coninit(); + if( c & 0xE0 ) asm_putc(c); + else switch(c) + { + default: + asm_putc(c); + break; + case CTRL('L'): + asm_cls(); + case CTRL('^'): + asm_cpos(0,0); + break; + } +} +#endif + +static asm_coninit() +{ +#asm + mov ax,#$0F00 + int $10 + mov _con_mode,ax +#endasm + if( (con_mode &0xFF) > 39 ) con_width = (con_mode>>8); + if( (con_mode&0xFF) != 0x7) + con_colour = 1; +} + +static asm_putc(c) +{ +#asm +#if !__FIRST_ARG_IN_AX__ + mov bx,sp + mov ax,[bx+2] +#endif + mov ah,#$0E + mov bx,#7 + int $10 +#endasm +} + +static asm_cls() +{ +#asm + push bp ! Bug in some old BIOS`s + !mov ax,#$0500 + !int $10 + mov ax,#$0600 + mov bh,_last_attr + mov cx,#$0000 + mov dl,_con_width + mov dh,_con_height + int $10 + pop bp +#endasm +} + +static asm_cpos(r,c) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,sp + mov dh,al + mov ax,[bx+2] + mov dl,al +#else + mov bx,sp + mov ax,[bx+2] + mov dh,al + mov ax,[bx+4] + mov dl,al +#endif + mov ah,#$02 + mov bx,#7 + int $10 +#endasm +} + +#ifndef DUMB_CON +static asm_colour(c) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,ax +#else + mov bx,sp + mov bx,[bx+2] +#endif + mov ah,#$08 + int $10 + mov ah,#$09 + mov cx,#1 + int $10 +#endasm +} + +static asm_gpos() +{ +#asm + mov ah,#$03 + mov bx,#7 + int $10 + mov [_con_row],dh + mov [_con_col],dl + mov ax,cx +#endasm +} +#endif +#endif + +/****************************************************************************/ + +#ifdef L_bios_rdline +bios_rdline(buf, len) +char * buf; +int len; +{ + int ch; + int pos=0; + + if( len == 1 ) + { + buf[0]=((ch=bios_getc())&0xFF?ch&0xFF:((ch>>8)&0xFF|0x80)); + return 1; + } + + for(ch=0;;) + { + if(ch != '\003') + { + ch = bios_getc(); + if( pos == 0 && (ch&0xFF) == 0 ) + { + buf[0] = ((ch>>8)|0x80); + return 1; + } + ch &= 0x7F; + } + if( ch == '\r' ) + { + bios_putc('\r'); bios_putc('\n'); + buf[pos++] = '\n'; + return pos; + } + if( ch >= ' ' && ch != 0x7F && pos < len-1) + bios_putc(buf[pos++] = ch); + else if( (ch == '\003' || ch == '\b') && pos > 0 ) + { + bios_putc('\b'); bios_putc(' '); bios_putc('\b'); + pos--; + } + else if( ch == '\003' ) + return 0; + else + bios_putc('\007'); + } +} +#endif + +/****************************************************************************/ + +#ifdef L_bios_getc +bios_getc() +{ +#asm + xor ax,ax + int $16 +#endasm +} +#endif + +/****************************************************************************/ + +#endif +#endif +#endif diff --git a/libc/crt0.c b/libc/crt0.c new file mode 100644 index 0000000..b21b525 --- /dev/null +++ b/libc/crt0.c @@ -0,0 +1,62 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#if defined(__AS386_16__) || defined(__AS386_32__) +#define CRT0_OK +/* + * Change of aim here, to allow easy alteration for generation of COM files + * this code has been moved into libc. This means only the linker needs to + * to be told to fetch a different libc the crt0 is unaltered. + * + * This also allows us to deal with __FIRST_ARG_IN_AX__ and __CALLER_SAVES__ + * in the same way. + */ + +#asm +.text +entry startup ! Crt0 startup +startup: + br ___cstartup +export no_op +no_op: ! Generic no operation call + ret + + .ascii __LIBC__ ! Version id. + + loc 1 ! Segment 1 is where the pointers to the autostart + ! functions are stored. +#if !__AS386_32__ +ZP_safety: + .word 0 ! But first some zeros to avoid null pointer writes. + .word 0 + .word 0 + .word 0 +#endif +export auto_start +auto_start: + +#endasm +#endif /* __AS386_16__ or __AS386_32__ */ + +#if defined(__GNUC__) && defined(__i386__) +#define CRT0_OK + +#ifdef __ELF__ +__asm__(".globl __startup\n__startup:"); +__asm__("jmp __cstartup"); +__asm__(".globl __no_op\n__no_op:"); +__asm__("ret"); +#else +__asm__(".globl startup\nstartup:"); +__asm__("jmp ___cstartup"); +__asm__(".globl no_op\nno_op:"); +__asm__("ret"); +#endif + +#endif /* defined(__GNUC__) && defined(__i386__) */ + +#ifndef CRT0_OK +#error You are not going to get far without crt0.o! +#endif diff --git a/libc/error/Config b/libc/error/Config new file mode 100644 index 0000000..1f384b7 --- /dev/null +++ b/libc/error/Config @@ -0,0 +1,2 @@ + +error: Unix error functions diff --git a/libc/error/Makefile b/libc/error/Makefile new file mode 100644 index 0000000..dc9b98e --- /dev/null +++ b/libc/error/Makefile @@ -0,0 +1,19 @@ +# 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 + +ifeq ($(LIB_OS),ELKS) +OBJ=error.o sys_errlist.o perror.o sys_siglist.o __assert.o +endif + +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..79a40bf --- /dev/null +++ b/libc/error/sys_errlist.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1996 Robert de Bath <robert@debath.thenet.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* This is a flash way of auto-initing the error array from an external file + * I wouldn't be surprised tho if it's a lot better just to hard code the + * error messages into the array. + * + * Of course the best of all is to use strerror(). + */ + +#ifdef __AS386_16__ +#define NR_ERRORS 128 + +extern char **__sys_errlist; +extern int __sys_nerr; + +char *sys_errlist[NR_ERRORS]; +int sys_nerr = NR_ERRORS; + +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word _init_vars ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm + +static void init_vars() +{ + char inbuf[256]; + char errbuf[80]; + int i, cc, fd, err, len, bufoff=0; + char * ptr; + + fd = open("/usr/lib/liberror.txt", 0); + if( fd < 0 ) return; + + for(i=0; i<NR_ERRORS; i++) sys_errlist[i] = "Unknown error"; + + while( (cc=read(fd, inbuf, sizeof(inbuf))) > 0 ) + { + for(i=0; i<cc; i++) + { + if( inbuf[i] == '\n' ) + { + errbuf[bufoff] = '\0'; + err = atoi(errbuf); + ptr = strchr(errbuf, ' '); + if( ptr && err > 0 && err < NR_ERRORS ) + { + while(*ptr == ' ') ptr++; + len = strlen(ptr)+1; + sys_errlist[err] = (void*)sbrk(len); + if( (int)sys_errlist[err] == -1 ) + { + sys_errlist[err] == ""; + break; + } + memcpy(sys_errlist[err], ptr, len); + } + bufoff = 0; + } + else if( bufoff < sizeof(errbuf)-1 ) + errbuf[bufoff++] = inbuf[i]; + } + } + close(fd); + + __sys_errlist = sys_errlist; + __sys_nerr = sys_nerr = NR_ERRORS; +} + +#endif /* __AS386_16__ */ diff --git a/libc/error/sys_siglist.c b/libc/error/sys_siglist.c new file mode 100644 index 0000000..8f502f6 --- /dev/null +++ b/libc/error/sys_siglist.c @@ -0,0 +1,38 @@ + +#include <signal.h> + +__const char * __const sys_siglist[NSIG] = +{ + "Unknown signal", + "Hangup", + "Interrupt", + "Quit", + "Illegal instruction", + "Trace/breakpoint trap", + "IOT trap/Abort", + "Bus error", + "Floating point exception", + "Killed", + "User defined signal 1", + "Segmentation fault", + "User defined signal 2", + "Broken pipe", + "Alarm clock", + "Terminated", + "Stack fault", + "Child exited", + "Continued", + "Stopped (signal)", + "Stopped", + "Stopped (tty input)", + "Stopped (tty output)", + "Possible I/O", + "CPU time limit exceeded", + "File size limit exceeded", + "Virtual time alarm", + "Profile signal", + "Window size changed", + "File lock lost", + "Power failure", + "Unused signal" +}; diff --git a/libc/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..f5d42a0 --- /dev/null +++ b/libc/grp/Makefile @@ -0,0 +1,42 @@ +# 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 ($(LIB_CPU),g386) +CFLAGS+=$(WALL) +else +CFLAGS=$(CCFLAGS) $(LIBDEFS) -ansi +endif + +GSRC=__getgrent.c grent.c getgrnam.c getgrgid.c fgetgrent.c initgroups.c \ + config-grp.h + +ifeq ($(LIB_OS),ELKS) +GOBJ=__getgrent.o grent.o getgrnam.o getgrgid.o fgetgrent.o initgroups.o +else +GOBJ= +endif + +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..62a966d --- /dev/null +++ b/libc/gtermcap/Makefile @@ -0,0 +1,23 @@ +# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> +# This file is part of the Linux-8086 C library and is distributed +# under the GNU Library General Public License. + +TOP=.. +include $(TOP)/Make.defs + +ifeq ($(LIB_OS),ELKS) +OBJ=termcap.o tparam.o +endif + +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/i386fp/Config b/libc/i386fp/Config new file mode 100644 index 0000000..dac69f0 --- /dev/null +++ b/libc/i386fp/Config @@ -0,0 +1 @@ +386fp: Bcc 386 floating point diff --git a/libc/i386fp/Makefile b/libc/i386fp/Makefile new file mode 100644 index 0000000..88158f7 --- /dev/null +++ b/libc/i386fp/Makefile @@ -0,0 +1,58 @@ +# Makefile for bcc 386 software floating point library + +TOP=.. +include $(TOP)/Make.defs + +.SUFFIXES: .x # .x files are .s files that need C-preprocessing +.x.o: + cp $< tmp.c + $(CC) $(CFLAGS) -P tmp.c | $(AS) - -n $* -o $@ + +# $(ASCPP) $(ASCPPFLAGS) $< >tmp +# $(AS) tmp -n $* -l tmp.lst -o $@ + +AS =as86 -3 +ASCPP =/lib/cpp +ASCPPFLAGS =-P -traditional + +FPDIST =Makefile $(FPSRC) test.c bccfp.tex +FPSRC =fadd.x fcomp.x fdiv.x fmul.x fbsr.x \ + fperr.c fperror.x fptoi.x fpushd.x fpulld.x \ + fpushi.x fpushf.x fpullf.x frexp.x ftst.x \ + gcclib.x \ + fabs.x ldexp.x modf.c \ + fperr.h fplib.h +FPOBJ =fadd.o fcomp.o fdiv.o fmul.o fpbsr.o \ + fperr.o fperror.o fptoi.o fpushd.o fpulld.o \ + fpushi.o fpushf.o fpullf.o frexp.o ftst.o \ + fabs.o ldexp.o modf.o +JUNK =tmp tmp.c tmp.lst +LIB =. + +test: test.c $(LIB)/libfp.a + $(CC) -o $@ test.c $(LIB)/libfp.a -lm + +$(FPOBJ): fplib.h +fperr.c fperror.x: fperr.h + +$(LIB)/libfp.a: $(FPOBJ) + ar rc $(LIB)/libfp.a $(FPOBJ) + rm -f $(JUNK) + +ifeq ($(LIB_CPU),i386) +libc.a: $(FPOBJ) + rm -f $(JUNK) + ar rc ../libc.a $(FPOBJ) +else +libc.a: +endif + +dist: $(FPDIST) + /bin/tar cvf - $(FPDIST) | /bin/compress -b 13 >bccfp.tar.Z + uue bccfp.tar.Z + +clean: + rm -f $(FPOBJ) $(JUNK) test + rm -f $(LIB)/libfp.a bccfp.tar.Z bccfp.uue + +realclean: clean diff --git a/libc/i386fp/bccfp.tex b/libc/i386fp/bccfp.tex new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libc/i386fp/bccfp.tex diff --git a/libc/i386fp/changes b/libc/i386fp/changes new file mode 100644 index 0000000..2cc632a --- /dev/null +++ b/libc/i386fp/changes @@ -0,0 +1,30 @@ +fcomp: +Fixes for negative 0 (perhaps this shouldn't be generated, like denormals +and infinities (these would cause even more trouble) but Fsub routine or +something generated one). + +frexp.x: +Deleted 3rd arg (used to return value when bcc wasn't doing it right). + +Fixed frexp(value = 0) and ldexp(value = 0) returning nonzero. + +Most files: +Changed comment symbol to '!' for new assembler (not the native ';' in +case this is ported to ACK someday). + +Avoided using ebp and unnecessary register saves. + +Changed assembler style to make it a bit more portable or like I do it +(no '$' for hex, 8[esp] instead of [esp+8], use only .define and not export +or .globl, use '#' (could use nothing) instead of '*' for immediate). +The partly-supported 8(ebp) and .globl would be still more portable. + +Changed terminology 'mantissa' to 'fraction'. + +Round to even. Required for 'paranioa' not to find any defects. + +Used preprocessor. + +Parametrized most of the magic numbers. Phew! + +Supported denormals. Now 'paranioa' doesn't find any flaws. diff --git a/libc/i386fp/fabs.x b/libc/i386fp/fabs.x new file mode 100644 index 0000000..fe81676 --- /dev/null +++ b/libc/i386fp/fabs.x @@ -0,0 +1,17 @@ +! bcc 386 floating point routines (version 2) -- _fabs +! author: Bruce Evans + +#include "fplib.h" + +! double fabs(double value); +! returns the absolute value of a number +! this works for all NaNs, like the 80*87 fabs, but perhaps we should check +! for exceptions that can happen when an 80*87 register is loaded + + .globl _fabs + .align ALIGNMENT +_fabs: + mov eax,PC_SIZE+D_LOW[esp] + mov edx,PC_SIZE+D_HIGH[esp] + and edx,~D_SIGN_MASK + ret diff --git a/libc/i386fp/fadd.x b/libc/i386fp/fadd.x new file mode 100644 index 0000000..d1e60b1 --- /dev/null +++ b/libc/i386fp/fadd.x @@ -0,0 +1,485 @@ +! bcc 386 floating point routines (version 2) +! -- Fadd, Faddd, Faddf, Fsub, Fsubd, Fsubf, normalize2 +! author: Bruce Evans + +#include "fplib.h" + +#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE) + + .extern Fpushf + .extern fpdenormal + .extern fpoverflow + .extern fpunderflow + + .globl Fadd + .align ALIGNMENT +Fadd: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp] + mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp] + call addition + mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret #D_SIZE + + .globl Faddd + .align ALIGNMENT +Faddd: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ecx,D_HIGH[ebx] + mov ebx,D_LOW[ebx] + call addition + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .globl Faddf + .align ALIGNMENT +Faddf: + push ebp + push edi + push esi + call Fpushf + pop ebx ! yl + pop ecx ! yu + mov eax,FRAME_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_HIGH[esp] ! xu + call addition + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .globl Fsub + .align ALIGNMENT +Fsub: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp] + mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp] + xor ecx,#D_SIGN_MASK ! complement sign + call addition + mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret #D_SIZE + + .globl Fsubd + .align ALIGNMENT +Fsubd: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ecx,D_HIGH[ebx] + mov ebx,D_LOW[ebx] + xor ecx,#D_SIGN_MASK ! complement sign + call addition + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .globl Fsubf + .align ALIGNMENT +Fsubf: + push ebp + push edi + push esi + call Fpushf + pop ebx ! yl + pop ecx ! yu + mov eax,FRAME_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_HIGH[esp] ! xu + xor ecx,#D_SIGN_MASK ! complement sign + call addition + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .align ALIGNMENT +exp_y_0: + +! Check for x denormal, to split off special case where both are denormal, +! so the norm bit (or 1 higher) is known to be set for addition, so addition +! can be done faster + + test esi,#D_EXP_MASK + jnz x_normal_exp_y_0 + test esi,esi ! test top bits of x fraction + jnz both_denorm ! denormal iff nonzero fraction with zero exp + test eax,eax ! test rest of fraction + jz return_edx_eax ! everything 0 (XXX - do signs matter?) +both_denorm: + call fpdenormal + test ebp,#D_SIGN_MASK + jnz denorm_subtract + +! Add denormal x to denormal or zero y + +#if D_NORM_BIT != D_EXP_SHIFT +#include "error, carry into norm bit does not go into exponent" +#endif + + add eax,ebx + adc esi,edi + or edx,esi + ret + +denorm_subtract: + sub eax,ebx + sbb esi,edi + or edx,esi + ret + + .align ALIGNMENT +x_normal_exp_y_0: + test edi,edi ! this is like the check for x denormal + jnz y_denorm + test ebx,ebx + jz return_edx_eax ! y = 0 +y_denorm: + call fpdenormal + or ecx,#1 << D_EXP_SHIFT ! normalize y by setting exponent to 1 + jmp got_y + + .align ALIGNMENT +return_edx_eax: + ret + + .align ALIGNMENT +add_bigshift: + cmp ecx,#D_FRAC_BIT+2 + jae return_edx_eax ! x dominates y + sub ecx,#REG_BIT + shrd ebp,ebx,cl + shrd ebx,edi,cl + shr edi,cl + add eax,edi + adc esi,#0 + xchg ebp,ebx + br normalize + + .align ALIGNMENT +addition: + mov esi,edx ! this mainly for consistent naming + and esi,#D_EXP_MASK | D_FRAC_MASK ! discard sign so comparison is simple + mov edi,ecx ! free cl for shifts + and edi,#D_EXP_MASK | D_FRAC_MASK + cmp esi,edi + ja xbigger + jb swap + cmp eax,ebx + jae xbigger +swap: + xchg edx,ecx + xchg eax,ebx + xchg esi,edi +xbigger: + +! edx holds sign of result from here on +! and exponent of result before the normalization step + + mov ebp,edx ! prepare difference of signs + xor ebp,ecx + + and ecx,#D_EXP_MASK ! extract exp_y and check for y 0 or denormal + beq exp_y_0 ! otherwise x is not 0 or denormal either + and edi,#D_FRAC_MASK ! extract fraction + or edi,#D_NORM_MASK ! normalize +got_y: + and esi,#D_FRAC_MASK ! extract fraction + or esi,#D_NORM_MASK ! normalize + + sub ecx,edx ! carries from non-exp bits in edx killed later + neg ecx + and ecx,#D_EXP_MASK + shr ecx,#D_EXP_SHIFT ! difference of exponents + +got_x_and_y: + and ebp,#D_SIGN_MASK ! see if signs are same + bne subtract ! else roundoff reg ebp has been cleared + + cmp cl,#REG_BIT + bhis add_bigshift + shrd ebp,ebx,cl + shrd ebx,edi,cl + shr edi,cl + add eax,ebx + adc esi,edi + +! result edx(D_SIGN_MASK | D_EXP_MASK bits):esi:eax:ebp but needs normalization + + mov edi,edx + and edi,#D_EXP_MASK + test esi,#D_NORM_MASK << 1 + jnz add_loverflow + +add_round: + cmp ebp,#1 << (REG_BIT-1) ! test roundoff register + jb add_done ! no rounding + jz tie +add_roundup: + add eax,#1 + adc esi,#0 + test esi,#D_NORM_MASK << 1 + jnz pre_add_loverflow ! rounding may cause overflow! +add_done: + mov ecx,edx ! duplicated code from 'done' + and edx,#D_SIGN_MASK + or edx,edi + and esi,#D_FRAC_MASK + or edx,esi + ret + + .align ALIGNMENT +tie: + test al,#1 ! tie case, round to even + jz add_done ! even, no rounding + jmp add_roundup + + .align ALIGNMENT +pre_add_loverflow: + sub ebp,ebp ! clear rounding register + ! probably avoiding tests for more rounding +add_loverflow: + shrd ebp,eax,#1 + jnc over_set_sticky_bit + or ebp,#1 +over_set_sticky_bit: + shrd eax,esi,#1 + shr esi,#1 + add edi,1 << D_EXP_SHIFT + cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT + jl add_round +overflow: + call fpoverflow + mov eax,ecx ! XXX - wrong reg + ret + +! result edx(D_SIGN_MASK | D_EXP_MASK bits): +! esi((D_NORM_MASK << 1) | D_NORM_MASK | D_FRAC_MASK bits):eax:ebp:ebx +! but needs normalization + + .align ALIGNMENT +normalize: + mov edi,edx + and edi,#D_EXP_MASK + test esi,#D_NORM_MASK << 1 + bne loverflow + +! result edx(D_SIGN_MASK bit):edi(D_EXP_MASK bits): +! esi(D_NORM_MASK | D_FRAC_MASK bits):eax:ebp:ebx +! but needs normalization + + .globl normalize2 +normalize2: + test esi,#D_NORM_MASK ! already-normalized is very common + jz normalize3 +round: + cmp ebp,#1 << (REG_BIT-1) ! test roundoff register + jb done ! no rounding + jz near_tie +roundup: + add eax,#1 + adc esi,#0 + test esi,#D_NORM_MASK << 1 + bne pre_loverflow ! rounding may cause overflow! +done: +cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT +jae overflow + and edx,#D_SIGN_MASK ! extract sign of largest and result + or edx,edi ! include exponent with sign + and esi,#D_FRAC_MASK ! discard norm bit + or edx,esi ! include fraction with sign and exponent + ret + + .align ALIGNMENT +near_tie: + test ebx,ebx + jnz roundup + test al,#1 ! tie case, round to even + jz done ! even, no rounding + jmp roundup + + .align ALIGNMENT +not_in_8_below: + shld ecx,esi,#REG_BIT-D_NORM_BIT+16 ! in 9 to 16 below? + jz not_in_16_below ! must be way below (17-20 for usual D_NORM_BIT) + mov cl,bsr_table[ecx] ! bsr(esi) - (D_NORM_BIT-16) + neg ecx ! (D_NORM_BIT-16) - bsr(esi) + add ecx,#16 + jmp got_shift + + .align ALIGNMENT +not_in_16_below: + mov cl,bsr_table[esi] ! bsr(esi) directly + neg ecx ! -bsr(esi) + add ecx,#D_NORM_BIT ! D_NORM_BIT - bsr(esi) + jmp got_shift + + .align ALIGNMENT +normalize3: + test esi,esi + jz shift32 + +! Find first nonzero bit in esi +! Don't use bsr, it is very slow (const + 3 * bit_found) +! We know that there is some nonzero bit, and the norm bit and above are clear + + sub ecx,ecx ! prepare unsigned extension of cl + shld ecx,esi,#REG_BIT-D_NORM_BIT+8 ! any bits in 8 below norm bit? + jz not_in_8_below + mov cl,bsr_table[ecx] ! bsr(esi) - (D_NORM_BIT-8) + neg ecx ! (D_NORM_BIT-8) - bsr(esi) + add ecx,#8 ! D_NORM_BIT - bsr(esi) +got_shift: + shld esi,eax,cl + shld eax,ebp,cl + shld ebp,ebx,cl + shl ebx,cl + shl ecx,D_EXP_SHIFT + sub edi,ecx + bhi round ! XXX - can rounding change the exponent to > 0? + ! not bgt since edi may be 0x80000000 + neg edi + shr edi,#D_EXP_SHIFT + inc edi + br fpunderflow + + .align ALIGNMENT +pre_loverflow: + sub ebp,ebp ! clear rounding registers + sub ebx,ebx ! probably avoiding tests for more rounding + +loverflow: + shr esi,#1 ! carry bit stayed in the reg + rcr eax,#1 + rcr ebp,#1 + rcr ebx,#1 + add edi,1 << D_EXP_SHIFT + cmp edi,#D_EXP_INFINITE << D_EXP_SHIFT + blt round + call fpoverflow + mov eax,ecx ! XXX - wrong reg + ret + + .align ALIGNMENT +shift32: + test eax,eax + jz shift64 + mov esi,eax + mov eax,ebp + mov ebp,ebx + sub ebx,ebx + sub edi,#REG_BIT << D_EXP_SHIFT +shiftxx: + test esi,#~(D_NORM_MASK | D_FRAC_MASK) + jz over_adjust ! else too big already + shrd ebx,ebp,#D_BIT-D_FRAC_BIT + shrd ebp,eax,#D_BIT-D_FRAC_BIT + shrd eax,esi,#D_BIT-D_FRAC_BIT + shr esi,#D_BIT-D_FRAC_BIT + add edi,#(D_BIT-D_FRAC_BIT) << D_EXP_SHIFT +over_adjust: + test edi,edi + bgt normalize2 + neg edi + shr edi,#D_EXP_SHIFT + inc edi + br fpunderflow + + .align ALIGNMENT +shift64: + test ebp,ebp + jz shift96 + mov esi,ebp + mov eax,ebx + sub ebp,ebp + mov ebx,ebp + sub edi,#(2*REG_BIT) << D_EXP_SHIFT + jmp shiftxx + + .align ALIGNMENT +shift96: + test ebx,ebx ! XXX - this test is probably unnecessary + ! since the shift must be small unless we + ! are subtracting 2 almost-equal numbers, + ! and then the bits beyond 64 will mostly + ! be 0 + jz return_esi_eax ! all zero + mov esi,ebx + sub ebx,ebx + sub edi,#(3*REG_BIT) << D_EXP_SHIFT + jmp shiftxx + + .align ALIGNMENT +return_esi_eax: + mov edx,esi + ret + + .align ALIGNMENT +subtract: + sub ebp,ebp ! set up roundoff register + cmp ecx,#REG_BIT + jae subtract_bigshift + shrd ebp,ebx,cl + shrd ebx,edi,cl + shr edi,cl + neg ebp ! begin subtraction esi:eax:0 - edi:ebx:ebp + sbb eax,ebx + sbb esi,edi + sub ebx,ebx + mov edi,edx + and edi,#D_EXP_MASK + br normalize2 + + .align ALIGNMENT +subtract_bigshift: + cmp ecx,#D_FRAC_BIT+2 + bhis return_edx_eax ! x dominates y + sub ecx,#REG_BIT + shrd ebp,ebx,cl + shrd ebx,edi,cl + shr edi,cl + not ebp ! begin subtraction esi:eax:0:0 - 0:edi:ebx:ebp + not ebx + add ebp,#1 + adc ebx,#0 + cmc + sbb eax,edi + sbb esi,#0 + xchg ebp,ebx + mov edi,edx + and edi,#D_EXP_MASK + br normalize2 + + .data + .extern bsr_table diff --git a/libc/i386fp/fcomp.x b/libc/i386fp/fcomp.x new file mode 100644 index 0000000..71148ab --- /dev/null +++ b/libc/i386fp/fcomp.x @@ -0,0 +1,89 @@ +! bcc 386 floating point routines (version 2) -- Fcomp, Fcompd, Fcompf +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern Fpushf + +! Pop 2 doubles from stack and compare them, return result in flags so +! normal signed branches work (unlike 80x87 which returns the result in +! the zero and carry flags). + + .globl Fcomp + .align ALIGNMENT +Fcomp: + pop ecx ! get return address + pop eax ! xl + pop edx ! xu + push ecx ! put back ret address - pop 2nd double later + +! All this popping is bad on 486's since plain mov takes 1+ cycle and pop +! takes 4 cycles. But this code is designed for 386's where popping is +! nominally the same speed and saves code space and so maybe instruction +! fetch time as well as the instruction to adjust the stack (ret #n takes +! no longer than plain ret but inhibits gotos). + + mov ebx,PC_SIZE+D_LOW[esp] ! yl + mov ecx,PC_SIZE+D_HIGH[esp] ! yu + jmp compare + +! Pop double from stack and compare with double at [ebx] + + .globl Fcompd + .align ALIGNMENT +Fcompd: + mov eax,PC_SIZE+D_LOW[esp] ! xl + mov edx,PC_SIZE+D_HIGH[esp] ! xu + mov ecx,D_HIGH[ebx] ! yu + mov ebx,D_LOW[ebx] ! yl + +compare: + test edx,#D_SIGN_MASK ! is x >= 0? + jz cmp0 ! yes; just compare x and y + test ecx,#D_SIGN_MASK ! no; but is y >= 0? + jz cmp0 ! yes; just compare x and y + + xchg edx,ecx ! x, y < 0, so ... + xchg eax,ebx ! ... swap x and y ... + xor edx,#D_SIGN_MASK ! ... and toggle signs + xor ecx,#D_SIGN_MASK + +cmp0: + cmp edx,ecx ! compare upper dwords + jnz checkneg0 ! if upper dwords differ, job is almost done + mov edx,eax ! upper dwords equal, so ... + mov ecx,ebx ! ... must make unsigned comparison of lower dwords + shr edx,#1 ! shift past sign + shr ecx,#1 + cmp edx,ecx ! compare top 31 bits of lower dwords + jnz return ! if these differ, job is done + and eax,#1 ! compare lowest bits + and ebx,#1 + cmp eax,ebx + +return: + ret #D_SIZE ! return, popping 1 double from stack + +checkneg0: + test edx,#D_EXP_MASK | D_FRAC_MASK ! check to catch unusual case ... + jnz recheck + test eax,eax + jnz recheck + test ecx,#D_EXP_MASK | D_FRAC_MASK + jnz recheck + test ebx,ebx + jz return ! ... both are (+-) zero, return 'z' + +recheck: + cmp edx,ecx ! the upper words were really different + ret #D_SIZE + + .globl Fcompf + .align ALIGNMENT +Fcompf: + call Fpushf + pop ebx ! yl + pop ecx ! yu + mov eax,PC_SIZE+D_LOW[esp] ! xl + mov edx,PC_SIZE+D_HIGH[esp] ! xu + jmp compare diff --git a/libc/i386fp/fdiv.x b/libc/i386fp/fdiv.x new file mode 100644 index 0000000..4a5cf74 --- /dev/null +++ b/libc/i386fp/fdiv.x @@ -0,0 +1,312 @@ +#define EF_SIZE 4 + +! bcc 386 floating point routines (version 2) -- Fdiv, Fdivd, Fdivf +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + +#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE) + + .extern Fpushf + .extern fpdivzero + .extern fpoverflow + .extern fpunderflow + +! double Fdiv(double x, double y) returns x / y + +! pop 2 doubles from stack, divide first by second, and push quotient on stack + +! we denote upper and lower dwords of x and y (or their fractions) +! by (xu,xl), (yu,yl) + + .globl Fdivf + .align ALIGNMENT +Fdivf: + sub esp,#D_SIZE ! make space for dummy double on stack + push ebp + push edi ! save some regs + push esi + mov eax,FRAME_SIZE-PC_SIZE+D_SIZE[esp] ! move return address ... + mov FRAME_SIZE-PC_SIZE[esp],eax ! ... to usual spot + call Fpushf + pop esi ! yl + pop edi ! yu + mov eax,FRAME_SIZE+D_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_SIZE+D_HIGH[esp] ! xu + jmp division + + .globl Fdiv + .align ALIGNMENT +Fdiv: + push ebp + push edi ! save some regs + push esi + mov eax,FRAME_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_HIGH[esp] ! xu + mov esi,FRAME_SIZE+D_SIZE+D_LOW[esp] ! yl + mov edi,FRAME_SIZE+D_SIZE+D_HIGH[esp] ! yu + jmp division + + .align ALIGNMENT +exp_y_0: + mov ebx,edi + or ebx,esi + beq zerodivide + mov ebx,#1 +fix_y: + test edi,edi ! XXX - sloow + js y_unpacked + shld edi,esi,#1 + shl esi,#1 + dec bx + jmp fix_y + + .align ALIGNMENT +exp_x_0: + mov ecx,edx + or ecx,eax + beq retz + mov ecx,#1 ! change exponent from 0 to 1 +fix_x: + test edx,#1 << (REG_BIT-1-2) ! XXX - sloow + jnz x_unpacked + shld edx,eax,#1 + shl eax,#1 + dec cx + jmp fix_x + +! Fdivd pops double from stack, divides it by double at [ebx], +! and pushes quotient back on stack + + .globl Fdivd + .align ALIGNMENT +Fdivd: + sub esp,#D_SIZE ! make space for dummy double on stack + push ebp + push edi ! save some regs + push esi + mov eax,FRAME_SIZE-PC_SIZE+D_SIZE[esp] ! move return address ... + mov FRAME_SIZE-PC_SIZE[esp],eax ! ... to usual spot + mov eax,FRAME_SIZE+D_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_SIZE+D_HIGH[esp] ! xu + mov esi,D_LOW[ebx] ! yl + mov edi,D_HIGH[ebx] ! yu + +division: + +! The full calculations are + +! (xu,xl,0) = yu * (zu,zl) + (0,r,0) (normal 96/32 -> 64 bit division) +! yl * zu = yu * q1 + r1 (32*32 -> 64 bit mul and 64/32 -> 32 bit div) + +! so + +! (xu,xl,0,0) = (yu,yl) * (zu,zl-q1) + (0,0,r-r1,yl*(q1-zl)) + +! where the calculations zl-q1, r-r1 and yl*(q1-zl) are more complicated +! than the notation suggests. They may be negative and the one with the +! multiplication may not fit in 32 bits and in both cases the overflow +! has to be moved into higher bit positions. + +! See Knuth for why (zu,zl-q1) is the correct 64-bit quotient to within +! 1 bit either way (assuming the normalization x < 2 * y). + +! We only need to calculate the remainder (0,0,r-r1,yl*(q1-zl)) to resolve +! tie cases. It tells whether the approximate quotient is too high or too +! low. + +#define NTEMPS 5 + + sub esp,#NTEMPS*GENREG_SIZE ! space to remember values for rounding of tie case + +! Offsets from esp for these values (offsets using FRAME_SIZE are invalid +! while these temps are active) +r = 0 +q1 = 4 +r1 = 8 +yl = 12 +zl = 16 + +! Step 1: unpack and normalize x to fraction in edx:eax (left shifted as +! far as possible less 2 so that x < y, and later z < y); unpack and normalize +! y to a fraction in edi:esi (left shifted as far as possible), put difference +! of signs (= sign of quotient) in ecx(D_SIGN_MASK) and difference of exponents +! (= exponent of quotient before normalization) in cx. + + mov ebp,edx ! xu + xor ebp,edi ! xu ^ yu + and ebp,#D_SIGN_MASK ! sign of result is difference of signs + +! Unpack y first to trap 0 / 0 + + mov ebx,edi ! remember yu for exponent of y + shld edi,esi,#D_BIT-D_FRAC_BIT ! extract fraction of y ... + shl esi,#D_BIT-D_FRAC_BIT + and ebx,#D_EXP_MASK ! exponent of y + jz exp_y_0 + shr ebx,#D_EXP_SHIFT ! in ebx (actually in bx, with high bits 0) + or edi,#D_NORM_MASK << (D_BIT-D_FRAC_BIT) ! normalize +y_unpacked: + +! Unpack x + + mov ecx,edx ! remember xu for exponent of x + shld edx,eax,#D_BIT-D_FRAC_BIT-2 ! extract fraction of x ... + shl eax,#D_BIT-D_FRAC_BIT-2 + and edx,#(D_NORM_MASK << (D_BIT-D_FRAC_BIT-2+1))-1 + ! XXX - above may be shifted 1 extra unnecessarily + and ecx,#D_EXP_MASK ! exponent of x + jz exp_x_0 + shr ecx,#D_EXP_SHIFT ! in ecx (actually in cx, with high bits 0) + or edx,#D_NORM_MASK << (D_BIT-D_FRAC_BIT-2) ! normalize +x_unpacked: + + sub cx,bx ! not ecx,ebx because we want to use high bit for sign + add cx,#D_EXP_BIAS ! adjust exponent of quotient + + or ecx,ebp ! include sign with exponent + +! Step 2: quotient of fractions -> (edx,eax) + +! 2a: (xu,xl,0) div yu = (zu,zl) -> (ebx,esi) + + div eax,edi ! (xu,xl) div yu = zu in eax; remainder (rem) in edx + mov ebx,eax ! save zu in ebx + sub eax,eax ! clear eax: (edx,eax) = (rem,0) + div eax,edi ! (rem,0) div yu = zl in eax + mov r[esp],edx + mov zl[esp],eax + xchg eax,esi ! store zl in esi; save yl in eax + mov yl[esp],eax + +! 2b: (yl * zu) div yu -> (0,eax) + + mul eax,ebx ! yl * zu -> (edx,eax) + div eax,edi ! (yl * zu) div yu in eax + mov q1[esp],eax + mov r1[esp],edx + +! 2c: (xu,xl) / (yu,yl) = (zu,zl) - (yl * zu) div yu -> (edx,eax) + + mov edx,ebx ! zu + xchg eax,esi ! eax <- zl; esi <- (yl * zu) div yu + sub eax,esi + sbb edx,#0 + +! Step 3: normalise quotient + + test edx,#1 << (REG_BIT-2) ! is fraction too small? (can only be by 1 bit) + jnz div4 + shld edx,eax,#1 ! yes; multiply fraction ... + shl eax,#1 ! ... by 2 ... + dec cx ! ... and decrement exponent + +! Step 4: shift and round + +div4: + mov ebx,eax ! save for rounding + shrd eax,edx,#D_BIT-D_FRAC_BIT-1 ! shift fraction of result ... + shr edx,#D_BIT-D_FRAC_BIT-1 ! ... to proper position + and ebx,#(1 << (D_BIT-D_FRAC_BIT-1))-1 ! look at bits shifted out + cmp ebx,#D_NORM_MASK >> (D_BIT-D_FRAC_BIT) ! compare with middle value + jb div5 ! below middle, don't round up + ja roundup ! above middle, round up + +! The low bits don't contain enough information to resolve the tie case, +! because the quotient itself is only an approximation. +! Calculate the exact remainder. +! This case is not very common, so don't worry much about speed. +! Unfortunately we had to save extra in all cases to prepare for it. + + push edx + push eax + + sub esi,esi ! the calculation requires 33 bits - carry to here + mov eax,2*GENREG_SIZE+q1[esp] + sub eax,2*GENREG_SIZE+zl[esp] + pushfd + mul dword EF_SIZE+2*GENREG_SIZE+yl[esp] + popfd + jnc foo + sub edx,2*GENREG_SIZE+yl[esp] + sbb esi,#0 +foo: + add edx,2*GENREG_SIZE+r[esp] + adc esi,#0 + sub edx,2*GENREG_SIZE+r1[esp] + sbb esi,#0 + mov ebx,eax + mov edi,edx + + pop eax + pop edx + +! Can finally decide rounding of tie case + + js div5 ! remainder < 0 from looking at top 64 bits + jnz roundup ! remainder > 0 from looking at top 64 bits + or edi,ebx ! test bottom 64 bits + jnz roundup ! remainder > 0 + + test al,#1 ! at last we know it is the tie case, check parity bit + jz div5 ! already even, otherwise round up to make even + +roundup: + add eax,#1 ! add rounding bit + adc edx,#0 + test edx,#D_NORM_MASK << 1 ! has fraction overflowed (very unlikely) + jz div5 +! Why were the shifts commented out? + shrd eax,edx,#1 ! yes, divide fraction ... + shr edx,#1 ! ... by 2 ... + inc cx ! ... and increment exponent + +! Step 5: put it all together + +div5: + mov ebx,ecx ! extract sign + and ebx,D_SIGN_MASK + cmp cx,#D_EXP_INFINITE ! is exponent too big? + jge overflow + test cx,cx + jle underflow + shl ecx,#D_EXP_SHIFT + + and edx,#D_FRAC_MASK ! remove norm bit + or edx,ecx ! include exponent ... + or edx,ebx ! ... and sign + +return: + add esp,#NTEMPS*GENREG_SIZE ! reclaim temp space + mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax ! "push" lower dword of product ... + mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx ! ... and upper dword + pop esi ! restore registers + pop edi + pop ebp + ret #D_SIZE + +retz: + sub edx,edx ! clear upper dword + sub eax,eax ! ... and lower dword + jmp return + +overflow: + mov edx,ecx ! put sign in usual reg + call fpoverflow + mov eax,ecx ! XXX - wrong reg + jmp return + +underflow: + mov esi,edx ! put upper part of fraction in usual reg + mov edx,ecx ! sign + movsx edi,cx ! put shift in usual reg + neg edi + inc edi + call fpunderflow + jmp return + +zerodivide: + mov edx,ebp ! sign + call fpdivzero + mov eax,ecx ! XXX - wrong reg + jmp return diff --git a/libc/i386fp/fmul.x b/libc/i386fp/fmul.x new file mode 100644 index 0000000..aa62b5c --- /dev/null +++ b/libc/i386fp/fmul.x @@ -0,0 +1,150 @@ +! bcc 386 floating point routines (version 2) -- Fmul, Fmuld, Fmulf +! author: Bruce Evans + +#include "fplib.h" + +#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE) + + .extern Fpushf + .extern fpoverflow + .extern fpunderflow + .extern normalize2 + + .globl Fmul + .align ALIGNMENT +Fmul: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp] + mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp] + call multiplication + mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret #D_SIZE + + .globl Fmuld + .align ALIGNMENT +Fmuld: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ecx,D_HIGH[ebx] + mov ebx,D_LOW[ebx] + call multiplication + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .globl Fmulf + .align ALIGNMENT +Fmulf: + push ebp + push edi + push esi + call Fpushf + pop ebx ! yl + pop ecx ! xu + mov eax,FRAME_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_HIGH[esp] ! xu + call multiplication + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .align ALIGNMENT +exp_x_0: + mov edx,#1 << D_EXP_SHIFT ! change exponent from 0 to 1 + jmp x_unpacked ! XXX - check for denormal? + + .align ALIGNMENT +exp_y_0: + mov ecx,#1 << D_EXP_SHIFT + jmp y_unpacked + + .align ALIGNMENT +multiplication: + mov ebp,edx ! xu + xor ebp,ecx ! xu ^ yu + and ebp,#D_SIGN_MASK ! sign of result is difference of signs + + mov esi,edx ! free edx for multiplications + and esi,#D_FRAC_MASK ! discard sign and exponent + and edx,#D_EXP_MASK ! exponent(x) + jz exp_x_0 + or esi,#D_NORM_MASK ! normalize +x_unpacked: + + mov edi,ecx ! this mainly for consistent naming + and edi,#D_FRAC_MASK + and ecx,#D_EXP_MASK ! exponent(y) + jz exp_y_0 + or edi,#D_NORM_MASK +y_unpacked: + + add ecx,edx ! add exponents + +! exponent is in ecx, sign in ebp, operands in esi:eax and edi:ebx, edx is free +! product to go in esi:eax:ebp:ebx +! terminology: x * y = (xu,xl) * (yu,yl) +! = (xu * yu,0,0) + (0,xu * yl + xl * yu,0) + (0,0,xl * yl) + + push ecx + push ebp + mov ecx,eax + mul ebx ! xl * yl + mov ebp,edx ! (xl * yl).u in ebp + xchg ebx,eax ! (xl * yl).l in ebx (final), yl in eax + mul esi ! xu * yl + push eax ! (xu * yl).l on stack + push edx ! (xu * yl).u on stack + mov eax,esi ! xu + mul edi ! xu * yu + mov esi,edx ! (xu * yu).u in esi (final except carries) + xchg ecx,eax ! (xu * yu).l in ecx, xl in eax + mul edi ! xl * yu + + add ebp,eax ! (xl * yl).u + (xl * yu).l + pop eax ! (xu * yl).u + adc eax,edx ! (xu * yl).u + (xl * yu).u + adc esi,#0 + pop edx ! (xu * yl).l + add ebp,edx ! ((xl * yl).u + (xl * yu).l) + (xu * yl).l + adc eax,ecx ! ((xu * yl).u + (xl * yu).u) + (xu * yu).l + adc esi,#0 + pop edx ! sign + pop edi ! exponent + sub edi,#(D_EXP_BIAS+1-(D_EXP_BIT+2)) << D_EXP_SHIFT ! adjust +! cmp edi,#(D_EXP_INFINITE-1+(D_EXP_BIT+2)) << D_EXP_SHIFT +! jae outofbounds ! 0 will be caught as underflow by normalize2 +cmp edi,#(2*D_EXP_INFINITE-(D_EXP_BIAS+1)+(D_EXP_BIT+2)) << D_EXP_SHIFT +ja underflow + br normalize2 + + .align ALIGNMENT +overflow: + mov edx,ebp ! put sign in usual reg + call fpoverflow + mov eax,ecx ! XXX - wrong reg + ret + + .align ALIGNMENT +underflow: + mov edx,ebp ! put sign in usual reg + neg edi + shr edi,#D_EXP_SHIFT + inc edi + br fpunderflow diff --git a/libc/i386fp/fpbsr.x b/libc/i386fp/fpbsr.x new file mode 100644 index 0000000..8ff38d7 --- /dev/null +++ b/libc/i386fp/fpbsr.x @@ -0,0 +1,25 @@ +! bcc 386 floating point routines (version 2) -- bsr_table +! author: Bruce Evans + +#include "fplib.h" + + .globl bsr_table + .data + .align ALIGNMENT +bsr_table: ! table to replace bsr on range 0-255 +.byte -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 +.byte 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 +.byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 +.byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 +.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 +.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 +.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 +.byte 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +.byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 diff --git a/libc/i386fp/fperr.c b/libc/i386fp/fperr.c new file mode 100644 index 0000000..fa1633e --- /dev/null +++ b/libc/i386fp/fperr.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <signal.h> + +#include "fperr.h" + +void fperr(errno) +int errno; +{ + +#if defined(DEBUG) || 0 + switch(errno) { + + case EFDENORMAL: + fputs("\nDenormal - ", stderr); + break; + + case EFINFINITY: + fputs("\nInfinity - ", stderr); + break; + + case EFNAN: + fputs("\nNaN - ", stderr); + break; + + case EFOVERFLOW: + fputs("\nOverflow - ", stderr); + break; + + case EFUNDERFLOW: + fputs("\nUnderflow - ", stderr); + break; + + case EFDIVZERO: + fputs("\nZero divide - ", stderr); + break; + + default: + fprintf(stderr, "\nUnknown error 0x%x - ", errno); + } + fflush(stderr); +#endif + + kill(getpid(), SIGFPE); +} diff --git a/libc/i386fp/fperr.h b/libc/i386fp/fperr.h new file mode 100644 index 0000000..f2a2a7d --- /dev/null +++ b/libc/i386fp/fperr.h @@ -0,0 +1,8 @@ +/* fperr.h */ + +#define EFDENORMAL 1 +#define EFINFINITY 2 +#define EFNAN 3 +#define EFOVERFLOW 4 +#define EFUNDERFLOW 5 +#define EFDIVZERO 6 diff --git a/libc/i386fp/fperror.x b/libc/i386fp/fperror.x new file mode 100644 index 0000000..04f3f74 --- /dev/null +++ b/libc/i386fp/fperror.x @@ -0,0 +1,126 @@ +! bcc 386 floating point routines (version 2) +! --- fpdenormal, fperror, fpinfinity, fpNaN, fpoverflow, fpunderflow,fpdivzero +! author: Bruce Evans + +#include "fperr.h" +#include "fplib.h" + + .extern _fperr + +! Cause a denormal-operand exception +! Preserves all general registers if signal handler returns + + .globl fpdenormal + .align ALIGNMENT +fpdenormal: +#if 0 + push eax + mov eax,#EFDENORMAL + call fperror + pop eax +#endif + ret + +! Cause an exception with error code eax, preserving all genregs except eax + + .globl fperror + .align ALIGNMENT +fperror: + push ebp ! set up usual frame ... + mov ebp,esp ! ... for debugging + push edx ! save default + push ecx + push eax ! error code is arg to C routine + call _fperr + add esp,#GENREG_SIZE + pop ecx ! restore default + pop edx + pop ebp + ret + + .align ALIGNMENT +fphuge: + mov ecx,#D_HUGE_LOW ! prepare number +-HUGEVAL + or edx,#D_HUGE_HIGH ! ... in case signal handler returns + jmp fperror + +! Cause an infinite-operand exception +! Return +-HUGEVAL in edx:ecx with sign from edx + + .globl fpinfinity + .align ALIGNMENT +fpinfinity: + mov eax,#EFINFINITY + jmp fphuge ! almost right + +! Cause an NaN-operand exception +! Return +-HUGEVAL in edx:ecx with sign from edx + + .globl fpNaN + .align ALIGNMENT +fpNaN: + mov eax,#EFNAN ! there are different types of NaNs but... + jmp fphuge ! WRONG + +! Cause an overflow exception +! Return +-HUGEVAL in edx:ecx with sign from edx + + .globl fpoverflow + .align ALIGNMENT +fpoverflow: + mov eax,#EFOVERFLOW + jmp fphuge ! almost right + +! Cause an underflow exception (actually assume it is masked for now) +! Return denormal or 0.0 in edx:ecx +! XXX - this should cause a denormal exception or none for the denormal case +! Args: sign in edx, fraction in esi:eax, right shift in edi +! Returns: denormalized number in edx:eax + + .globl fpunderflow + .align ALIGNMENT +fpunderflow: +#if 0 + mov eax,#EFUNDERFLOW + jmp fperror +#endif + cmp edi,#REG_BIT + jb denormalize1 + mov eax,esi + sub esi,esi + sub edi,#REG_BIT + cmp edi,#REG_BIT + jb denormalize1 +denormalize_underflow: +#if 0 + mov eax,#EFUNDERFLOW + jmp fperror +#endif + sub eax,eax + mov edx,eax + ret + + .align ALIGNMENT +denormalize1: + mov ecx,edi + shrd eax,esi,cl + shr esi,cl + mov ecx,esi + or ecx,eax + jz denormalize_underflow + and edx,#D_SIGN_MASK + or edx,esi + ret + +! Cause an fp division by zero exception +! Return +-HUGEVAL in edx:ecx with sign from edx + + .globl fpdivzero + .align ALIGNMENT +fpdivzero: + mov eax,#EFDIVZERO + test edx,#D_EXP_MASK + jnz fphuge ! almost right + sub ecx,ecx + mov edx,ecx + jmp fperror diff --git a/libc/i386fp/fplib.h b/libc/i386fp/fplib.h new file mode 100644 index 0000000..f110717 --- /dev/null +++ b/libc/i386fp/fplib.h @@ -0,0 +1,43 @@ +#define ALIGNMENT 4 +#define CHAR_BIT 8 +#define D_BIT (D_SIZE * CHAR_BIT) +#define D_EXP_BIAS ((1 << (D_EXP_BIT - 1)) - 1) +#define D_EXP_BIT 11 +#define D_EXP_INFINITE ((1 << D_EXP_BIT) - 1) +#define D_EXP_MASK (((1 << D_EXP_BIT) - 1) << D_EXP_SHIFT) +#define D_EXP_SHIFT (REG_BIT - (1 + D_EXP_BIT)) +#define D_FRAC_BIT 53 +#define D_FRAC_MASK (D_NORM_MASK - 1) +#define D_HIGH 4 +#define D_HUGE_HIGH (D_EXP_MASK - 1) +#define D_HUGE_LOW 0xFFFFFFFF +#define D_LOW 0 +#define D_NORM_BIT (D_FRAC_BIT - 1 - REG_BIT) +#define D_NORM_MASK (1 << D_NORM_BIT) +#define D_SIGN_BIT 63 +#define D_SIGN_MASK (1 << (D_SIGN_BIT - REG_BIT)) +#define D_SIZE 8 +#define F_BIT (F_SIZE * CHAR_BIT) +#define F_EXP_BIAS ((1 << (F_EXP_BIT - 1)) - 1) +#define F_EXP_BIT 8 +#define F_EXP_INFINITE ((1 << F_EXP_BIT) - 1) +#define F_EXP_MASK (((1 << F_EXP_BIT) - 1) << F_EXP_SHIFT) +#define F_EXP_SHIFT (REG_BIT - (1 + F_EXP_BIT)) +#define F_FRAC_BIT 24 +#define F_FRAC_MASK (F_NORM_MASK - 1) +#define F_HIGH 0 +#define F_HUGE_HIGH (F_EXP_MASK - 1) +#define F_NORM_BIT (F_FRAC_BIT - 1) +#define F_NORM_MASK (1 << F_NORM_BIT) +#define F_SIGN_BIT 31 +#define F_SIGN_MASK (1 << F_SIGN_BIT) +#define F_SIZE 4 +#define FREE_D_SIGN_BIT_TEST (D_SIGN_BIT % REG_BIT == REG_BIT - 1) +#define GENREG_SIZE 4 +#define INT_BIT 32 +#define INT_MAX 0x7FFFFFFF +#define INT_MIN (-0x7FFFFFFF - 1) +#define PC_SIZE 4 +#define REG_BIT 32 +#define SHORT_BIT 16 +#define UINT_MAX 0xFFFFFFFF diff --git a/libc/i386fp/fptoi.x b/libc/i386fp/fptoi.x new file mode 100644 index 0000000..30de729 --- /dev/null +++ b/libc/i386fp/fptoi.x @@ -0,0 +1,117 @@ +! bcc 386 floating point routines (version 2) +! -- dtoi, dtol, dtoui, dtoul, ftoi, ftol (todo: ftoui, ftoul) +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern fpoverflow + .extern Fpushf + +! Convert double x at [ebx] to int and return in eax + + .globl dtoi + .globl dtol + .align ALIGNMENT +dtoi: +dtol: + mov eax,D_HIGH[ebx] + mov ecx,eax + and ecx,#D_EXP_MASK ! extract exponent + jz retz ! if 0 return 0 + test eax,#D_SIGN_MASK + jnz negative + call into_dtoui + cmp eax,#INT_MAX + ja overflow_int_max + ret + + .align ALIGNMENT +negative: + and eax,#~D_SIGN_MASK + call into_dtoui + cmp eax,#INT_MIN + ja overflow_int_min + neg eax + ret + + .align ALIGNMENT +overflow_int_max: + call fpoverflow + mov eax,#INT_MAX + ret + + .align ALIGNMENT +overflow_int_min: + js return ! actually INT_MIN is OK + call fpoverflow + mov eax,#INT_MIN +return: + ret + + .align ALIGNMENT +retz: + sub eax,eax ! clear return value + ret + +! Convert double x at [ebx] to unsigned and return in eax + + .globl dtoui + .globl dtoul + .align ALIGNMENT +dtoui: +dtoul: + mov eax,D_HIGH[ebx] + mov ecx,eax + and ecx,#D_EXP_MASK ! extract exponent + jz retz ! if 0 return 0 + test eax,#D_SIGN_MASK + jnz overflow_0 +into_dtoui: + mov edx,D_LOW[ebx] + + and eax,#D_FRAC_MASK ! extract fraction + or eax,#D_NORM_MASK ! restore normalization bit + + shr ecx,#D_EXP_SHIFT ! convert exponent to number + sub ecx,#D_EXP_BIAS+D_NORM_BIT ! adjust radix point + jl dtoui_rightshift ! should we shift left or right? + cmp ecx,#D_BIT-D_FRAC_BIT ! can shift left by at most this + ja overflow_uint_max ! if more, overflow + shld eax,edx,cl + ret + + .align ALIGNMENT +dtoui_rightshift: + neg ecx ! make shift count > 0 + cmp ecx,#REG_BIT ! big shifts would be taken mod REG_BIT ... + jae retz ! ... no good + shr eax,cl ! otherwise it is faster to do the shift ... + ret ! ... then to jump for the slightly smaller + ! ... shift counts that shift out all bits + + .align ALIGNMENT +overflow_0: + call fpoverflow + sub eax,eax + ret + + .align ALIGNMENT +overflow_uint_max: + call fpoverflow + mov eax,#UINT_MAX + ret + +! ftoi is like dtoi except ebx points to a float instead of a double. +! This is a quickly-written slowish version that does not take advantage +! of the float being smaller. + + .globl ftoi + .globl ftol + .align ALIGNMENT +ftoi: +ftol: + call Fpushf + mov ebx,esp + call dtoi + add esp,#D_SIZE + ret diff --git a/libc/i386fp/fpulld.x b/libc/i386fp/fpulld.x new file mode 100644 index 0000000..928a846 --- /dev/null +++ b/libc/i386fp/fpulld.x @@ -0,0 +1,20 @@ +! bcc 386 floating point routines (version 2) -- Fpulld +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + +! Pop double from stack and store at address [ebx] + + .globl Fpulld + .align ALIGNMENT +Fpulld: + pop ecx + pop dword D_LOW[ebx] + pop dword D_HIGH[ebx] + jmp ecx ! return + +! This popping method is much slower on 486's because popping to memory +! takes 5+ while moving twice takes 2 and the return address doesn't +! have to be moved. However, popping is a little faster on a non-cached +! 386/20 with static column RAM although the memory access pattern is +! better for a double-width move than for popping. What about a cached 386? diff --git a/libc/i386fp/fpullf.x b/libc/i386fp/fpullf.x new file mode 100644 index 0000000..417ef92 --- /dev/null +++ b/libc/i386fp/fpullf.x @@ -0,0 +1,101 @@ +! bcc 386 floating point routines (version 2) -- Fpullf +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern fpoverflow + .extern fpunderflow + +! pop double from stack, convert to float and store at address [ebx] + + .globl Fpullf + .align ALIGNMENT +Fpullf: + +! Step 1: load and shift left + + mov eax,PC_SIZE+D_LOW[esp] ! lower dword + mov edx,PC_SIZE+D_HIGH[esp] ! upper dword + mov ecx,edx ! copy upper dword into ecx ... + and ecx,#D_SIGN_MASK ! ... and extract sign + and edx,#D_EXP_MASK | D_FRAC_MASK ! extract exponent and fraction + sub edx,#(D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT ! adjust exponent bias + jz underflow + cmp edx,#F_EXP_INFINITE << D_EXP_SHIFT ! check if exponent lies in reduced range + jae outofbounds + shld edx,eax,#D_EXP_BIT-F_EXP_BIT ! shift exponent and fraction + +! Step 2: round + + test eax,#1 << (REG_BIT-1-(D_EXP_BIT-F_EXP_BIT)) ! test upper rounding bit + jz step3 ! below middle, don't round up + test eax,#(1 << (REG_BIT-1-(D_EXP_BIT-F_EXP_BIT)))-1 ! test other rounding bits + jnz roundup ! above middle, round up + test dl,#1 ! in middle, check parity bit + jz step3 ! already even, otherwise round up to make even + +roundup: + inc edx ! carry 1 + test edx,#F_FRAC_MASK ! is fraction now 0? (carry into F_EXPMASK) + jnz step3 ! no -- carry complete + cmp edx,#(F_EXP_INFINITE << F_EXP_SHIFT) & ~F_NORM_MASK ! yes (very unlikely): check for overflow + ! XXX - I think these tests say 0x7e7fffff overflows + jae overflow + +! Step 3: put it all together + +step3: + or edx,ecx ! include sign + mov F_HIGH[ebx],edx ! store the result in [ebx] + ret #D_SIZE ! return and release double from stack + + .align ALIGNMENT +outofbounds: + jns overflow ! have just compared exponent with the max +underflow: +! call fpunderflow ! XXX + push ecx ! save sign + mov ecx,edx + and ecx,#~D_FRAC_MASK ! assume fraction is below exp + cmp ecx,#-((D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT) ! was exp = 0? + jz exp_x_0 + shr ecx,#D_EXP_SHIFT + neg ecx + and edx,#D_FRAC_MASK + or edx,#D_NORM_MASK + shld edx,eax,#D_EXP_BIT-F_EXP_BIT-1 + shl eax,#D_EXP_BIT-F_EXP_BIT-1 + push ebx ! save to use for rounding + sub ebx,ebx + shrd ebx,eax,cl + shrd eax,edx,cl + shr edx,cl + cmp eax,#1 << (REG_BIT-1) + jb over_denorm_roundup + ja denorm_roundup + test dl,#1 + jz over_denorm_roundup +denorm_roundup: +#if F_NORM_BIT != F_EXP_SHIFT +#include "carry into norm bit doesn't go into low exp bit" +#endif + inc edx +over_denorm_roundup: + pop ebx + pop ecx + or edx,ecx + mov F_HIGH[ebx],edx + ret #D_SIZE + + .align ALIGNMENT +exp_x_0: ! XXX check for denormals - they underflow + pop ecx + mov dword F_HIGH[ebx],#0 + ret #D_SIZE + + .align ALIGNMENT +overflow: + mov edx,ebx ! put sign in usual reg + call fpoverflow + mov F_HIGH[ebx],dword #F_HUGE_HIGH ! XXX - should use infinity + ret #D_SIZE ! ... if fpoverflow does diff --git a/libc/i386fp/fpushd.x b/libc/i386fp/fpushd.x new file mode 100644 index 0000000..68caab0 --- /dev/null +++ b/libc/i386fp/fpushd.x @@ -0,0 +1,60 @@ +! bcc 386 floating point routines (version 2) -- dtof, Fpushd, Fneg, Fnegd +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern Fpullf + +! dtof converts the double at [ebx] to a float and pushes the float onto +! the stack (D_SIZE bytes are allocated for the float although only the bottom +! F_SIZE are used). +! This is a quickly-written slowish version. + + .globl dtof + .align ALIGNMENT +dtof: + pop eax + sub esp,#D_SIZE ! build result here + push eax ! put back return address + call Fpushd + lea ebx,D_SIZE+PC_SIZE[esp] + call Fpullf + ret + +! Push double at address [ebx] onto stack + + .globl Fpushd + .align ALIGNMENT +Fpushd: + pop ecx + push dword D_HIGH[ebx] + push dword D_LOW[ebx] + jmp ecx ! return + +! Push double at address [ebx] onto stack, negating it on the way. + +! Don't worry about generating -0 because other routines have to allow for +! it anyway. + +! Perhaps this and Fneg should check for denormals and illegal operands +! (I think only signalling NaNs are illegal). +! fchs doesn't check, but fld does. +! Our Fpushd is not quite like fld because no conversions are involved. + + .globl Fnegd + .align ALIGNMENT +Fnegd: + pop ecx + mov eax,D_HIGH[ebx] + xor eax,#D_SIGN_MASK ! toggle sign + push eax + push dword D_LOW[ebx] + jmp ecx ! return + +! Negate double on stack + + .globl Fneg + .align ALIGNMENT +Fneg: + xorb PC_SIZE+D_SIZE-1[esp],D_SIGN_MASK >> (REG_BIT-CHAR_BIT) ! toggle sign + ret diff --git a/libc/i386fp/fpushf.x b/libc/i386fp/fpushf.x new file mode 100644 index 0000000..7cb2f8d --- /dev/null +++ b/libc/i386fp/fpushf.x @@ -0,0 +1,74 @@ +! bcc 386 floating point routines (version 2) -- Fpushf, Fnegf +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern fpdenormal + +! Load float at [ebx], convert to double and push on stack + + .globl Fpushf + .align ALIGNMENT +Fpushf: + mov edx,F_HIGH[ebx] +into_Fpushf: + test edx,#F_EXP_MASK ! is exponent 0? + jz exp_x_0 + + mov ecx,edx ! extract sign + and ecx,#F_SIGN_MASK + + and edx,#F_EXP_MASK | F_FRAC_MASK ! extract exponent and fraction + sub eax,eax ! clear lower dword + shrd eax,edx,#D_EXP_BIT-F_EXP_BIT ! shift exponent and fraction to new position + shr edx,#D_EXP_BIT-F_EXP_BIT + + add edx,#(D_EXP_BIAS-F_EXP_BIAS) << D_EXP_SHIFT ! adjust exponent bias + or edx,ecx ! include sign + + pop ecx + push edx ! upper dword + push eax ! lower dword + jmp ecx ! return + + .align ALIGNMENT +exp_x_0: + mov eax,edx + and eax,#F_FRAC_MASK + jnz x_denorm + pop ecx + push eax ! upper dword = 0 + push eax ! lower dword = 0 + jmp ecx ! return + + .align ALIGNMENT +x_denorm: + call fpdenormal + bsr ecx,eax ! zzzz + neg ecx + add ecx,#F_NORM_BIT + shl eax,cl + and eax,#F_FRAC_MASK + neg ecx + add ecx,#D_EXP_BIAS-F_EXP_BIAS+1 + shl ecx,#D_EXP_SHIFT + and edx,#F_SIGN_MASK ! assumed same as D_SIGN_MASK + or edx,ecx + sub ecx,ecx + shrd ecx,eax,#D_EXP_BIT-F_EXP_BIT + shr eax,#D_EXP_BIT-F_EXP_BIT + or edx,eax + + pop eax + push edx ! upper dword + push ecx ! lower dword + jmp eax ! return + +! Fnegf: as Fpushf, but negate double before pushing onto stack + + .globl Fnegf + .align ALIGNMENT +Fnegf: + mov edx,F_HIGH[ebx] + xor edx,#F_SIGN_MASK ! toggle sign + jmp into_Fpushf ! join Fpushf diff --git a/libc/i386fp/fpushi.x b/libc/i386fp/fpushi.x new file mode 100644 index 0000000..b19aae2 --- /dev/null +++ b/libc/i386fp/fpushi.x @@ -0,0 +1,126 @@ +! bcc 386 floating point routines (version 2) +! -- Fpushi, Fpushl, Fpushs, Fpushc, Fpushuc, Fpushui, Fpushul, Fpushus +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + +! Convert the short in ax to double and push on stack + + .globl Fpushs + .align ALIGNMENT +Fpushs: + cwde + add eax,#0 ! fast 3-byte instruction to align + +! Convert the int or long in eax to double and push on stack + + .globl Fpushi + .globl Fpushl +! .align ALIGNMENT ! don't do this until it pads with nop's +Fpushi: +Fpushl: + test eax,eax + jz return_eax ! got 0 in eax + mov ebx,#(D_EXP_BIAS+D_NORM_BIT) << D_EXP_SHIFT ! set no-sign and exponent + jns normalize ! sign and fraction bits already set up + mov ebx,#D_SIGN_MASK | ((D_EXP_BIAS+D_NORM_BIT) << D_EXP_SHIFT) ! adjust sign + neg eax ! adjust fraction + jmp normalize + + .align ALIGNMENT +ret1: + mov eax,#D_EXP_BIAS << D_EXP_SHIFT + add eax,#0 ! fast 3-byte instruction to align + +! .align ALIGNMENT ! don't do this until it pads with nop's +return_eax: + pop ecx + push eax ! upper dword + push dword #0 ! lower dword = 0 + jmp ecx ! return + +! Convert the (unsigned) char in al to double and push on stack + + .globl Fpushc + .globl Fpushuc + .align ALIGNMENT +Fpushc: +Fpushuc: + and eax,#(1 << CHAR_BIT)-1 + add eax,#0 ! fast 3-byte instruction to align + +! Convert the unsigned short in ax to double and push on stack + + .globl Fpushus +! .align ALIGNMENT ! don't do this until it pads with nop's +Fpushus: + and eax,#(1 << SHORT_BIT)-1 + add eax,#0 ! fast 3-byte instruction to align + +! Convert the unsigned int or long in eax to double and push on stack + + .globl Fpushui + .globl Fpushul +! .align ALIGNMENT ! don't do this until it pads with nop's +Fpushui: +Fpushul: + cmp eax,#1 ! this tests for both 0 and 1 + jb return_eax ! got 0 in eax + jz ret1 + mov ebx,#(D_EXP_BIAS+D_NORM_BIT) << D_EXP_SHIFT ! set no-sign and exponent + +! .align ALIGNMENT ! don't do this until it pads with nop's +normalize: + sub edx,edx ! clear lower dword of result + +! Find first nonzero bit +! Don't use bsr, it is slow (const + 3n on 386, const + n on 486) + + sub ecx,ecx ! prepare unsigned extension of cl + test eax,#~D_FRAC_MASK + jnz large + test eax,#0xFF << (D_NORM_BIT-8) + jnz middle + shl eax,#8 + sub ebx,#8 << D_EXP_SHIFT + test eax,#0xFF << (D_NORM_BIT-8) + jnz middle + shl eax,#8 + sub ebx,#8 << D_EXP_SHIFT +middle: + shld ecx,eax,#D_NORM_BIT + mov cl,bsr_table[ecx] + add ecx,#REG_BIT-D_NORM_BIT-D_NORM_BIT + neg ecx + shl eax,cl + shl ecx,#D_EXP_SHIFT + sub ebx,ecx +return: + and eax,#D_FRAC_MASK ! remove normalization bit + or eax,ebx ! include exponent (and sign) to fraction + pop ecx + push eax ! upper dword + push edx ! lower dword + jmp ecx ! return + + .align ALIGNMENT +large: + shld ecx,eax,#REG_BIT-(D_NORM_BIT+8) + jnz huge + shld ecx,eax,#REG_BIT-D_NORM_BIT + mov cl,bsr_table[ecx] +got_shift_right: + shrd edx,eax,cl + shr eax,cl + shl ecx,#D_EXP_SHIFT + add ebx,ecx + jmp return + + .align ALIGNMENT +huge: + mov cl,bsr_table[ecx] + add cl,#8 + jmp got_shift_right + + .data + .extern bsr_table diff --git a/libc/i386fp/frexp.x b/libc/i386fp/frexp.x new file mode 100644 index 0000000..318fc34 --- /dev/null +++ b/libc/i386fp/frexp.x @@ -0,0 +1,66 @@ +! bcc 386 floating point routines (version 2) -- _frexp +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern fpdenormal + +! void frexp(double value, int *exponent); +! splits a double into exponent and fraction (where 0.5 <= fraction < 1.0) + + .globl _frexp + .align ALIGNMENT +_frexp: +push ebx +#undef PC_SIZE +#define PC_SIZE 8 + mov eax,PC_SIZE+D_LOW[esp] ! lower dword of x + mov ebx,PC_SIZE+D_HIGH[esp] ! upper dword of x + mov edx,PC_SIZE+D_SIZE[esp] ! exponent pointer + mov ecx,ebx ! extract exponent here + and ecx,#D_EXP_MASK + jz exp_x_0 + + shr ecx,#D_EXP_SHIFT ! exponent + bias +got_x: + sub ecx,#D_EXP_BIAS-1 ! D_EXP_BIAS is for 1.x form, we want 0.1x form + mov [edx],ecx ! return exponent + and ebx,#D_SIGN_MASK | D_FRAC_MASK ! extract sign and fraction + or ebx,#(D_EXP_BIAS-1) << D_EXP_SHIFT ! set new exponent for 0.1x +mov edx,ebx +pop ebx + ret + + .align ALIGNMENT +exp_x_0: + test ebx,#D_FRAC_MASK + jnz xu_denorm + test eax,eax + jnz xl_denorm + mov [edx],ecx ! return zero exponent + mov ebx,ecx ! guard against -0 (may not be necessary) +mov edx,ebx +pop ebx + ret + + .align ALIGNMENT +xl_denorm: + call fpdenormal + bsr ecx,eax ! zzzz + neg ecx + add ecx,#REG_BIT-1 + shl eax,cl + shld ebx,eax,#D_NORM_BIT+1 + shl eax,#D_NORM_BIT+1 + sub ecx,#D_NORM_BIT+1 + jmp got_x + + .align ALIGNMENT +xu_denorm: + call fpdenormal + bsr ecx,ebx + neg ecx + add ecx,#D_NORM_BIT + shld ebx,eax,cl + shl eax,cl + jmp got_x diff --git a/libc/i386fp/ftst.x b/libc/i386fp/ftst.x new file mode 100644 index 0000000..2a92ef1 --- /dev/null +++ b/libc/i386fp/ftst.x @@ -0,0 +1,28 @@ +! bcc 386 floating point routines (version 2) -- Ftst, Ftstd, Ftstf +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + +#if 0 /* bcc doesn't generate Ftst (but it might in future) */ + .globl Ftst +#endif + .align ALIGNMENT +Ftst: + cmp dword PC_SIZE+D_HIGH[esp],#0 ! need only test upper dword of x + ret #D_SIZE + +! Compare double at address [ebx] with 0 + + .globl Ftstd + .align ALIGNMENT +Ftstd: + cmp dword D_HIGH[ebx],#0 ! need only test upper dword of x + ret + +! Compare float at address [ebx] with 0 + + .globl Ftstf + .align ALIGNMENT +Ftstf: + cmp dword F_HIGH[ebx],#0 + ret diff --git a/libc/i386fp/ldexp.x b/libc/i386fp/ldexp.x new file mode 100644 index 0000000..bc9dd03 --- /dev/null +++ b/libc/i386fp/ldexp.x @@ -0,0 +1,74 @@ +! bcc 386 floating point routines (version 2) -- _ldexp +! authors: Timothy Murphy (tim@maths.tcd.ie), Bruce Evans + +#include "fplib.h" + + .extern fpoverflow + .extern fpunderflow + +! void ldexp(double value, int exponent); +! returns value * (2 ** exponent) + + .globl _ldexp + .align ALIGNMENT +_ldexp: +push ebx +#undef PC_SIZE +#define PC_SIZE 8 + mov ebx,PC_SIZE+D_HIGH[esp] ! upper dword of x + mov ecx,PC_SIZE+D_SIZE[esp] ! exponent arg + mov eax,ebx ! extract exponent (of x) here + and eax,#D_EXP_MASK +! jz exp_y_0 ! may need check for preposterous exponent arg too + + shr eax,#D_EXP_SHIFT ! shift to low bits just for testing + jz underflow ! denormal? + add eax,ecx ! test-add the exponents + jz underflow ! XXX probably need to fiddle norm bit + cmp eax,#D_EXP_INFINITE ! check if still within range + jae outofbounds ! the unsigned compare catches all overflow cases + ! because the exponent of x is non-negative + + shl ecx,#D_EXP_SHIFT ! shift exponent arg bits into final position ... + add ebx,ecx ! ... safe to add it to exponent of x now + mov eax,PC_SIZE+D_LOW[esp] ! lower dword of x +mov edx,ebx +pop ebx + ret + + + .align ALIGNMENT +outofbounds: + test ecx,ecx ! overflow or underflow? + jns overflow +underflow: + mov edx,ebx ! put sign in usual reg + push edi + push esi + mov edi,eax ! put exponent in usual reg + mov eax,2*GENREG_SIZE+PC_SIZE+D_LOW[esp] + ! put lower dword of x in usual reg + mov esi,ebx ! put upper dword of x in usual reg + and esi,#D_EXP_MASK | D_FRAC_MASK + test esi,#D_EXP_MASK + jz foo + and esi,#D_FRAC_MASK + or esi,#D_NORM_MASK +foo: + neg edi +! inc edi ! XXX ? + call fpunderflow + pop esi + pop edi + mov ebx,edx ! XXX = wrong reg +pop ebx + ret + + .align ALIGNMENT +overflow: + mov edx,ebx ! put sign in usual reg + call fpoverflow + mov eax,ecx ! XXX = wrong reg + mov ebx,edx ! XXX = wrong reg +pop ebx + ret diff --git a/libc/i386fp/modf.c b/libc/i386fp/modf.c new file mode 100644 index 0000000..3232543 --- /dev/null +++ b/libc/i386fp/modf.c @@ -0,0 +1,14 @@ +#include <math.h> + +/* Slooow version. */ + +double modf(x, pint) +double x; +double *pint; +{ + if (x >= 0) + *pint = floor(x); + else + *pint = ceil(x); + return x - *pint; +} diff --git a/libc/i386fp/test.c b/libc/i386fp/test.c new file mode 100644 index 0000000..bd92581 --- /dev/null +++ b/libc/i386fp/test.c @@ -0,0 +1,118 @@ +#include <sys/times.h> +#include <limits.h> +#include <stdio.h> +#include <time.h> + +#define CONVTYPE int +#define MAX (MIN + NITER - 1) +#define MIN INT_MIN + +#define NITER 1000000 + +double one = 1; +double two = 2; +double big = 1e99; + +double d; +double d1; +float f; + +int main() +{ + CONVTYPE cti; + CONVTYPE cto; + clock_t delta; + struct tms finish; + int i; + struct tms start; + +#if 0 + times(&start); + for (cti = MIN; cti <= MAX; ++cti) + { + d = cti; + cto = d; + if (cti != cto) + printf("%08x %08x\n", cti, cto); + if (cti % 10000000 == 0) + { + printf("%8x ok ", cti); + fflush(stdout); + } + } + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for %d i -> d and d -> i conversions was %g s (%d t)\n", + MAX - MIN + 1, delta / (double) CLOCKS_PER_SEC, delta); +#endif + + times(&start); + for (cti = MIN; cti <= MAX; ++cti) + d = cti; + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for %d i -> d conversions was %g s (%d t)\n", + MAX - MIN + 1, delta / (double) CLOCKS_PER_SEC, delta); + + times(&start); + for (cti = MIN; cti <= MAX; ++cti) + { + d = cti; + cto = d; + } + times(&finish); + delta = finish.tms_utime - start.tms_utime - delta; + printf("Time for %d d -> i conversions was %g s (%d t)\n", + MAX - MIN + 1, delta / (double) CLOCKS_PER_SEC, delta); + + d = 0; + times(&start); + for (i = 0; i < NITER; ++i) + d = d + 1; + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for adding %d 1.0's to 0.0 was %g s (%d t), result = %g\n", + NITER, delta / (double) CLOCKS_PER_SEC, delta, d); + + d = 0; + times(&start); + for (; d < NITER;) + d = d + 1; + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for adding %d 1.0's to 0.0 (d index) was %g s (%d t), result = %g\n", + NITER, delta / (double) CLOCKS_PER_SEC, delta, d); + + times(&start); + for (i = 1; i <= NITER; ++i) + { + d1 = i; + d = d1 * d1; + } + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for %d mults was %g s (%d t), result = %g\n", + NITER, delta / (double) CLOCKS_PER_SEC, delta, d); + + times(&start); + for (i = 1; i <= NITER; ++i) + { + d1 = i; + d = 1 / d1; + } + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for %d divs was %g s (%d t), result = %g\n", + NITER, delta / (double) CLOCKS_PER_SEC, delta, d); + + f = 0; + times(&start); + for (i = 0; i < NITER; ++i) + f = f + 1; + times(&finish); + delta = finish.tms_utime - start.tms_utime; + printf("Time for adding %d 1.0f's to 0.0f was %g s (%d t), result = %g\n", + NITER, delta / (double) CLOCKS_PER_SEC, delta, f); + + return 0; +} diff --git a/libc/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/bsd/bsd.h b/libc/include/bsd/bsd.h new file mode 100644 index 0000000..5ab1173 --- /dev/null +++ b/libc/include/bsd/bsd.h @@ -0,0 +1,49 @@ +/* bsd.h - simplify porting BSD programs to Linux - rick sladkey */ + +/* make sure BSD features are enabled, i.e. __USE_BSD and _FAVOR_BSD */ + +/* cpp in gcc 2.3.3 is broken. +#ifndef _BSD_BSD_H +#define _BSD_BSD_H +*/ + +#define _BSD_SOURCE 1 +#include <features.h> +#include <endian.h> + +/* some BSD progs expect MIN and MAX to be defined */ + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +/* make sure we get L_SET and L_INCR, which is in a different place */ + +#include <sys/file.h> + +/* BSD has slight non-POSIX names (and meanings :-) for some things */ + +#define FAPPEND O_APPEND + +#include <limits.h> + +/* (absolute) max # characters in exec arglist */ + +#define NCARGS ARG_MAX + +/* ftpd uses this as bits per byte, I don't know why it's called NBBY */ + +#define NBBY CHAR_BIT + +/* gloss over slight differences between BSD direct and POSIX dirent */ + +#define d_namlen d_reclen + +#if 0 + +/* See <bsd/signal.h> */ + +typedef void sig_t; + +#endif + +/* #endif _BSD_BSD_H */ diff --git a/libc/include/bsd/errno.h b/libc/include/bsd/errno.h new file mode 100644 index 0000000..c2d464e --- /dev/null +++ b/libc/include/bsd/errno.h @@ -0,0 +1,9 @@ +/* make sure EWOULDBLOCK doesn't screw us up */ +#ifndef _BSD_ERRNO_H +#define _BSD_ERRNO_H + +#include_next <errno.h> +#undef EWOULDBLOCK +#define EWOULDBLOCK EAGAIN + +#endif /* _BSD_ERRNO_H */ diff --git a/libc/include/bsd/sgtty.h b/libc/include/bsd/sgtty.h new file mode 100644 index 0000000..4e21901 --- /dev/null +++ b/libc/include/bsd/sgtty.h @@ -0,0 +1,113 @@ +/* sgtty.h */ + +/* This file contains defintions to help make linux termios look like + bsd sgtty. */ + +/* Copyright (c) 1992 Ross Biro + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free +Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#ifndef _BSD_SGTTY_H +#define _BSD_SGTTY_H + +#include <termios.h> + +#define TIOCGETP 0x5481 +#define TIOCSETP 0x5482 +#define TIOCGETC 0x5483 +#define TIOCSETC 0x5484 +#define TIOCGLTC 0x5485 +#define TIOCSLTC 0x5486 +#define TIOCLGET 0x5487 +#define TIOCLSET 0x5488 +#define TIOCFLUSH 0x5489 +#define TIOCSETN 0x548a + +struct sgttyb +{ + unsigned short sg_flags; + char sg_ispeed; + char sg_ospeed; + char sg_erase; + char sg_kill; + struct termios t; + int check; +}; + +struct tchars +{ + char t_intrc; + char t_quitc; + char t_eofc; + char t_startc; + char t_stopc; + char t_brkc; +}; + +struct ltchars +{ + char t_werasc; + char t_suspc; + char t_dsuspc; + char t_rprntc; + char t_flushc; + char t_lnextc; +}; + +#define O_RAW 1 +#define O_LCASE 2 +#define O_CRMOD 4 +#define O_ECHO 8 +#define O_ODDP 16 +#define O_EVENP 32 +#define O_CBREAK 64 +/* these don't do anything yet. */ +#define O_TBDELAY 0 +#define O_LLITOUT 0 +#define O_XTABS 0 +#define O_ANYP 0 + +#ifndef _SGTTY_SOURCE + +#undef ioctl +#define ioctl bsd_ioctl + +#undef RAW +#define RAW O_RAW +#undef LCASE +#define LCASE O_LCASE +#undef ECHO +#define ECHO O_ECHO +#undef CRMOD +#define CRMOD O_CRMOD +#undef ODDP +#define ODDP O_ODDP +#undef EVENP +#define EVENP O_EVENP +#undef CBREAK +#define CBREAK O_CBREAK +#undef TBDELAY +#define TBDELAY O_TBDELAY +#undef LLITOUT +#define LLITOUT O_LLITOUT +#undef XTABS +#define XTABS O_XTABS +#undef ANYP +#define ANYP O_ANYP +#endif + +#endif /* _BSD_SGTTY_H */ diff --git a/libc/include/bsd/signal.h b/libc/include/bsd/signal.h new file mode 100644 index 0000000..24d4502 --- /dev/null +++ b/libc/include/bsd/signal.h @@ -0,0 +1,25 @@ +#ifndef _BSD_SIGNAL_H +#define _BSD_SIGNAL_H + +/* make sure we get BSD style signals (that don't need to be reset) */ + +#define __USE_BSD_SIGNAL +#include_next <signal.h> + +/* use rough approximation of sigaction to sigvec, not completely safe! */ + +#define sigvec sigaction +#define sv_mask sa_mask +#define sv_flags sa_flags +#define sv_handler sa_handler +#define sv_onstack sa_mask /* ouch, this one really hurts */ + +/* BSD uses some non-POSIX signals without ifdefs */ + +#define SIGSYS SIGUNUSED + +/* BSD wants this typedef for signal handlers */ + +#define sig_t __sighandler_t + +#endif /* _BSD_SIGNAL_H */ diff --git a/libc/include/bsd/stdlib.h b/libc/include/bsd/stdlib.h new file mode 100644 index 0000000..20d34f9 --- /dev/null +++ b/libc/include/bsd/stdlib.h @@ -0,0 +1,12 @@ +/* some things shouldn't be macros, get out your barf bag */ + +#ifndef _BSD_STDLIB_H +#define _BSD_STDLIB_H + +#undef __MALLOC_0_RETURNS_NULL +#define __MALLOC_0_RETURNS_NULL +#include_next <stdlib.h> +#undef atoi +#undef atol + +#endif /* _BSD_STDLIB_H */ diff --git a/libc/include/bsd/sys/ttychars.h b/libc/include/bsd/sys/ttychars.h new file mode 100644 index 0000000..b3a2036 --- /dev/null +++ b/libc/include/bsd/sys/ttychars.h @@ -0,0 +1,3 @@ +#ifndef _BSD_SYS_TTYCHARS_H +#define _BSD_SYS_TTYCHARS_H +#endif /* _BSD_SYS_TTYCHARS_H */ diff --git a/libc/include/bsd/tzfile.h b/libc/include/bsd/tzfile.h new file mode 100644 index 0000000..459a603 --- /dev/null +++ b/libc/include/bsd/tzfile.h @@ -0,0 +1,10 @@ +#ifndef _BSD_TZFILE_H +#define _BSD_TZFILE_H + +#define SECSPERDAY (60*60*24) +#define DAYSPERNYEAR 365 +#define DAYSPERLYEAR 366 + +#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0) + +#endif /* _BSD_TZFILE_H */ diff --git a/libc/include/bsd/unistd.h b/libc/include/bsd/unistd.h new file mode 100644 index 0000000..20c2ccc --- /dev/null +++ b/libc/include/bsd/unistd.h @@ -0,0 +1,4 @@ +#include_next <unistd.h> +#include <sys/time.h> +#include <fcntl.h> +#include <sys/stat.h> diff --git a/libc/include/ctype.h b/libc/include/ctype.h new file mode 100644 index 0000000..3e94272 --- /dev/null +++ b/libc/include/ctype.h @@ -0,0 +1,38 @@ +/* + * ctype.h Character classification and conversion + */ + +#ifndef __CTYPE_H +#define __CTYPE_H + +extern unsigned char _ctype[]; + +#define __CT_d 0x01 /* numeric digit */ +#define __CT_u 0x02 /* upper case */ +#define __CT_l 0x04 /* lower case */ +#define __CT_c 0x08 /* control character */ +#define __CT_s 0x10 /* whitespace */ +#define __CT_p 0x20 /* punctuation */ +#define __CT_x 0x40 /* hexadecimal */ + +#define toupper(c) (islower(c) ? (c)^0x20 : (c)) +#define tolower(c) (isupper(c) ? (c)^0x20 : (c)) +#define _toupper(c) ((c)^0x20) +#define _tolower(c) ((c)^0x20) +#define toascii(c) ((c)&0x7F) + +/* Note the '!!' is a cast to 'bool' and even BCC deletes it in an if() */ +#define isalnum(c) (!!(_ctype[(int) c]&(__CT_u|__CT_l|__CT_d))) +#define isalpha(c) (!!(_ctype[(int) c]&(__CT_u|__CT_l))) +#define isascii(c) (!((c)&~0x7F)) +#define iscntrl(c) (!!(_ctype[(int) c]&__CT_c)) +#define isdigit(c) (!!(_ctype[(int) c]&__CT_d)) +#define isgraph(c) (!(_ctype[(int) c]&(__CT_c|__CT_s))) +#define islower(c) (!!(_ctype[(int) c]&__CT_l)) +#define isprint(c) (!(_ctype[(int) c]&__CT_c)) +#define ispunct(c) (!!(_ctype[(int) c]&__CT_p)) +#define isspace(c) (!!(_ctype[(int) c]&__CT_s)) +#define isupper(c) (!!(_ctype[(int) c]&__CT_u)) +#define isxdigit(c) (!!(_ctype[(int) c]&__CT_x)) + +#endif /* __CTYPE_H */ diff --git a/libc/include/dirent.h b/libc/include/dirent.h new file mode 100644 index 0000000..c2e8f37 --- /dev/null +++ b/libc/include/dirent.h @@ -0,0 +1,52 @@ + +#ifndef __DIRENT_H +#define __DIRENT_H + +#include <features.h> +#include <sys/types.h> + +#ifndef MAXNAMLEN +#define MAXNAMLEN 255 +#endif + +/* Directory stream type. */ +typedef struct { + int dd_fd; /* file descriptor */ + int dd_loc; /* offset in buffer */ + int dd_size; /* # of valid entries in buffer */ + struct dirent *dd_buf; /* -> directory buffer */ +} DIR; /* stream data from opendir() */ + +typedef int (*__dir_select_fn_t) __P ((__const struct dirent *)); + +typedef int (*__dir_compar_fn_t) __P (( + __const struct dirent * __const *, + __const struct dirent * __const * + )); + +struct dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[MAXNAMLEN+1]; +}; + +extern DIR *opendir __P ((__const char *__name)); +extern int closedir __P ((DIR * __dirp)); +extern struct dirent *readdir __P ((DIR * __dirp)); +extern void rewinddir __P ((DIR * __dirp)); + +extern void seekdir __P ((DIR * __dirp, off_t __pos)); +extern off_t telldir __P ((DIR * __dirp)); + +/* Scan the directory DIR, calling SELECT on each directory entry. + Entries for which SELECT returns nonzero are individually malloc'd, + sorted using qsort with CMP, and collected in a malloc'd array in + *NAMELIST. Returns the number of entries selected, or -1 on error. */ +extern int scandir __P ((__const char *__dir, + struct dirent ***__namelist, + __dir_select_fn_t __select, + __dir_compar_fn_t __compar)); + +#endif /* dirent.h */ + diff --git a/libc/include/dos.h b/libc/include/dos.h new file mode 100644 index 0000000..1e2b11e --- /dev/null +++ b/libc/include/dos.h @@ -0,0 +1,36 @@ + +#ifndef __DOS_H +#define __DOS_H +#include <features.h> + +union REGS +{ + struct { unsigned int ax, bx, cx, dx, si, di, cflag; } x; + struct { unsigned char al, ah, bl, bh, cl, ch, dl, dh; } h; +}; + +struct SREGS +{ + unsigned int es, cs, ss, ds; +}; + +#ifdef __MSDOS__ +extern unsigned int __envseg; +extern unsigned int __psp; +char * __fconv __P((char * fname)); + +unsigned int __segalloc __P((unsigned int paracount)); +void __setvect __P((int i, long j)); +long __getvect __P((int vecno)); +#endif + +unsigned int __get_ds __P((void)); +unsigned int __get_es __P((void)); +void __set_es __P((unsigned int seg)); +int __peek_es __P((unsigned int off)); +int __deek_es __P((unsigned int off)); + +#define movedata __movedata + +#endif + diff --git a/libc/include/errno.h b/libc/include/errno.h new file mode 100644 index 0000000..c8d2002 --- /dev/null +++ b/libc/include/errno.h @@ -0,0 +1,25 @@ +#ifndef __ERRNO_H +#define __ERRNO_H + +#include <features.h> +#include <linuxmt/errno.h> + +#ifdef __USE_BSD +extern int sys_nerr; +extern char *sys_errlist[]; +#endif +#ifdef __USE_GNU +extern int _sys_nerr; +extern char *_sys_errlist[]; +#endif + +extern int errno; + +__BEGIN_DECLS + +extern void perror __P ((__const char* __s)); +extern char* strerror __P ((int __errno)); + +__END_DECLS + +#endif diff --git a/libc/include/fcntl.h b/libc/include/fcntl.h new file mode 100644 index 0000000..ddd9afc --- /dev/null +++ b/libc/include/fcntl.h @@ -0,0 +1,20 @@ +#ifndef __FCNTL_H +#define __FCNTL_H + +#include <features.h> +#include <sys/types.h> +#include <linuxmt/fcntl.h> + +#ifndef FNDELAY +#define FNDELAY O_NDELAY +#endif + +__BEGIN_DECLS + +extern int creat __P ((__const char * __filename, mode_t __mode)); +extern int fcntl __P ((int __fildes,int __cmd, ...)); +extern int open __P ((__const char * __filename, int __flags, ...)); + +__END_DECLS + +#endif diff --git a/libc/include/features.h b/libc/include/features.h new file mode 100644 index 0000000..11eb610 --- /dev/null +++ b/libc/include/features.h @@ -0,0 +1,36 @@ + +#ifndef __FEATURES_H +#define __FEATURES_H + +#ifdef __STDC__ + +#define __P(x) x +#define __const const + +/* Almost ansi */ +#if __STDC__ != 1 +#define const +#define volatile +#endif + +#else /* K&R */ + +#define __P(x) () +#define __const +#define const +#define volatile + +#endif + +/* No C++ */ +#define __BEGIN_DECLS +#define __END_DECLS + +/* GNUish things */ +#define __CONSTVALUE +#define __CONSTVALUE2 + +#include <sys/cdefs.h> + +#endif + diff --git a/libc/include/getopt.h b/libc/include/getopt.h new file mode 100644 index 0000000..0d71ff6 --- /dev/null +++ b/libc/include/getopt.h @@ -0,0 +1,17 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#ifndef __GETOPT_H +#define __GETOPT_H + +#include <features.h> + +extern char *optarg; +extern int opterr; +extern int optind; + +extern int getopt __P((int argc, char *const *argv, const char *shortopts)); + +#endif /* __GETOPT_H */ diff --git a/libc/include/grp.h b/libc/include/grp.h new file mode 100644 index 0000000..96b2b4b --- /dev/null +++ b/libc/include/grp.h @@ -0,0 +1,37 @@ +#ifndef __GRP_H +#define __GRP_H + +#include <sys/types.h> +#include <features.h> +#include <stdio.h> + +/* The group structure */ +struct group +{ + char *gr_name; /* Group name. */ + char *gr_passwd; /* Password. */ + gid_t gr_gid; /* Group ID. */ + char **gr_mem; /* Member list. */ +}; + +extern void setgrent __P ((void)); +extern void endgrent __P ((void)); +extern struct group * getgrent __P ((void)); + +extern struct group * getgrgid __P ((__const gid_t gid)); +extern struct group * getgrnam __P ((__const char * name)); + +extern struct group * fgetgrent __P ((FILE * file)); + +extern int setgroups __P ((size_t n, __const gid_t * groups)); +extern int initgroups __P ((__const char * user, gid_t gid)); + + +#ifdef __LIBC__ +extern struct group * __getgrent __P ((int grp_fd)); +#endif + +#endif /* _GRP_H */ + + + diff --git a/libc/include/limits.h b/libc/include/limits.h new file mode 100644 index 0000000..520c1c4 --- /dev/null +++ b/libc/include/limits.h @@ -0,0 +1,57 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#ifndef __LIMITS_H +#define __LIMITS_H + +#if __AS386_16__ +#define MB_LEN_MAX 1 /* Longest multi-byte character */ +#define CHAR_MAX 127 /* maximum char value */ +#define CHAR_MIN (-127) /* mimimum char value */ +#define SCHAR_MAX 127 /* maximum signed char value */ +#define SCHAR_MIN (-127) /* minimum signed char value */ +#define CHAR_BIT 8 /* number of bits in a char */ +#define SHRT_MAX 32767 /* maximum (signed) short value */ +#define SHRT_MIN (-32767) /* minimum (signed) short value */ +#define INT_MAX 32767 /* maximum (signed) int value */ +#define INT_MIN (-32767) /* minimum (signed) int value */ +#define LONG_MAX 2147483647 /* maximum (signed) long value */ +#define LONG_MIN (-2147483647) /* minimum (signed) long value */ +#define UCHAR_MAX 255 /* maximum unsigned char value */ +#define USHRT_MAX 0xffff /* maximum unsigned short value */ +#define UINT_MAX 0xffff /* maximum unsigned int value */ +#define ULONG_MAX 0xffffffff /* maximum unsigned long value */ +#ifndef RAND_MAX +#define RAND_MAX INT_MAX +#endif +#endif + +#if __AS386_32__ +#define MB_LEN_MAX 1 /* Longest multi-byte character */ +#define CHAR_MAX 127 /* maximum char value */ +#define CHAR_MIN (-127) /* mimimum char value */ +#define SCHAR_MAX 127 /* maximum signed char value */ +#define SCHAR_MIN (-127) /* minimum signed char value */ +#define CHAR_BIT 8 /* number of bits in a char */ +#define SHRT_MAX 32767 /* maximum (signed) short value */ +#define SHRT_MIN (-32767) /* minimum (signed) short value */ +#define INT_MAX 2147483647 /* maximum (signed) int value */ +#define INT_MIN (-2147483647) /* minimum (signed) int value */ +#define LONG_MAX 2147483647 /* maximum (signed) long value */ +#define LONG_MIN (-2147483647) /* minimum (signed) long value */ +#define UCHAR_MAX 255 /* maximum unsigned char value */ +#define USHRT_MAX 0xffff /* maximum unsigned short value */ +#define UINT_MAX 0xffffffff /* maximum unsigned int value */ +#define ULONG_MAX 0xffffffff /* maximum unsigned long value */ +#ifndef RAND_MAX +#define RAND_MAX INT_MAX +#endif +#endif + +#ifndef CHAR_MAX +#error "Limits.h not implemented" +#endif + +#endif diff --git a/libc/include/malloc.h b/libc/include/malloc.h new file mode 100644 index 0000000..e8fdb0a --- /dev/null +++ b/libc/include/malloc.h @@ -0,0 +1,30 @@ + +#ifndef __MALLOC_H +#define __MALLOC_H +#include <features.h> +#include <sys/types.h> + +/* + * Mini malloc allows you to use a less efficient but smaller malloc the + * cost is about 100 bytes of code in free but malloc (700bytes) doesn't + * have to be linked. Unfortunatly memory can only be reused if everything + * above it has been freed + * + */ + +extern void free __P((void *)); +extern void *malloc __P((size_t)); +extern void *realloc __P((void *, size_t)); +extern void *alloca __P((size_t)); + +extern void *(*__alloca_alloc) __P((size_t)); + +#ifdef __LIBC__ +#define __MINI_MALLOC__ +#endif + +#ifdef __MINI_MALLOC__ +#define malloc(x) ((*__alloca_alloc)(x)) +#endif + +#endif diff --git a/libc/include/math.h b/libc/include/math.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libc/include/math.h diff --git a/libc/include/memory.h b/libc/include/memory.h new file mode 100644 index 0000000..3b2f590 --- /dev/null +++ b/libc/include/memory.h @@ -0,0 +1 @@ +#include <string.h> diff --git a/libc/include/paths.h b/libc/include/paths.h new file mode 100644 index 0000000..dc76939 --- /dev/null +++ b/libc/include/paths.h @@ -0,0 +1,21 @@ +/* paths.h <ndf@linux.mit.edu> */ + +#ifndef ___PATHS_H +#define ___PATHS_H + + +#define _PATH_CONSOLE "/dev/console" +#define _PATH_TTY "/dev/tty" +#define _PATH_NOLOGIN "/etc/nologin" +#define _PATH_LOGIN "/bin/login" +#define _PATH_BSHELL "/bin/sh" +#define _PATH_UTMP "/var/run/utmp" +#define _PATH_WTMP "/var/log/wtmp" +#define _PATH_DEFPATH "/bin:/usr/bin:/usr/local/bin:." +#define _PATH_DEV "/dev/" +#define _PATH_DEVNULL "/dev/null" +#define _PATH_TMP "/tmp/" +#define _PATH_LASTLOG "/var/log/lastlog" +#define _PATH_LOCALE "/usr/lib/locale" + +#endif /* __PATHS_H */ diff --git a/libc/include/pwd.h b/libc/include/pwd.h new file mode 100644 index 0000000..1b48c6a --- /dev/null +++ b/libc/include/pwd.h @@ -0,0 +1,40 @@ +#ifndef __PWD_H +#define __PWD_H + +#include <sys/types.h> +#include <features.h> +#include <stdio.h> + +/* The passwd structure. */ +struct passwd +{ + char *pw_name; /* Username. */ + char *pw_passwd; /* Password. */ + uid_t pw_uid; /* User ID. */ + gid_t pw_gid; /* Group ID. */ + char *pw_gecos; /* Real name. */ + char *pw_dir; /* Home directory. */ + char *pw_shell; /* Shell program. */ +}; + + +extern void setpwent __P ((void)); +extern void endpwent __P ((void)); +extern struct passwd * getpwent __P ((void)); + +extern int putpwent __P ((__const struct passwd * __p, FILE * __f)); +extern int getpw __P ((uid_t uid, char *buf)); + +extern struct passwd * fgetpwent __P ((FILE * file)); + +extern struct passwd * getpwuid __P ((__const uid_t)); +extern struct passwd * getpwnam __P ((__const char *)); + +#ifdef __LIBC__ +extern struct passwd * __getpwent __P ((__const int passwd_fd)); +#endif + +#endif /* pwd.h */ + + + diff --git a/libc/include/regexp.h b/libc/include/regexp.h new file mode 100644 index 0000000..73d6bf4 --- /dev/null +++ b/libc/include/regexp.h @@ -0,0 +1,21 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +extern void regsub(); +extern void regerror(); diff --git a/libc/include/regmagic.h b/libc/include/regmagic.h new file mode 100644 index 0000000..5acf447 --- /dev/null +++ b/libc/include/regmagic.h @@ -0,0 +1,5 @@ +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/libc/include/search.h b/libc/include/search.h new file mode 100644 index 0000000..b9c8a17 --- /dev/null +++ b/libc/include/search.h @@ -0,0 +1,94 @@ +/* Copyright (C) 1993 Ulrich Drepper + +This file is intended to be included in the GNU C Library and the +Linux C Library. So the copyright notice will be: + + +Copyright (C) 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. + + +For now the file can be distributed under the LGPL. */ + +#ifndef _SEARCH_H +#define _SEARCH_H + +#include <features.h> + +#define __need_size_t +#define __need_NULL +#include <stddef.h> + +__BEGIN_DECLS + +#ifndef __COMPAR_FN_T +#define __COMPAR_FN_T +typedef int (*__compar_fn_t) __P ((__const __ptr_t, __const __ptr_t)); +#endif + +/* for use with hsearch(3) */ + +typedef struct entry { char *key; char *data; } ENTRY; +typedef enum { FIND, ENTER } ACTION; + +extern ENTRY * hsearch __P((ENTRY __item, ACTION __action)); +extern int hcreate __P((unsigned __nel)); +extern void hdestroy __P((void)); + + +/* The tsearch routines are very interesting. They make many + * assumptions about the compiler. It assumpts that the first field + * in node must be the "key" field, which points to the datum. + * Everything depends on that. It is a very tricky stuff. H.J. + */ +/* For tsearch */ +typedef enum { preorder, postorder, endorder, leaf } VISIT; + +extern void *tsearch __P((__const void * __key, void **__rootp, + __compar_fn_t compar)); + +extern void *tfind __P((__const void * __key, __const void ** __rootp, + __compar_fn_t compar)); + +extern void *tdelete __P((__const void * __key, void ** __rootp, + __compar_fn_t compar)); + +#ifndef __ACTION_FN_T +#define __ACTION_FN_T +/* FYI, the first argument should be a pointer to "key". + * Please read the man page for details. + */ +typedef void (*__action_fn_t) __P((__const void *__nodep, + __const VISIT __value, + __const int __level)); +#endif + +extern void twalk __P((__const void * __root, __action_fn_t action)); + + +extern void * lfind __P((__const void * __key, __const void * __base, + size_t * __nmemb, size_t __size, + __compar_fn_t __compar)); + +extern void * lsearch __P((__const void * __key, __const void * __base, + size_t * __nmemb, size_t __size, + __compar_fn_t __compar)); + +__END_DECLS + +#endif /* search.h */ diff --git a/libc/include/setjmp.h b/libc/include/setjmp.h new file mode 100644 index 0000000..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/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..d30fbd8 --- /dev/null +++ b/libc/include/stdarg.h @@ -0,0 +1,43 @@ + /* + * @(#) stdarg.h 1.2 91/11/30 21:10:39 + * + * Sample stdarg.h file for use with the unproto filter. + * + * This file serves two purposes. + * + * 1 - As an include file for use with ANSI-style C source that implements + * variadic functions. + * + * 2 - To configure the unproto filter itself. If the _VA_ALIST_ macro is + * defined, its value will appear in the place of the "..." in argument + * lists of variadic function *definitions* (not declarations). + * + * Compilers that pass arguments via the stack can use the default code at the + * end of this file (this usually applies for the VAX, MC68k and 80*86 + * architectures). + * + * RISC-based systems often need special tricks. An example of the latter is + * given for the SPARC architecture. Read your /usr/include/varargs.h for + * more information. + * + * You can use the varargs.c program provided with the unproto package to + * verify that the stdarg.h file has been set up correctly. + */ + +#ifndef __STDARG_H +#define __STDARG_H + +#ifdef sparc +# define _VA_ALIST_ "__builtin_va_alist" + typedef char *va_list; +# define va_start(ap, p) (ap = (char *) &__builtin_va_alist) +# define va_arg(ap, type) ((type *) __builtin_va_arg_incr((type *) ap))[0] +# define va_end(ap) +#else /* vax, mc68k, 80*86 */ + typedef char *va_list; +# define va_start(ap, p) (ap = (char *) (&(p)+1)) +# define va_arg(ap, type) ((type *) (ap += sizeof(type)))[-1] +# define va_end(ap) +#endif + +#endif /* __STDARG_H */ diff --git a/libc/include/stddef.h b/libc/include/stddef.h new file mode 100644 index 0000000..ce3cf2b --- /dev/null +++ b/libc/include/stddef.h @@ -0,0 +1,28 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ +/* We don't care, ignore GCC's __need hackery */ + +#undef __need_wchar_t +#undef __need_size_t +#undef __need_ptrdiff_t +#undef __need_NULL + +/* Fact is these are _normal_ */ +#if 1 /* __BCC__ */ /* Only for Bcc 8086/80386 */ + +#ifndef __STDDEF_H +#define __STDDEF_H + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#endif /* __STDDEF_H */ +#endif /* __AS386_16__ */ diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 0000000..98ca38a --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,129 @@ + +#ifndef __STDIO_H +#define __STDIO_H + +#include <features.h> +#include <sys/types.h> + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#define _IOFBF 0x00 /* full buffering */ +#define _IOLBF 0x01 /* line buffering */ +#define _IONBF 0x02 /* no buffering */ +#define __MODE_BUF 0x03 /* Modal buffering dependent on isatty */ + +#define __MODE_FREEBUF 0x04 /* Buffer allocated with malloc, can free */ +#define __MODE_FREEFIL 0x08 /* FILE allocated with malloc, can free */ + +#define __MODE_READ 0x10 /* Opened in read only */ +#define __MODE_WRITE 0x20 /* Opened in write only */ +#define __MODE_RDWR 0x30 /* Opened in read/write */ + +#define __MODE_READING 0x40 /* Buffer has pending read data */ +#define __MODE_WRITING 0x80 /* Buffer has pending write data */ + +#define __MODE_EOF 0x100 /* EOF status */ +#define __MODE_ERR 0x200 /* Error status */ +#define __MODE_UNGOT 0x400 /* Buffer has been polluted by ungetc */ + +#ifdef __MSDOS__ +#define __MODE_IOTRAN 0x1000 /* MSDOS nl <-> cr,nl translation */ +#else +#define __MODE_IOTRAN 0 +#endif + +/* when you add or change fields here, be sure to change the initialization + * in stdio_init and fopen */ +struct __stdio_file { + unsigned char *bufpos; /* the next byte to write to or read from */ + unsigned char *bufread; /* the end of data returned by last read() */ + unsigned char *bufwrite; /* highest address writable by macro */ + unsigned char *bufstart; /* the start of the buffer */ + unsigned char *bufend; /* the end of the buffer; ie the byte after the last + malloc()ed byte */ + + int fd; /* the file descriptor associated with the stream */ + int mode; + + char unbuf[8]; /* The buffer for 'unbuffered' streams */ + + struct __stdio_file * next; +}; + +#define EOF (-1) +#ifndef NULL +#define NULL (0) +#endif + +typedef struct __stdio_file FILE; + +#ifdef __AS386_16__ +#define BUFSIZ (256) +#else +#define BUFSIZ (2048) +#endif + +extern FILE stdin[1]; +extern FILE stdout[1]; +extern FILE stderr[1]; + +#ifdef __MSDOS__ +#define putc(c, fp) fputc(c, fp) +#define getc(fp) fgetc(fp) +#else +#define putc(c, stream) \ + (((stream)->bufpos >= (stream)->bufwrite) ? fputc((c), (stream)) \ + : (unsigned char) (*(stream)->bufpos++ = (c)) ) + +#define getc(stream) \ + (((stream)->bufpos >= (stream)->bufread) ? fgetc(stream): \ + (*(stream)->bufpos++)) +#endif + +#define putchar(c) putc((c), stdout) +#define getchar() getc(stdin) + +#define ferror(fp) (((fp)->mode&__MODE_ERR) != 0) +#define feof(fp) (((fp)->mode&__MODE_EOF) != 0) +#define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0) +#define fileno(fp) ((fp)->fd) + +/* declare functions; not like it makes much difference without ANSI */ +/* RDB: The return values _are_ important, especially if we ever use + 8086 'large' model + */ + +/* These two call malloc */ +#define setlinebuf(__fp) setvbuf((__fp), (char*)0, _IOLBF, 0) +extern int setvbuf __P((FILE*, char*, int, size_t)); + +/* These don't */ +#define setbuf(__fp, __buf) setbuffer((__fp), (__buf), BUFSIZ) +extern void setbuffer __P((FILE*, char*, int)); + +extern int fgetc __P((FILE*)); +extern int fputc __P((int, FILE*)); + +extern int fclose __P((FILE*)); +extern int fflush __P((FILE*)); +extern char *fgets __P((char*, size_t, FILE*)); +extern FILE *__fopen __P((char*, int, FILE*, char*)); + +#define fopen(__file, __mode) __fopen((__file), -1, (FILE*)0, (__mode)) +#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode)) +#define fdopen(__file, __mode) __fopen((char*)0, (__file), (FILE*)0, (__mode)) + +extern int fputs __P((char*, FILE*)); +extern int puts __P((char*)); + +extern int printf __P ((__const char*, ...)); +extern int fprintf __P ((FILE*, __const char*, ...)); +extern int sprintf __P ((char*, __const char*, ...)); + +#define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos) + +#endif /* __STDIO_H */ diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h new file mode 100644 index 0000000..7831424 --- /dev/null +++ b/libc/include/stdlib.h @@ -0,0 +1,46 @@ +/* stdlib.h <ndf@linux.mit.edu> */ +#include <features.h> +#include <sys/types.h> + +#ifndef __STDLIB_H +#define __STDLIB_H + +/* Don't overwrite user definitions of NULL */ +#ifndef NULL +#define NULL ((void *) 0) +#endif + +/* For program termination */ +#define EXIT_FAILURE 1 +#define EXIT_SUCCESS 0 + +extern void * malloc __P ((size_t)); +extern void * calloc __P ((size_t, size_t)); +extern void free __P ((void *)); +extern void * realloc __P ((void *, size_t)); + +extern int rand __P ((void)); +extern void srand __P ((unsigned int seed)); + +extern long strtol __P ((const char * nptr, char ** endptr, int base)); +extern unsigned long strtoul __P ((const char * nptr, + char ** endptr, int base)); +#ifndef __HAS_NO_FLOATS__ +extern double strtod __P ((const char * nptr, char ** endptr)); +#endif + +/* Returned by `div'. */ +typedef struct + { + int quot; /* Quotient. */ + int rem; /* Remainder. */ + } div_t; + +/* Returned by `ldiv'. */ +typedef struct + { + long int quot; /* Quotient. */ + long int rem; /* Remainder. */ + } ldiv_t; + +#endif /* __STDLIB_H */ diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 0000000..2233bf9 --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,53 @@ + +#ifndef __STRING_H +#define __STRING_H +#include <features.h> +#include <sys/types.h> +#include <stddef.h> + +/* Basic string functions */ +extern size_t strlen __P ((__const char* __str)); + +extern char * strcat __P ((char*, __const char*)); +extern char * strcpy __P ((char*, __const char*)); +extern int strcmp __P ((__const char*, __const char*)); + +extern char * strncat __P ((char*, char*, size_t)); +extern char * strncpy __P ((char*, char*, size_t)); +extern int strncmp __P ((__const char*, __const char*, size_t)); + +extern char * strchr __P ((char*, int)); +extern char * strrchr __P ((char*, int)); +extern char * strdup __P ((char*)); + +/* Basic mem functions */ +extern void * memcpy __P ((void*, __const void*, size_t)); +extern void * memccpy __P ((void*, void*, int, size_t)); +extern void * memchr __P ((__const void*, __const int, size_t)); +extern void * memset __P ((void*, int, size_t)); +extern int memcmp __P ((__const void*, __const void*, size_t)); + +extern void * memmove __P ((void*, void*, size_t)); + +/* Minimal (very!) locale support */ +#define strcoll strcmp +#define strxfrm strncpy + +/* BSDisms */ +#define index strchr +#define rindex strrchr + +/* Other common BSD functions */ +extern int strcasecmp __P ((char*, char*)); +extern int strncasecmp __P ((char*, char*, size_t)); +char *strpbrk __P ((char *, char *)); +char *strsep __P ((char **, char *)); +char *strstr __P ((char *, char *)); +char *strtok __P ((char *, char *)); +size_t strcspn __P ((char *, char *)); +size_t strspn __P ((char *, char *)); + +/* Linux silly hour */ +char *strfry __P ((char *)); + +#endif diff --git a/libc/include/strings.h b/libc/include/strings.h new file mode 100644 index 0000000..3b2f590 --- /dev/null +++ b/libc/include/strings.h @@ -0,0 +1 @@ +#include <string.h> diff --git a/libc/include/sys/cdefs.h b/libc/include/sys/cdefs.h new file mode 100644 index 0000000..0afc883 --- /dev/null +++ b/libc/include/sys/cdefs.h @@ -0,0 +1,36 @@ + +#ifndef __SYS_CDEFS_H +#define __SYS_CDEFS_H +#include <features.h> + +#if defined (__STDC__) && __STDC__ + +#define __CONCAT(x,y) x ## y +#define __STRING(x) #x + +/* This is not a typedef so `const __ptr_t' does the right thing. */ +#define __ptr_t void * +typedef long double __long_double_t; + +#else + +#define __CONCAT(x,y) x/**/y +#define __STRING(x) "x" + +#define __ptr_t char * + +#ifndef __HAS_NO_FLOATS__ +typedef double __long_double_t; +#endif + +#endif + +/* No C++ */ +#define __BEGIN_DECLS +#define __END_DECLS + +/* GNUish things */ +#define __CONSTVALUE +#define __CONSTVALUE2 + +#endif diff --git a/libc/include/sys/errno.h b/libc/include/sys/errno.h new file mode 100644 index 0000000..339f4fc --- /dev/null +++ b/libc/include/sys/errno.h @@ -0,0 +1 @@ +#include <errno.h> diff --git a/libc/include/sys/fcntl.h b/libc/include/sys/fcntl.h new file mode 100644 index 0000000..cd30455 --- /dev/null +++ b/libc/include/sys/fcntl.h @@ -0,0 +1 @@ +#include <fcntl.h> diff --git a/libc/include/sys/file.h b/libc/include/sys/file.h new file mode 100644 index 0000000..2401b15 --- /dev/null +++ b/libc/include/sys/file.h @@ -0,0 +1,35 @@ +#ifndef _SYS_FILE_H +#define _SYS_FILE_H + +#include <features.h> +#include <fcntl.h> + +#ifndef L_SET + +#define L_SET 0 /* absolute offset */ +#define L_INCR 1 /* relative to current offset */ +#define L_XTND 2 /* relative to end of file */ + +#endif + +#ifndef LOCK_SH + +/* Operations for the `flock' call. */ +#define LOCK_SH 1 /* Shared lock. */ +#define LOCK_EX 2 /* Exclusive lock. */ +#define LOCK_UN 8 /* Unlock. */ + +/* Can be OR'd in to one of the above. */ +#define LOCK_NB 4 /* Don't block when locking. */ + +#endif + +__BEGIN_DECLS + +/* Apply or remove an advisory lock, according to OPERATION, + on the file FD refers to. */ +extern int flock __P ((int __fd, int __operation)); + +__END_DECLS + +#endif diff --git a/libc/include/sys/ioctl.h b/libc/include/sys/ioctl.h new file mode 100644 index 0000000..55e5882 --- /dev/null +++ b/libc/include/sys/ioctl.h @@ -0,0 +1,9 @@ + +#ifndef _SYS_IOCTL_H +#define _SYS_IOCTL_H +#include <features.h> +#include <linuxmt/ioctl.h> + +extern int ioctl __P((int __fildes, int __cmd, ...)); + +#endif diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/libc/include/sys/mman.h diff --git a/libc/include/sys/param.h b/libc/include/sys/param.h new file mode 100644 index 0000000..1a31d1f --- /dev/null +++ b/libc/include/sys/param.h @@ -0,0 +1,18 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#ifndef _PARAM_H +#define _PARAM_H + +#include <limits.h> + +#ifndef NR_OPEN +#define NR_OPEN 32 +#endif +#ifndef NR_FILE +#define NR_FILE 32 +#endif + +#endif diff --git a/libc/include/sys/resource.h b/libc/include/sys/resource.h new file mode 100644 index 0000000..19ed06f --- /dev/null +++ b/libc/include/sys/resource.h @@ -0,0 +1,73 @@ +/* + * Resource control/accounting header file for linux-86 + */ + +#ifndef _SYS_RESOURCE_H +#define _SYS_RESOURCE_H + +#include <features.h> +#include <sys/time.h> +#include <limits.h> + +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN (-1) +#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */ + +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; /* maximum resident set size */ + long ru_ixrss; /* integral shared memory size */ + long ru_idrss; /* integral unshared data size */ + long ru_isrss; /* integral unshared stack size */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +}; + +#define RLIM_INFINITY ((long)(~0UL>>1)) + +struct rlimit { + long rlim_cur; + long rlim_max; +}; + +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +#define PRIO_PROCESS 0 +#define PRIO_PGRP 1 +#define PRIO_USER 2 + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ +#define RLIMIT_NPROC 6 /* max number of processes */ +#define RLIMIT_NOFILE 7 /* max number of open files */ +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ + +#define RLIM_NLIMITS 9 + +extern int getrlimit __P ((int __resource, + struct rlimit *__rlp)); +extern int setrlimit __P ((int __resource, + __const struct rlimit *__rlp)); + +extern int getpriority __P((int __which, int __who)); +extern int setpriority __P((int __which, int __who, + int __prio)); + +extern int __getrusage __P ((int __who, struct rusage *__rusage)); +extern int getrusage __P ((int __who, struct rusage *__rusage)); + +#endif /* _SYS_RESOURCE_H */ diff --git a/libc/include/sys/signal.h b/libc/include/sys/signal.h new file mode 100644 index 0000000..2e602da --- /dev/null +++ b/libc/include/sys/signal.h @@ -0,0 +1 @@ +#include <signal.h> diff --git a/libc/include/sys/stat.h b/libc/include/sys/stat.h new file mode 100644 index 0000000..d21f986 --- /dev/null +++ b/libc/include/sys/stat.h @@ -0,0 +1,64 @@ +#ifndef _SYS_STAT_H +#define _SYS_STAT_H + +#include <linuxmt/stat.h> +#include <sys/types.h> +#include <features.h> + +#ifdef __AS386_32__ +/* This is for Linux-386, ho hum, I wish BCC could compile the proper one */ +#define mknod __dv32_mknod +#define stat __dv32_stat +#define lstat __dv32_lstat +#define fstat __dv32_fstat + +struct stat { + dev_t st_dev; + unsigned short __pad1; + ino_t st_ino; + umode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + unsigned short __pad2; + off_t st_size; + unsigned long st_blksize; + unsigned long st_blocks; + time_t st_atime; + unsigned long __unused1; + time_t st_mtime; + unsigned long __unused2; + time_t st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +#else + +struct stat +{ + dev_t st_dev; + ino_t st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + dev_t st_rdev; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; +#endif + +int stat __P((__const char * __path, struct stat * __statbuf)); +int lstat __P((__const char * __path, struct stat * __statbuf)); +int fstat __P((int __fd, struct stat * __statbuf)); + +/* hysterical raisins */ +#define S_IREAD S_IRUSR /* read permission, owner */ +#define S_IWRITE S_IWUSR /* write permission, owner */ +#define S_IEXEC S_IXUSR /* execute/search permission, owner */ +#endif diff --git a/libc/include/sys/time.h b/libc/include/sys/time.h new file mode 100644 index 0000000..91fd187 --- /dev/null +++ b/libc/include/sys/time.h @@ -0,0 +1 @@ +#include <time.h> diff --git a/libc/include/sys/times.h b/libc/include/sys/times.h new file mode 100644 index 0000000..b6defa8 --- /dev/null +++ b/libc/include/sys/times.h @@ -0,0 +1,21 @@ +#ifndef _SYS_TIMES_H +#define _SYS_TIMES_H + +#include <features.h> +#include <sys/types.h> +#include <time.h> + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +__BEGIN_DECLS + +extern clock_t times __P ((struct tms * __tp)); + +__END_DECLS + +#endif diff --git a/libc/include/sys/types.h b/libc/include/sys/types.h new file mode 100644 index 0000000..7b7de09 --- /dev/null +++ b/libc/include/sys/types.h @@ -0,0 +1,2 @@ +#include <stddef.h> +#include <linuxmt/types.h> diff --git a/libc/include/sys/utsname.h b/libc/include/sys/utsname.h new file mode 100644 index 0000000..0cbc37f --- /dev/null +++ b/libc/include/sys/utsname.h @@ -0,0 +1,18 @@ +#ifndef __SYS_UTSNAME_H +#define __SYS_UTSNAME_H + +#include <features.h> +#include <sys/param.h> + +struct utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +extern int uname __P ((struct utsname * __utsbuf)); + +#endif diff --git a/libc/include/sys/vm86.h b/libc/include/sys/vm86.h new file mode 100644 index 0000000..851814e --- /dev/null +++ b/libc/include/sys/vm86.h @@ -0,0 +1,125 @@ +#if !__AS386_16__ + +#ifndef _SYS_VM86_H +#define _SYS_VM86_H + +#include <features.h> +#ifndef _LINUX_VM86_H +#define _LINUX_VM86_H + +/* + * I'm guessing at the VIF/VIP flag usage, but hope that this is how + * the Pentium uses them. Linux will return from vm86 mode when both + * VIF and VIP is set. + * + * On a Pentium, we could probably optimize the virtual flags directly + * in the eflags register instead of doing it "by hand" in vflags... + * + * Linus + */ + +#define TF_MASK 0x00000100 +#define IF_MASK 0x00000200 +#define IOPL_MASK 0x00003000 +#define NT_MASK 0x00004000 +#define VM_MASK 0x00020000 +#define AC_MASK 0x00040000 +#define VIF_MASK 0x00080000 /* virtual interrupt flag */ +#define VIP_MASK 0x00100000 /* virtual interrupt pending */ +#define ID_MASK 0x00200000 + +#define BIOSSEG 0x0f000 + +#define CPU_086 0 +#define CPU_186 1 +#define CPU_286 2 +#define CPU_386 3 +#define CPU_486 4 +#define CPU_586 5 + +/* + * Return values for the 'vm86()' system call + */ +#define VM86_TYPE(retval) ((retval) & 0xff) +#define VM86_ARG(retval) ((retval) >> 8) + +#define VM86_SIGNAL 0 /* return due to signal */ +#define VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */ +#define VM86_INTx 2 /* int3/int x instruction (ARG = x) */ +#define VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */ + +/* + * This is the stack-layout when we have done a "SAVE_ALL" from vm86 + * mode - the main change is that the old segment descriptors aren't + * useful any more and are forced to be zero by the kernel (and the + * hardware when a trap occurs), and the real segment descriptors are + * at the end of the structure. Look at ptrace.h to see the "normal" + * setup. + */ + +struct vm86_regs { +/* + * normal regs, with special meaning for the segment descriptors.. + */ + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + long __null_ds; + long __null_es; + long __null_fs; + long __null_gs; + long orig_eax; + long eip; + unsigned short cs, __csh; + long eflags; + long esp; + unsigned short ss, __ssh; +/* + * these are specific to v86 mode: + */ + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned short fs, __fsh; + unsigned short gs, __gsh; +}; + +struct revectored_struct { + unsigned long __map[8]; /* 256 bits */ +}; + +struct vm86_struct { + struct vm86_regs regs; + unsigned long flags; + unsigned long screen_bitmap; + unsigned long cpu_type; + struct revectored_struct int_revectored; + struct revectored_struct int21_revectored; +}; + +/* + * flags masks + */ +#define VM86_SCREEN_BITMAP 0x0001 + +#ifdef __KERNEL__ + +void handle_vm86_fault(struct vm86_regs *, long); +void handle_vm86_debug(struct vm86_regs *, long); + +#endif + +#endif + +__BEGIN_DECLS + +extern vm86(struct vm86_struct * __info); + +__END_DECLS + +#endif /*_SYS_VM86_H */ + +#endif diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h new file mode 100644 index 0000000..566aac7 --- /dev/null +++ b/libc/include/sys/wait.h @@ -0,0 +1,77 @@ + +#ifndef _SYS_WAIT_H +#define _SYS_WAIT_H + +#include <features.h> + +/* Bits in the third argument to `waitpid'. */ +#define WNOHANG 1 /* Don't block waiting. */ +#define WUNTRACED 2 /* Report status of stopped children. */ + +/* Everything extant so far uses these same bits. */ +/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */ +#define WEXITSTATUS(status) (((status) & 0xff00) >> 8) + +/* If WIFSIGNALED(STATUS), the terminating signal. */ +#define WTERMSIG(status) ((status) & 0x7f) + +/* If WIFSTOPPED(STATUS), the signal that stopped the child. */ +#define WSTOPSIG(status) WEXITSTATUS(status) + +/* Nonzero if STATUS indicates normal termination. */ +#define WIFEXITED(status) (((status) & 0xff) == 0) + +/* Nonzero if STATUS indicates termination by a signal. */ +#define WIFSIGNALED(status) (((unsigned int)((status)-1) & 0xFFFF) < 0xFF) + +/* Nonzero if STATUS indicates the child is stopped. */ +#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f) + +/* Nonzero if STATUS indicates the child dumped core. */ +#define WCOREDUMP(status) ((status) & 0200) + +/* Macros for constructing status values. */ +#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig)) +#define W_STOPCODE(sig) ((sig) << 8 | 0x7f) + +/* Wait for a child to die. When one does, put its status in *STAT_LOC + and return its process ID. For errors, return (pid_t) -1. */ +extern pid_t wait __P ((__WAIT_STATUS __stat_loc)); + +/* Special values for the PID argument to `waitpid' and `wait4'. */ +#define WAIT_ANY (-1) /* Any process. */ +#define WAIT_MYPGRP 0 /* Any process in my process group. */ + +/* Wait for a child matching PID to die. + If PID is greater than 0, match any process whose process ID is PID. + If PID is (pid_t) -1, match any process. + If PID is (pid_t) 0, match any process with the + same process group as the current process. + If PID is less than -1, match any process whose + process group is the absolute value of PID. + If the WNOHANG bit is set in OPTIONS, and that child + is not already dead, return (pid_t) 0. If successful, + return PID and store the dead child's status in STAT_LOC. + Return (pid_t) -1 for errors. If the WUNTRACED bit is + set in OPTIONS, return status for stopped children; otherwise don't. */ + +extern pid_t waitpid __P ((pid_t __pid, int *__stat_loc, + int __options)); + +/* This being here makes the prototypes valid whether or not + we have already included <sys/resource.h> to define `struct rusage'. */ +struct rusage; + +/* Wait for a child to exit. When one does, put its status in *STAT_LOC and + return its process ID. For errors return (pid_t) -1. If USAGE is not + nil, store information about the child's resource usage there. If the + WUNTRACED bit is set in OPTIONS, return status for stopped children; + otherwise don't. */ +extern pid_t wait3 __P ((__WAIT_STATUS __stat_loc, + int __options, struct rusage * __usage)); + +/* PID is like waitpid. Other args are like wait3. */ +extern pid_t wait4 __P ((pid_t __pid, __WAIT_STATUS __stat_loc, + int __options, struct rusage *__usage)); + +#endif /* sys/wait.h */ diff --git a/libc/include/termcap.h b/libc/include/termcap.h new file mode 100644 index 0000000..a7ae37b --- /dev/null +++ b/libc/include/termcap.h @@ -0,0 +1,21 @@ + +#ifndef _TERMCAP_H +#define _TERMCAP_H + +#include <features.h> +#include <sys/types.h> + +extern char PC; +extern char *UP; +extern char *BC; +extern int ospeed; + +extern int tgetent __P((char *, const char *)); +extern int tgetflag __P((const char *)); +extern int tgetnum __P((const char *)); +extern char *tgetstr __P((const char *, char **)); + +extern int tputs __P((const char *, int, int (*)(int))); +extern char *tgoto __P((const char *, int, int)); + +#endif /* _TERMCAP_H */ diff --git a/libc/include/termio.h b/libc/include/termio.h new file mode 100644 index 0000000..9e26956 --- /dev/null +++ b/libc/include/termio.h @@ -0,0 +1 @@ +#include <termios.h> diff --git a/libc/include/termios.h b/libc/include/termios.h new file mode 100644 index 0000000..604e654 --- /dev/null +++ b/libc/include/termios.h @@ -0,0 +1,24 @@ +#ifndef __TERMIOS_H +#define __TERMIOS_H + +#include <features.h> +#include <sys/types.h> +#include <linuxmt/termios.h> + +extern speed_t cfgetispeed __P ((struct termios *__termios_p)); +extern speed_t cfgetospeed __P ((struct termios *__termios_p)); +extern int cfsetispeed __P ((struct termios *__termios_p, speed_t __speed)); +extern int cfsetospeed __P ((struct termios *__termios_p, speed_t __speed)); + +extern void cfmakeraw __P ((struct termios *__t)); + +extern int tcsetattr __P ((int __fd, int __opt, struct termios *__termios_p)); +extern int tcgetattr __P ((int __fildes, struct termios *__termios_p)); +extern int tcdrain __P ((int __fildes)); +extern int tcflow __P ((int __fildes, int __action)); +extern int tcflush __P ((int __fildes, int __queue_selector)); +extern int tcsendbreak __P ((int __fildes, int __duration)); +extern pid_t tcgetpgrp __P ((int __fildes)); +extern int tcsetpgrp __P ((int __fildes, pid_t __pgrp_id)); + +#endif diff --git a/libc/include/time.h b/libc/include/time.h new file mode 100644 index 0000000..30ae4bc --- /dev/null +++ b/libc/include/time.h @@ -0,0 +1,68 @@ +#ifndef __TIME_H +#define __TIME_H + +#include <features.h> +#include <sys/types.h> +#include <stddef.h> + +#ifndef _CLOCK_T +#define _CLOCK_T +typedef long clock_t; +#endif + +#define CLOCKS_PER_SEC 100 +#define CLK_TCK 100 /* That must be the same as HZ ???? */ + +struct timeval { + long tv_sec; + long tv_usec; +}; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +#define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +extern char *tzname[2]; +extern int daylight; +extern long int timezone; + +__BEGIN_DECLS + +extern int stime __P ((time_t* __tptr)); + +extern clock_t clock __P ((void)); +extern time_t time __P ((time_t * __tp)); +#ifndef __HAS_NO_FLOATS__ +extern __CONSTVALUE double difftime __P ((time_t __time2, + time_t __time1)) __CONSTVALUE2; +#endif +extern time_t mktime __P ((struct tm * __tp)); + +extern char * asctime __P ((__const struct tm * __tp)); +extern char * ctime __P ((__const time_t * __tp)); +extern size_t strftime __P ((char * __s, size_t __smax, + __const char * __fmt, __const struct tm * __tp)); +extern void tzset __P ((void)); + +extern struct tm* gmtime __P ((__const time_t *__tp)); +extern struct tm* localtime __P ((__const time_t * __tp)); + +__END_DECLS + +#endif diff --git a/libc/include/unistd.h b/libc/include/unistd.h new file mode 100644 index 0000000..c96f710 --- /dev/null +++ b/libc/include/unistd.h @@ -0,0 +1,37 @@ +/* unistd.h <ndf@linux.mit.edu> */ +#include <features.h> +#include <sys/types.h> + +#ifndef __UNISTD_H +#define __UNISTD_H + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +extern int close __P ((int)); +extern size_t read __P ((int __fd, char * __buf, size_t __nbytes)); +extern size_t write __P ((int __fd, __const char * __buf, size_t __n)); +extern off_t lseek __P ((int __fd, off_t __n, int __whence)); +extern int pipe __P ((int __pipedes[2])); +extern unsigned int alarm __P ((unsigned int __seconds)); +extern unsigned int sleep __P ((unsigned int __seconds)); +extern int pause __P ((void)); +extern char* crypt __P((__const char *__key, __const char *__salt)); + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifndef R_OK +#define R_OK 4 /* Test for read permission. */ +#define W_OK 2 /* Test for write permission. */ +#define X_OK 1 /* Test for execute permission. */ +#define F_OK 0 /* Test for existence. */ +#endif + +#endif /* __UNISTD_H */ + + diff --git a/libc/include/utime.h b/libc/include/utime.h new file mode 100644 index 0000000..7f82b9f --- /dev/null +++ b/libc/include/utime.h @@ -0,0 +1,15 @@ +#ifndef __UTIME_H +#define __UTIME_H + +#include <features.h> +#include <sys/types.h> + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +extern int utime __P ((char *__filename, struct utimbuf *__utimebuf)); + +#endif + diff --git a/libc/include/utmp.h b/libc/include/utmp.h new file mode 100644 index 0000000..9fe0e87 --- /dev/null +++ b/libc/include/utmp.h @@ -0,0 +1,52 @@ +/* utmp.h */ + +#ifndef __UTMP_H +#define __UTMP_H + +#include <features.h> +#include <sys/types.h> +#include <paths.h> +#include <time.h> + +#define UT_UNKNOWN 0 +#define UT_LINESIZE 12 +#define UT_NAMESIZE 8 +#define UT_HOSTSIZE 16 + +#define RUN_LVL 1 +#define BOOT_TIME 2 +#define NEW_TIME 3 +#define OLD_TIME 4 + +#define INIT_PROCESS 5 +#define LOGIN_PROCESS 6 +#define USER_PROCESS 7 +#define DEAD_PROCESS 8 + +struct utmp +{ + short ut_type; /* type of login */ + pid_t ut_pid; /* pid of login-process */ + char ut_line[UT_LINESIZE]; /* devicename of tty -"/dev/", null-term */ + char ut_id[2]; /* abbrev. ttyname, as 01, s1 etc. */ + time_t ut_time; /* login time */ + char ut_user[UT_NAMESIZE]; /* username, not null-term */ + char ut_host[UT_HOSTSIZE]; /* hostname for remote login... */ + long ut_addr; /* IP addr of remote host */ + +}; + +extern void setutent __P ((void)); +extern void utmpname __P ((__const char *)); +extern struct utmp * getutent __P ((void)); +extern struct utmp * getutid __P ((struct utmp *)); +extern struct utmp * getutline __P ((struct utmp *)); +extern struct utmp * pututline __P ((struct utmp *)); +extern void endutent __P ((void)); + +#ifdef __LIBC__ +struct utmp * __getutent __P ((int)); +#endif + +#endif /* __UTMP_H */ + diff --git a/libc/include/varargs.h b/libc/include/varargs.h new file mode 100644 index 0000000..b5c647f --- /dev/null +++ b/libc/include/varargs.h @@ -0,0 +1,12 @@ + +#ifndef __VARARGS_H +#define __VARARGS_H + +typedef char *va_list; + +#define va_dcl va_list va_alist; +#define va_start(ap) ap = (va_list)&va_alist +#define va_arg(ap,t) ((t *)(ap += sizeof(t)))[-1] +#define va_end(ap) ap = NULL + +#endif diff --git a/libc/kinclude/Config b/libc/kinclude/Config new file mode 100644 index 0000000..f3d064f --- /dev/null +++ b/libc/kinclude/Config @@ -0,0 +1 @@ +kinc: The kernel include files diff --git a/libc/kinclude/Makefile b/libc/kinclude/Makefile new file mode 100644 index 0000000..8982f57 --- /dev/null +++ b/libc/kinclude/Makefile @@ -0,0 +1,27 @@ +# 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 + @touch Used + +# This is for use once linuxmt's syscall interface really gets working. +# beware the arch directory must be removed when you do this. +real_transfer: + -@rm -f ../include/linuxmt + cd ../include ; ln -s ../../linuxmt/include/linuxmt . + +clean: + -@rm -f ../include/linuxmt + -@rm -f Used diff --git a/libc/kinclude/arch/errno.h b/libc/kinclude/arch/errno.h new file mode 100644 index 0000000..ee3fcab --- /dev/null +++ b/libc/kinclude/arch/errno.h @@ -0,0 +1,127 @@ +#ifndef _I86_ERRNO_H +#define _I86_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ +#define EDEADLOCK 58 /* File locking deadlock error */ +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#endif diff --git a/libc/kinclude/arch/ioctl.h b/libc/kinclude/arch/ioctl.h new file mode 100644 index 0000000..55b276b --- /dev/null +++ b/libc/kinclude/arch/ioctl.h @@ -0,0 +1,9 @@ +/* + * Nothing here yet. + */ + +#ifndef _ASMI86_IOCTL_H +#define _ASMI86_IOCTL_H + + +#endif /* _ASMI86_IOCTL_H */ diff --git a/libc/kinclude/arch/types.h b/libc/kinclude/arch/types.h new file mode 100644 index 0000000..00afeed --- /dev/null +++ b/libc/kinclude/arch/types.h @@ -0,0 +1,48 @@ +/* arch/i86/include/asm/types.h - Basic Linux/MT data types. */ + +#ifndef __LINUXMT_8086_TYPES +#define __LINUXMT_8086_TYPES + +/* First we define all of the __u and __s types...*/ + +typedef unsigned char __u8; +typedef unsigned char * __pu8; +typedef char __s8; +typedef char * __ps8; + +typedef unsigned short __u16; +typedef unsigned short * __pu16; +typedef short __s16; +typedef short * __ps16; + +typedef unsigned long __u32; +typedef unsigned long * __pu32; +typedef long __s32; +typedef long * __ps32; + +/* __uint == 16bit here */ + +typedef unsigned int __uint; +typedef int __sint; +typedef unsigned int * __puint; +typedef int * __psint; + +/* Then we define registers, etc... */ + +struct _registers { + __u16 ksp, sp, ss, ax, bx, cx, dx, di, si, ds, es, bp, ip, cs, flags; +}; + +typedef struct _registers __registers; +typedef struct _registers * __pregisters; + +typedef __u32 __pptr; + +struct _mminit { + __u16 cs, endcs, ds, endds, ss, endss, lowss; +}; + +typedef struct _mminit __arch_mminit; +typedef struct _mminit * __parch_mminit; + +#endif diff --git a/libc/kinclude/linuxmt/errno.h b/libc/kinclude/linuxmt/errno.h new file mode 100644 index 0000000..b4c07a3 --- /dev/null +++ b/libc/kinclude/linuxmt/errno.h @@ -0,0 +1 @@ +#include "../arch/errno.h" diff --git a/libc/kinclude/linuxmt/fcntl.h b/libc/kinclude/linuxmt/fcntl.h new file mode 100644 index 0000000..d9188a1 --- /dev/null +++ b/libc/kinclude/linuxmt/fcntl.h @@ -0,0 +1,70 @@ +#ifndef __LINUXMT_FCNTL_H +#define __LINUXMT_FCNTL_H + +/* + * Definitions taken from the i386 Linux kernel. + */ + +/* open/fcntl */ + +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#if 0 +#define O_SYNC 010000 /* Not supported */ +#define FASYNC 020000 /* Not supported */ +#endif + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* for old implementation of bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#ifdef __KERNEL__ +#define F_POSIX 1 +#define F_FLOCK 2 +#endif /* __KERNEL__ */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#endif diff --git a/libc/kinclude/linuxmt/ioctl.h b/libc/kinclude/linuxmt/ioctl.h new file mode 100644 index 0000000..20f5ac6 --- /dev/null +++ b/libc/kinclude/linuxmt/ioctl.h @@ -0,0 +1 @@ +#include "../arch/ioctl.h" diff --git a/libc/kinclude/linuxmt/stat.h b/libc/kinclude/linuxmt/stat.h new file mode 100644 index 0000000..9fbd191 --- /dev/null +++ b/libc/kinclude/linuxmt/stat.h @@ -0,0 +1,57 @@ +#ifndef __LINUXMT_STAT_H +#define __LINUXMT_STAT_H + +#ifdef __KERNEL__ + +#include "../arch/stat.h" + +#endif + +#define S_IFMT 00170000 +#ifdef __LINUXMT_NETWORK__ +#define S_IFSOCK 0140000 +#endif +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#ifdef __LINUXMT_NETWORK__ +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#endif + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#ifdef __KERNEL__ +#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) +#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) +#endif + +#endif diff --git a/libc/kinclude/linuxmt/termios.h b/libc/kinclude/linuxmt/termios.h new file mode 100644 index 0000000..2aff58a --- /dev/null +++ b/libc/kinclude/linuxmt/termios.h @@ -0,0 +1,260 @@ +#ifndef __LINUXMT_TERMIOS_H +#define __LINUXMT_TERMIOS_H +#include <linuxmt/types.h> + +/* This is just a magic number to make these relatively unique ('T') */ +#define __TERMIOS_MAJ ('T'<<8) + +#define TCGETS (__TERMIOS_MAJ+0x01) +#define TCSETS (__TERMIOS_MAJ+0x02) +#define TCSETSW (__TERMIOS_MAJ+0x03) +#define TCSETSF (__TERMIOS_MAJ+0x04) +#define TCGETA (__TERMIOS_MAJ+0x05) +#define TCSETA (__TERMIOS_MAJ+0x06) +#define TCSETAW (__TERMIOS_MAJ+0x07) +#define TCSETAF (__TERMIOS_MAJ+0x08) +#define TCSBRK (__TERMIOS_MAJ+0x09) +#define TCXONC (__TERMIOS_MAJ+0x0A) +#define TCFLSH (__TERMIOS_MAJ+0x0B) +#define TIOCEXCL (__TERMIOS_MAJ+0x0C) +#define TIOCNXCL (__TERMIOS_MAJ+0x0D) +#define TIOCSCTTY (__TERMIOS_MAJ+0x0E) +#define TIOCGPGRP (__TERMIOS_MAJ+0x0F) +#define TIOCSPGRP (__TERMIOS_MAJ+0x10) +#define TIOCOUTQ (__TERMIOS_MAJ+0x11) +#define TIOCSTI (__TERMIOS_MAJ+0x12) +#define TIOCGWINSZ (__TERMIOS_MAJ+0x13) +#define TIOCSWINSZ (__TERMIOS_MAJ+0x14) +#define TIOCMGET (__TERMIOS_MAJ+0x15) +#define TIOCMBIS (__TERMIOS_MAJ+0x16) +#define TIOCMBIC (__TERMIOS_MAJ+0x17) +#define TIOCMSET (__TERMIOS_MAJ+0x18) +#define TIOCGSOFTCAR (__TERMIOS_MAJ+0x19) +#define TIOCSSOFTCAR (__TERMIOS_MAJ+0x1A) +#define FIONREAD (__TERMIOS_MAJ+0x1B) +#define TIOCINQ FIONREAD +#define TIOCLINUX (__TERMIOS_MAJ+0x1C) +#define TIOCCONS (__TERMIOS_MAJ+0x1D) +#define TIOCGSERIAL (__TERMIOS_MAJ+0x1E) +#define TIOCSSERIAL (__TERMIOS_MAJ+0x1F) +#define TIOCPKT (__TERMIOS_MAJ+0x20) +#define FIONBIO (__TERMIOS_MAJ+0x21) +#define TIOCNOTTY (__TERMIOS_MAJ+0x22) +#define TIOCSETD (__TERMIOS_MAJ+0x23) +#define TIOCGETD (__TERMIOS_MAJ+0x24) +#define TCSBRKP (__TERMIOS_MAJ+0x25) /* Needed for POSIX tcsendbreak */ +#define TIOCTTYGSTRUCT (__TERMIOS_MAJ+0x26) /* For debugging only */ +#define FIONCLEX (__TERMIOS_MAJ+0x50) /* these numbers need to be adjusted. */ +#define FIOCLEX (__TERMIOS_MAJ+0x51) +#define FIOASYNC (__TERMIOS_MAJ+0x52) +#define TIOCSERCONFIG (__TERMIOS_MAJ+0x53) +#define TIOCSERGWILD (__TERMIOS_MAJ+0x54) +#define TIOCSERSWILD (__TERMIOS_MAJ+0x55) +#define TIOCGLCKTRMIOS (__TERMIOS_MAJ+0x56) +#define TIOCSLCKTRMIOS (__TERMIOS_MAJ+0x57) +#define TIOCSERGSTRUCT (__TERMIOS_MAJ+0x58) /* For debugging only */ +#define TIOCSERGETLSR (__TERMIOS_MAJ+0x59) /* Get line status register */ +#define TIOCSERGETMULTI (__TERMIOS_MAJ+0x5A) /* Get multiport config */ +#define TIOCSERSETMULTI (__TERMIOS_MAJ+0x5B) /* Set multiport config */ + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 + +#define _POSIX_VDISABLE '\0' + +#endif /* __LINUXMT_TERMIOS_H */ diff --git a/libc/kinclude/linuxmt/types.h b/libc/kinclude/linuxmt/types.h new file mode 100644 index 0000000..8e5236a --- /dev/null +++ b/libc/kinclude/linuxmt/types.h @@ -0,0 +1,34 @@ +#ifndef __LINUXMT_TYPES_H +#define __LINUXMT_TYPES_H + +#include "../arch/types.h" + +/* Throw away _FUNCTION parameters - the syntax is ripped off of Minix's + _PROTOTYPE. Considering Borland did the same thing to MFC on a bigger + scale, I don't think PH will mind :) */ + +/* Yes, this should be in arch/types.h too */ + +#define _FUNCTION(function, params) function() +#define _VFUNCTION(functiom, params) (*function) () + +typedef __u32 off_t; +typedef __u16 pid_t; +typedef __u16 uid_t; +typedef __u16 gid_t; +typedef __u32 time_t; +typedef __u16 umode_t; +typedef __u16 nlink_t; +typedef __u16 mode_t; +typedef __u32 loff_t; +typedef __u32 speed_t; + +typedef __u16 dev_t; +typedef __uint ino_t; +typedef __u32 tcflag_t; +typedef __u8 cc_t; + +typedef int ptrdiff_t; + +#endif + diff --git a/libc/malloc1/Config b/libc/malloc1/Config new file mode 100644 index 0000000..4404398 --- /dev/null +++ b/libc/malloc1/Config @@ -0,0 +1 @@ +malloc: Robert's malloc routines diff --git a/libc/malloc1/Makefile b/libc/malloc1/Makefile new file mode 100644 index 0000000..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..86ffd42 --- /dev/null +++ b/libc/malloc1/malloc.c @@ -0,0 +1,546 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* + * This is a combined alloca/malloc package. It uses a classic algorithm + * and so may be seen to be quite slow compared to more modern routines + * with 'nasty' distributions. + */ + +#include <malloc.h> +#include <errno.h> + +#define MCHUNK 2048 /* Allocation unit in 'mem' elements */ +#define XLAZY_FREE /* If set frees can be infinitly defered */ +#define XMINALLOC 32 /* Smallest chunk to alloc in 'mem's */ +#define XVERBOSE /* Lots of noise, debuging ? */ + +#undef malloc +#define MAX_INT ((int)(((unsigned)-1)>>1)) + +#ifdef VERBOSE +#define noise __noise +#else +#define noise(y,x) +#endif + +typedef union mem_cell +{ + union mem_cell *next; /* A pointer to the next mem */ + unsigned int size; /* An int >= sizeof pointer */ + char *depth; /* For the alloca hack */ +} +mem; + +#define m_size(p) ((p) [0].size) /* For malloc */ +#define m_next(p) ((p) [1].next) /* For malloc and alloca */ +#define m_deep(p) ((p) [0].depth) /* For alloca */ + +extern void *__mini_malloc __P ((size_t)); +extern void *(*__alloca_alloc) __P ((size_t)); +extern mem *__freed_list; + +#ifdef L_free +/* Start the alloca with just the dumb version of malloc */ + +void *(*__alloca_alloc) __P ((size_t)) = __mini_malloc; +mem *__freed_list = 0; + +#ifdef VERBOSE +/* NB: Careful here, stdio may use malloc - so we can't */ +static +phex(val) +{ + static char hex[] = "0123456789ABCDEF"; + int i; + for (i = sizeof(int)*8-4; i >= 0; i -= 4) + write(2, hex + ((val >> i) & 0xF), 1); +} + +noise(y, x) +char *y; +mem *x; +{ + write(2, "Malloc ", 7); + phex(x); + write(2, " sz ", 4); + if(x) phex(m_size(x)); else phex(0); + write(2, " nxt ", 5); + if(x) phex(m_next(x)); else phex(0); + write(2, " is ", 4); + write(2, y, strlen(y)); + write(2, "\n", 1); +} +#endif + +#endif + +#ifdef L_alloca +static mem *alloca_stack = 0; + +void * +alloca(size) +size_t size; +{ + auto char probe; /* Probes stack depth: */ + register mem *hp; + + /* + * Reclaim garbage, defined as all alloca'd storage that was allocated + * from deeper in the stack than currently. + */ + + for (hp = alloca_stack; hp != 0;) + if (m_deep(hp) < &probe) + { + register mem *np = m_next(hp); + free((void *) hp); /* Collect garbage. */ + hp = np; /* -> next header. */ + } + else + break; /* Rest are not deeper. */ + + alloca_stack = hp; /* -> last valid storage. */ + if (size == 0) + return 0; /* No allocation required. */ + + hp = (mem *) (*__alloca_alloc) (sizeof(mem)*2 + size); + if (hp == 0) + return hp; + + m_next(hp) = alloca_stack; + m_deep(hp) = &probe; + alloca_stack = hp; + + /* User storage begins just after header. */ + return (void *) (hp + 2); +} +#endif /* L_alloca */ + +#ifdef L_free +void +free(ptr) +void *ptr; +{ + register mem *top; + register mem *chk = (mem *) ptr; + + if (chk == 0) + return; /* free(NULL) - be nice */ + chk--; + + try_this:; + top = (mem *) sbrk(0); + if (chk + m_size(chk) == top) + { + noise("FREE brk", chk); + brk(top-m_size(chk)); + /* + * Adding this code allow free to release blocks in any order; they + * can still only be allocated from the top of the heap tho. + */ +#ifdef __MINI_MALLOC__ + if (__alloca_alloc == __mini_malloc && __freed_list) + { + mem *prev, *curr; + chk = __freed_list; + __freed_list = m_next(__freed_list); + goto try_this; + } +#endif + } + else + { /* Nope, not sure where this goes, leave + * it for malloc to deal with */ +#ifdef __MINI_MALLOC__ + if( __freed_list || chk > __freed_list ) + { m_next(chk) = __freed_list; __freed_list = chk; } + else + { + register mem *prev; + prev=__freed_list; + for(top=__freed_list; top && top > chk; prev=top, top=m_next(top)) + ; + m_next(chk) = top; + m_next(prev) = chk; + } +#else + m_next(chk) = __freed_list; + __freed_list = chk; +#endif + noise("ADD LIST", chk); + } +} + +void * +__mini_malloc(size) +size_t size; +{ + register mem *ptr; + register unsigned int sz; + + /* First time round this _might_ be odd, But we won't do that! */ + sz = (unsigned int) sbrk(0); + if (sz & (sizeof(mem) - 1)) + sbrk(4 - (sz & (sizeof(mem) - 1))); + + if (size <= 0) + return 0; + /* Minor oops here, sbrk has a signed argument */ + if( size > (((unsigned)-1)>>1)-sizeof(mem)*3 ) + { + errno = ENOMEM; + return 0; + } + + size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */ + size /= sizeof(mem); + + ptr = (mem *) sbrk(size * sizeof(mem)); + if ((int) ptr == -1) + return 0; + + m_size(ptr) = size; + noise("CREATE", ptr); + return ptr + 1; +} +#endif /* L_free */ + +#ifdef L_malloc + +/* + * The chunk_list pointer is either NULL or points to a chunk in a + * circular list of all the free blocks in memory + */ + +#define Static static + +static mem *chunk_list = 0; +Static void __insert_chunk(); +Static mem *__search_chunk(); + +void * +malloc(size) +size_t size; +{ + register mem *ptr = 0; + register unsigned int sz; + + if (size == 0) + return 0; /* ANSI STD */ + + sz = size + sizeof(mem) * 2 - 1; + sz /= sizeof(mem); + +#ifdef MINALLOC + if (sz < MINALLOC) + sz = MINALLOC; +#endif + +#ifdef VERBOSE + { + static mem arr[2]; + m_size(arr) = sz; + noise("WANTED", arr); + } +#endif + + __alloca_alloc = malloc; /* We'll be messing with the heap now TVM */ + +#ifdef LAZY_FREE + ptr = __search_chunk(sz); + if (ptr == 0) + { +#endif + + /* First deal with the freed list */ + if (__freed_list) + { + while (__freed_list) + { + ptr = __freed_list; + __freed_list = m_next(__freed_list); + + if (m_size(ptr) == sz) /* Oh! Well that's lucky ain't it + * :-) */ + { + noise("LUCKY MALLOC", ptr); + return ptr + 1; + } + + __insert_chunk(ptr); + } + ptr = m_next(chunk_list); + if (ptr + m_size(ptr) == (void *) sbrk(0)) + { + /* Time to free for real */ + m_next(chunk_list) = m_next(ptr); + if (ptr == m_next(ptr)) + chunk_list = 0; + free(ptr + 1); + } +#ifdef LAZY_FREE + ptr = __search_chunk(sz); +#endif + } +#ifndef LAZY_FREE + ptr = __search_chunk(sz); +#endif + if (ptr == 0) + { +#ifdef MCHUNK + unsigned int alloc; + alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1); + ptr = __mini_malloc(alloc); + if (ptr) + __insert_chunk(ptr - 1); + else /* Oooo, near end of RAM */ + { + unsigned int needed = alloc; + for(alloc/=2; alloc>256 && needed; ) + { + ptr = __mini_malloc(alloc); + if (ptr) + { + if( alloc > needed ) needed = 0; else needed -= alloc; + __insert_chunk(ptr - 1); + } + else alloc/=2; + } + } + ptr = __search_chunk(sz); + if (ptr == 0) +#endif + { +#ifndef MCHUNK + ptr = __mini_malloc(size); +#endif +#ifdef VERBOSE + if( ptr == 0 ) + noise("MALLOC FAIL", 0); + else + noise("MALLOC NOW", ptr - 1); +#endif + return ptr; + } + } +#ifdef LAZY_FREE + } +#endif + +#ifdef VERBOSE + ptr[1].size = 0x55555555; +#endif + noise("MALLOC RET", ptr); + return ptr + 1; +} + +/* + * This function takes a pointer to a block of memory and inserts it into + * the chain of memory chunks + */ + +Static void +__insert_chunk(mem_chunk) +mem *mem_chunk; +{ + register mem *p1, *p2; + if (chunk_list == 0) /* Simple case first */ + { + m_next(mem_chunk) = chunk_list = mem_chunk; + noise("FIRST CHUNK", mem_chunk); + return; + } + p1 = mem_chunk; + p2 = chunk_list; + + do + { + if (p1 > p2) + { + if (m_next(p2) <= p2) + { /* We're at the top of the chain, p1 is + * higher */ + + if (p2 + m_size(p2) == p1) + { /* Good, stick 'em together */ + noise("INSERT CHUNK", mem_chunk); + m_size(p2) += m_size(p1); + noise("JOIN 1", p2); + } + else + { + m_next(p1) = m_next(p2); + m_next(p2) = p1; + noise("INSERT CHUNK", mem_chunk); + noise("FROM", p2); + } + return; + } + if (m_next(p2) > p1) + { + /* In chain, p1 between p2 and next */ + + m_next(p1) = m_next(p2); + m_next(p2) = p1; + noise("INSERT CHUNK", mem_chunk); + noise("FROM", p2); + + /* Try to join above */ + if (p1 + m_size(p1) == m_next(p1)) + { + m_size(p1) += m_size(m_next(p1)); + m_next(p1) = m_next(m_next(p1)); + noise("JOIN 2", p1); + } + /* Try to join below */ + if (p2 + m_size(p2) == p1) + { + m_size(p2) += m_size(p1); + m_next(p2) = m_next(p1); + noise("JOIN 3", p2); + } + chunk_list = p2; /* Make sure it's valid */ + return; + } + } + else if (p1 < p2) + { + if (m_next(p2) <= p2 && p1 < m_next(p2)) + { + /* At top of chain, next is bottom of chain, p1 is below next */ + + m_next(p1) = m_next(p2); + m_next(p2) = p1; + noise("INSERT CHUNK", mem_chunk); + noise("FROM", p2); + chunk_list = p2; + + if (p1 + m_size(p1) == m_next(p1)) + { + if (p2 == m_next(p1)) + chunk_list = p1; + m_size(p1) += m_size(m_next(p1)); + m_next(p1) = m_next(m_next(p1)); + noise("JOIN 4", p1); + } + return; + } + } + chunk_list = p2; /* Save for search */ + p2 = m_next(p2); + } + while (p2 != chunk_list); + + /* If we get here we have a problem, ignore it, maybe it'll go away */ + noise("DROPPED CHUNK", mem_chunk); +} + +/* + * This function will search for a chunk in memory of at least 'mem_size' + * when found, if the chunk is too big it'll be split, and pointer to the + * chunk returned. If none is found NULL is returned. + */ + +Static mem * +__search_chunk(mem_size) +unsigned int mem_size; +{ + register mem *p1, *p2; + if (chunk_list == 0) /* Simple case first */ + return 0; + + /* Search for a block >= the size we want */ + p1 = m_next(chunk_list); + p2 = chunk_list; + do + { + noise("CHECKED", p1); + if (m_size(p1) >= mem_size) + break; + + p2 = p1; + p1 = m_next(p1); + } + while (p2 != chunk_list); + + /* None found, exit */ + if (m_size(p1) < mem_size) + return 0; + + /* If it's exactly right remove it */ + if (m_size(p1) < mem_size + 2) + { + noise("FOUND RIGHT", p1); + chunk_list = m_next(p2) = m_next(p1); + if (chunk_list == p1) + chunk_list = 0; + return p1; + } + + noise("SPLIT", p1); + /* Otherwise split it */ + m_next(p2) = p1 + mem_size; + chunk_list = p2; + + p2 = m_next(p2); + m_size(p2) = m_size(p1) - mem_size; + m_next(p2) = m_next(p1); + m_size(p1) = mem_size; + if (chunk_list == p1) + chunk_list = p2; +#ifdef VERBOSE + p1[1].size = 0xAAAAAAAA; +#endif + noise("INSERT CHUNK", p2); + noise("FOUND CHUNK", p1); + noise("LIST IS", chunk_list); + return p1; +} + +#endif /* L_malloc */ + +#ifdef L_calloc +void * +calloc(elm, sz) +unsigned int elm, sz; +{ + register unsigned int v; + register void *ptr; + ptr = malloc(v = elm * sz); + if (ptr) + memset(ptr, 0, v); + return ptr; +} +#endif /* L_calloc */ + +#ifdef L_realloc +void * +realloc(ptr, size) +void *ptr; +size_t size; +{ + void *nptr; + unsigned int osize; + if (ptr == 0) + return malloc(size); + + osize = (m_size(((mem *) ptr) - 1) - 1) * sizeof(mem); + if (size <= osize) + { + return ptr; + } + + nptr = malloc(size); + + if (nptr == 0) + return 0; + + memcpy(nptr, ptr, osize); + free(ptr); + + return nptr; +} +#endif /* L_realloc */ diff --git a/libc/malloc1/malloc.h b/libc/malloc1/malloc.h new file mode 100644 index 0000000..e8fdb0a --- /dev/null +++ b/libc/malloc1/malloc.h @@ -0,0 +1,30 @@ + +#ifndef __MALLOC_H +#define __MALLOC_H +#include <features.h> +#include <sys/types.h> + +/* + * Mini malloc allows you to use a less efficient but smaller malloc the + * cost is about 100 bytes of code in free but malloc (700bytes) doesn't + * have to be linked. Unfortunatly memory can only be reused if everything + * above it has been freed + * + */ + +extern void free __P((void *)); +extern void *malloc __P((size_t)); +extern void *realloc __P((void *, size_t)); +extern void *alloca __P((size_t)); + +extern void *(*__alloca_alloc) __P((size_t)); + +#ifdef __LIBC__ +#define __MINI_MALLOC__ +#endif + +#ifdef __MINI_MALLOC__ +#define malloc(x) ((*__alloca_alloc)(x)) +#endif + +#endif diff --git a/libc/malloc2/Config b/libc/malloc2/Config new file mode 100644 index 0000000..11c476d --- /dev/null +++ b/libc/malloc2/Config @@ -0,0 +1 @@ +malloc: Joel's malloc functions diff --git a/libc/malloc2/Makefile b/libc/malloc2/Makefile new file mode 100644 index 0000000..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..2e1cc04 --- /dev/null +++ b/libc/malloc2/malloc.c @@ -0,0 +1,126 @@ +/* simplified linux malloc.h + Copyright (C) 1995 Joel N. Weber II + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <malloc.h> + +typedef struct __malloc_struct malloc_struct; + +typedef union __malloc_union +{ + char *c; + malloc_struct *m; +} malloc_union; + + +struct __malloc_struct +{ + unsigned char status; +#define ALLOC 0x53 +#define FREE 0x55 +#define END_OF_WORLD 0x57 + malloc_union next; +} *malloc_start; + +extern int __STACKSIZE; + +/* WARNING: this init will only work if there is a hard limit on the + amount of RAM that can be allocated. + */ + +#ifdef __AS386_16__ +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word _malloc_init ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +malloc_init() +{ + extern unsigned int sbrk(); + + unsigned int ptr, sz, count; + + malloc_start = (malloc_struct*) ((sbrk(16)+1)&~1); + malloc_start->status = FREE; + + count=254; + for(sz=16384; sz>64; ) + { + ptr= sbrk(sz); + if( ptr == (unsigned)-1 ) sz>>=1; + else count+=sz; + } + if( __STACKSIZE > count || __STACKSIZE <= 0 ) __STACKSIZE = ((count>>1)&-2); + ptr = sbrk(-__STACKSIZE); + + malloc_start->next.m = ((malloc_struct*)ptr) - 1; + + malloc_start->next.m->status = END_OF_WORLD; +} + +char *malloc(size) +size_t size; +{ + register malloc_union tmp, tmp2; + + /* Make sure we don't lose the alignment */ + size = (size+sizeof(malloc_struct)-1)/sizeof(malloc_struct); + + tmp.m = malloc_start; + while ( ( tmp.m->next.m - tmp.m - 2 ) < size + || ( tmp.m->status == ALLOC )) + tmp.m = tmp.m->next.m; + + if (tmp.m->status == FREE){ + tmp2.m = size + tmp.m + 1; + tmp2.m->status = FREE; + tmp2.m->next.c = tmp.m->next.c; + tmp.m->status = ALLOC; + tmp.m->next.c = tmp2.c; + } + else return 0; + tmp.m++; + return tmp.c; +} + +__malloc_cleanup() /* finds consecutive free blocks and joins them */ +{ + malloc_struct *tmp; + + tmp = malloc_start; + while ((tmp->status != END_OF_WORLD)&&(tmp->next.m->status != END_OF_WORLD)){ + if ((tmp->status==FREE)&&(tmp->next.m->status==FREE)) + tmp->next.m = tmp->next.m->next.m; + else tmp = tmp->next.m; + } +} + +free(what) +char *what; +{ + malloc_union tmp; + + tmp.c = what; tmp.m--; + if( tmp.m->status == ALLOC ) + { + tmp.m->status = FREE; + __malloc_cleanup; + } +} diff --git a/libc/malloc2/malloc.h b/libc/malloc2/malloc.h new file mode 100644 index 0000000..ffcb3a4 --- /dev/null +++ b/libc/malloc2/malloc.h @@ -0,0 +1,21 @@ +/* simplified linux malloc.h + Copyright (C) 1995 Joel N. Weber II + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +char *malloc(size); +void free(what); +char *realloc(what, size); diff --git a/libc/malloc2/stack.c b/libc/malloc2/stack.c new file mode 100644 index 0000000..5f33e21 --- /dev/null +++ b/libc/malloc2/stack.c @@ -0,0 +1,10 @@ + +/* + * Under Linux 8086 the stack and heap areas are at the top and bottom + * of the same area of memory, this version of malloc requires that the + * malloc area is of a fixed size this means that there must also be a + * specific amount of stack space reserved outside of this. The number + * of bytes to be reserved is specified below. + */ + +int __STACKSIZE = 2048; diff --git a/libc/misc/Config b/libc/misc/Config new file mode 100644 index 0000000..9ede0c2 --- /dev/null +++ b/libc/misc/Config @@ -0,0 +1 @@ +misc: Various unix lib functions diff --git a/libc/misc/Makefile b/libc/misc/Makefile new file mode 100644 index 0000000..3db73a7 --- /dev/null +++ b/libc/misc/Makefile @@ -0,0 +1,59 @@ +# 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 + +GOBJ=atoi.o atol.o ltoa.o ltostr.o \ + ctype.o qsort.o bsearch.o rand.o lsearch.o getopt.o \ + itoa.o cputype.o strtol.o crypt.o + +UOBJ=getenv.o putenv.o popen.o system.o setenv.o + + +ifeq ($(LIB_OS),ELKS) +OBJ=$(MOBJ) $(EOBJ) $(GOBJ) $(UOBJ) +else +OBJ=$(MOBJ) $(EOBJ) $(GOBJ) +endif + +# No ELKS strtod() until BCC does 16 bit FP... +ifneq ($(LIB_CPU),i86) +OBJ+=strtod.o +endif + +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 ($(LIB_CPU),g386) + $(CC) $(CFLAGS) $< -c -o $@ $(WALL) +else + $(CC) $(CFLAGS) $< -c -o $@ -ansi +endif + +strto%.o: strto%.c +ifeq ($(LIB_CPU),g386) + $(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..d23ea65 --- /dev/null +++ b/libc/misc/aliases.c @@ -0,0 +1,110 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ +#include <string.h> +#include <sys/types.h> + +#ifdef L_abs +int +abs(arg1) +int arg1; +{ + return arg1>0?arg1:-arg1; +} +#endif + +#ifdef L_raise +int +raise(signo) +int signo; +{ + return kill(getpid(), signo); +} +#endif + +#ifdef L_bcopy +#undef bcopy +void +bcopy(src, dest, len) +__const void * src; +void *dest; +int len; +{ + (void) memcpy(dest, src, len); +} +#endif + +#ifdef L_bzero +#undef bzero +void +bzero(dest, len) +void *dest; +int len; +{ + (void) memset(dest, '\0', len); +} +#endif + +#ifdef L_bcmp +#undef bcmp +int +bcmp(dest, src, len) +__const void * src, *dest; +int len; +{ + return memcmp(dest, src, len); +} +#endif + +#ifdef L_index +#undef index +char * +index(src, chr) +__const char *src; +int chr; +{ + return strchr(src, chr); +} +#endif + +#ifdef L_rindex +#undef rindex +char * +rindex(src, chr) +__const char *src; +int chr; +{ + return strrchr(src, chr); +} +#endif + +#ifdef L_remove +#include <errno.h> + +int +remove(src) +__const char *src; +{ + extern int errno; + int er = errno; + int rv = unlink(src); + if( rv < 0 && errno == EISDIR ) + rv = rmdir(src); + if( rv >= 0 ) errno = er; + return rv; +} +#endif + +#ifdef L_creat +#include <fcntl.h> + +int +creat(file, mode) +__const char * file; +mode_t mode; +{ + return open(file, O_TRUNC|O_CREAT|O_WRONLY, mode); +} +#endif + diff --git a/libc/misc/atexit.c b/libc/misc/atexit.c new file mode 100644 index 0000000..6e8e45b --- /dev/null +++ b/libc/misc/atexit.c @@ -0,0 +1,102 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* + * This deals with both the atexit and on_exit function calls + * + * Note calls installed with atexit are called with the same args as on_exit + * fuctions; the void* is given the NULL value. + * + */ + +#include <errno.h> + +/* ATEXIT.H */ +#define MAXONEXIT 20 /* AIUI Posix requires 10 */ + +typedef void (*vfuncp) (); + +extern vfuncp __cleanup; +extern void __do_exit(); + +extern struct exit_table +{ + vfuncp called; + void *argument; +} +__on_exit_table[MAXONEXIT]; + +extern int __on_exit_count; + +/* End ATEXIT.H */ + +#ifdef L_atexit +int +atexit(ptr) +vfuncp ptr; +{ + if( __on_exit_count < 0 || __on_exit_count >= MAXONEXIT) + { + errno = ENOMEM; + return -1; + } + __cleanup = __do_exit; + if( ptr ) + { + __on_exit_table[__on_exit_count].called = ptr; + __on_exit_table[__on_exit_count].argument = 0; + __on_exit_count++; + } + return 0; +} + +#endif + +#ifdef L_on_exit +int +on_exit(ptr, arg) +vfuncp ptr; +void *arg; +{ + if( __on_exit_count < 0 || __on_exit_count >= MAXONEXIT) + { + errno = ENOMEM; + return -1; + } + __cleanup = __do_exit; + if( ptr ) + { + __on_exit_table[__on_exit_count].called = ptr; + __on_exit_table[__on_exit_count].argument = arg; + __on_exit_count++; + } + return 0; +} + +#endif + +#ifdef L___do_exit + +int __on_exit_count = 0; +struct exit_table __on_exit_table[MAXONEXIT]; + +void +__do_exit(rv) +int rv; +{ + register int count = __on_exit_count-1; + register vfuncp ptr; + __on_exit_count = -1; /* ensure no more will be added */ + __cleanup = 0; /* Calling exit won't re-do this */ + + /* In reverse order */ + for (; count >= 0; count--) + { + ptr = __on_exit_table[count].called; + (*ptr) (rv, __on_exit_table[count].argument); + } +} + +#endif diff --git a/libc/misc/atoi.c b/libc/misc/atoi.c new file mode 100644 index 0000000..5272646 --- /dev/null +++ b/libc/misc/atoi.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +int +atoi(number) +register char *number; +{ + register int n = 0, neg = 0; + + while (*number <= ' ' && *number > 0) + ++number; + if (*number == '-') + { + neg = 1; + ++number; + } + else if (*number == '+') + ++number; + while (*number>='0' && *number<='9') + n = (n * 10) + ((*number++) - '0'); + return (neg ? -n : n); +} diff --git a/libc/misc/atol.c b/libc/misc/atol.c new file mode 100644 index 0000000..901dfe2 --- /dev/null +++ b/libc/misc/atol.c @@ -0,0 +1,24 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +long +atol(number) +register char *number; +{ + register long n = 0, neg = 0; + + while (*number <= ' ' && *number > 0) + ++number; + if (*number == '-') + { + neg = 1; + ++number; + } + else if (*number == '+') + ++number; + while (*number>='0' && *number<='9') + n = (n * 10) + ((*number++) - '0'); + return (neg ? -n : n); +} diff --git a/libc/misc/bsearch.c b/libc/misc/bsearch.c new file mode 100644 index 0000000..9898667 --- /dev/null +++ b/libc/misc/bsearch.c @@ -0,0 +1,46 @@ + +/* + * This file lifted in toto from 'Dlibs' on the atari ST (RdeBath) + * + * + * Dale Schumacher 399 Beacon Ave. + * (alias: Dalnefre') St. Paul, MN 55104 + * dal@syntel.UUCP United States of America + * "It's not reality that's important, but how you perceive things." + */ +#include <stdio.h> + +static int _bsearch; /* index of element found, or where to + * insert */ + +char * +bsearch(key, base, num, size, cmp) +register char *key; /* item to search for */ +register char *base; /* base address */ +int num; /* number of elements */ +register int size; /* element size in bytes */ +register int (*cmp) (); /* comparison function */ +{ + register int a, b, c, dir; + + a = 0; + b = num - 1; + while (a <= b) + { + c = (a + b) >> 1; /* == ((a + b) / 2) */ + if (dir = (*cmp) ((base + (c * size)), key)) + { + if (dir > 0) + b = c - 1; + else /* (dir < 0) */ + a = c + 1; + } + else + { + _bsearch = c; + return (base + (c * size)); + } + } + _bsearch = b; + return (NULL); +} diff --git a/libc/misc/cputype.c b/libc/misc/cputype.c new file mode 100644 index 0000000..8417514 --- /dev/null +++ b/libc/misc/cputype.c @@ -0,0 +1,357 @@ +/* + * This does a determination of the cpu type that is actually being used. + * It can determine the CPU on anything upto and including a 386 accuratly + * whatever mode the CPU is in (This is 16 bit code) + * + * For Post 386 interpretation the argument must be set to 1, if this is done + * an attempt to determine the CPU type will be made using MSDOS calls and + * potentially Illegal instructions. + * + * If STANDALONE is defined this will decode and print the output from cputype + * + * $ cputype # Call cputype(0) and interpret + * $ cputype + # Call cputype(1) get a SIGILL (or perhaps interpret) + * + * NOTE: This code is COPYRIGHT and not under the GNU Lib copyright, this + * may be distributed freely as source or as a standalone binary + * compiled from this unmodified source. + * + * You may use the cputype() function in your own personal code. + * You may distribute a binary version of code containing the + * cputype() function if either you distribute this source with + * the binary version or distribute a clear reference to a freely + * available copy of this source code and the source code to the + * rest of your package with the binary version of the package. + * + * (C) Copyright R de Bath 1989-1996 + */ + +#ifdef STANDALONE +#define cputype cpu + +#include <stdio.h> +#ifndef __MSDOS__ +#include <signal.h> +#endif + +char * name_808x[] = { +"8088", "8086", "80C88", "80C86", "NEC V20", "NEC V30", "808x Clone" +}; + +char * name_8018x[] = { +"80188", "80186", "8018x Clone" +}; + +void +main(argc, argv) +int argc; char **argv; +{ + int c, major, flg, fpu; +#ifdef SIGFPE + signal(SIGFPE, SIG_IGN); +#endif + + printf("Cpu identifier - (C) R de Bath <rdebath@cix.compulink.co.uk>\n"); + + c = cputype(argc!=1); + fpu = (c<0); major = ((c>>8)&0x1F); c &= 0xFF; + + if( major == 0 ) + { + if( c > 6 ) c = 6; + printf("Cpu is an %s\n", name_808x[c]); + } + else if( major == 1 ) + { + if( c > 3 ) c = 3; + printf("Cpu is an %s\n", name_8018x[c]); + } + else + { + printf("Cpu is an 80%x86%s", major&0xF, major>15?"+":""); + if(c&0x01) printf( " in protected mode"); + printf(" MSW= "); + if( c&0x10 ) printf("ET,"); else printf("--,"); + if( c&0x08 ) printf("TS,"); else printf("--,"); + if( c&0x04 ) printf("EM,"); else printf("--,"); + if( c&0x02 ) printf("MP,"); else printf("--,"); + if( c&0x01 ) printf("PE\n"); else printf("--\n"); + + if( !fpu && ( c&0x06) ) + printf("An FPU appears to exist but it is unavailable\n"); + else + { + if( c&0x02 ) printf("Math processor requires WAIT\n"); + if( c&0x04 ) printf("Emulated math present\n"); + if( c&0x08 ) printf("Math processor belongs to a different process\n"); + /* if( c&0x10 ) printf("Humm\n"); */ + } + } + if( fpu ) printf("FPU available for use\n"); + + exit(0); +} +#endif + +/* + * The assembler for CPU determination. + * + * Improvements and additional CPUs are solicited. + */ + +#ifdef __AS386_16__ +#asm + .text +#ifdef STANDALONE +export _cpu +_cpu: +#else +export _cputype +_cputype: +#endif + ; First save everything ... + push bp + mov bp,sp + push ds + push es + push bx + push cx + push dx + pushf +#if __FIRST_ARG_IN_AX__ + mov cx, ax ; Collect the flag +#else + mov cx, [bp+4] ; Collect the flag +#endif + + ; Tiny mode code ... + mov ax, cs + mov es, ax + mov ds, ax + mov bx, #0 ; Init to 8086 + + ; First easy check is it a 286 or better ... + push sp + pop ax + cmp ax, sp + jz ge286 + br pre286 + + ; Come here when we`re done (286+) +cpu_prot: + ; .286P + smsw ax ; Fetch 5 LSB of MSW (PE,MP,EP,...) + and al,#31 + mov bl,al + + ; Check for FPU + fninit + xor ax,ax + push ax + mov bp,sp + fnstcw word ptr [bp] + pop ax + cmp ah,#3 + jne cpuend + or bh,#$80 + + ; Another check for FPU *BUT* I think this only get`s 287+ +; finit +; fstsw ax +; or al,al +; jnz cpuend +; or bh,#$80 + + ; .8086 +cpuend: + mov ax, bx + popf + pop dx + pop cx + pop bx + pop es + pop ds + pop bp + ret + +ge286: ; .286P + ; Does the caller want the exact CPU + cmp cx,#0 + jne try_486 + +; Simple test for a 286 ... + + mov bh,#2 ; Major CPU type >= 80286 + ; What`s the contents of the GDT pointer + sub sp,#6 + mov bp,sp + sgdt [bp] + add sp,#4 + pop ax ; For 286, ah can only be 0xFF + inc ah + jz cpu_prot + mov bh,#$13 ; Major CPU type >= 80386 + +#ifdef __MSDOS__ + smsw ax ; If we`re in MSDOS and running in real mode + ror ax,#1 ; we can do the int 6 detection. + jnc try_486 +#endif + + jmp cpu_prot ; Assume 486 test will NOT work in prot mode + + ; This is an alternate way of finding a 386 ... + ; But it *can* be hidden by V86 mode. +; pushf +; mov ax,#$7000 +; push ax +; popf +; pushf +; pop ax +; popf +; and ax,#$7000 +; jz is_a_286 + +try_486: + ; This trys to trap undefined instructions + ; it may not work if the CPU is in protected mode + ; Note: This code works for anything 286+ + cli + push bp + mov bp, sp + mov ax,#$3506 + int #$21 ; WARNING - DOS DOS DOS DOS DOS !!!!! + mov [vector+2], es + mov [vector], bx + mov ax,#$2506 + lea dx, [int6] + int #$21 + mov bh,#2 ; 286 + + ; .486 +test386: + mov ebx,#$00040300 ; 386 or 486 +test486: + bswap ebx ; Byte twiddle now 486 + + mov ax,#1 +do_cpuid: + db $0F ; CPUID instruction + db $A2 + + mov ax,#1 ; And again cause of Nasty EMM386s + db $0F ; CPUID instruction + db $A2 + + and ah,#15 ; Select family number + mov bh,ah ; put it where we want it + + ; .286P +fail386: + mov ax, #$2506 + mov dx, [vector] + mov ds, [vector+2] + int #$21 + pop bp + sti + br cpu_prot + + + ; Tests for processors before the 80286 ... + ; .8086 +pre286: + ; Is it an 8018x ? These mask shifts to less that 32 bits + mov cl,#32 + mov ax, #$0100 + shl ax,cl + mov bx, ax + jnz test8 + + ; Try for an NEC V20/30 + mov ax, #$0208 + db $D5 + db 16 ; Only the 8088 actually checks the arg to AAD + cmp al, #$28 ; as intel ran out of microcode space + jz cmos + mov bx,#4 ; NEC V20 + jmp test8 + + ; The CMOS 8088/6 had the bug with rep lods repaired. +cmos: push si + sti + mov cx, #$FFFF + rep + lodsb + pop si + or cx,cx + jne test8 + mov bx,#2 ; Intel 80C88 + + ; This tests the prefetch of the CPU, 8 bit ones have 4 bytes + ; 16 bit cpus have a queue of 6 bytes. +test8: push di + push bx + mov dx,#0 + mov bx,#4 + std + mov al,#$90 + +retest: lea di,[_nop] + cli + mov cx,#3 + rep + stosb + nop + nop + nop + nop +_inc: inc dx + nop +_nop: nop + sti + mov byte ptr [_inc], #$42 + dec bx + jnz retest + pop bx + cmp dx,#0 + jz done8 + inc bx +done8: pop di + cld + + br cpuend + + + ; Function called by the illegal instruction trap +int6: + mov sp, bp + jmp fail386 + +; This was the old way, didn`t always work tho. +; push bp +; mov bp, sp +; push ax +; mov ax,cs +; cmp 4[bp],ax +; pop ax +; jnz pass +; cmp bh,#2 +; je move23 +; cmp bh,#3 +; je move34 +; add [bp+2], #(fail386 - do_cpuid) +; jmp return +;move34: add [bp+2], #(fail386 - test486) +; jmp return +;move23: add [bp+2], #(fail386 - test386) +;return: pop bp +; iret +; +;pass: pop bp +; jmp [vector] + +vector: dd 0 + +#endasm + +#endif diff --git a/libc/misc/crypt.c b/libc/misc/crypt.c new file mode 100644 index 0000000..906dea2 --- /dev/null +++ b/libc/misc/crypt.c @@ -0,0 +1,50 @@ +#include <features.h> +#include <stdlib.h> +/* TEA based crypt(), version 0.0 <ndf@linux.mit.edu> + * It looks like there are problems with key bits carrying through + * to the encryted data, and I want to get rid of that libc call.. + * This is just so rob could see it ;) */ +char * +crypt(const char * key, const char * salt) +{ + /* n is the number of rounds, delta is a golden # derivative, + k is the key, v is the data to be encrypted. */ + unsigned long v[2], sum=0, delta=0x9e3779b9, n=64, k[4]; + static char rkey[16]; + unsigned char i; + + /* Our constant string will be a string of zeros .. */ + v[0]=v[1]=k[0]=k[1]=k[2]=k[3]=0; + for(i=0;i<16;i++) rkey[i]=0; + rkey[0]=*salt; + rkey[1]=salt[1]; + for (i=0;key[i];i++) rkey[i+1]=key[i]; + memcpy(k, rkey, 4*sizeof(long)); + + while (n-->0) { + sum += delta; + v[0] += (v[1]<<4)+k[0] ^ v[1]+sum ^ (v[1]>>5)+k[1]; + v[1] += (v[0]<<4)+k[2] ^ v[0]+sum ^ (v[0]>>5)+k[3]; + } + + *rkey=*salt; rkey[1]=salt[1]; + + /* Now we need to unpack the bits and map it to "A-Za-z0-9./" for printing + in /etc/passwd */ + for (i=2;i<13;i++) + { + /* This unpacks the 6 bit data, each cluster into its own byte */ + if (i==8) v[0]|=v[1]>>28; + rkey[i]=v[(i-2)/6]&0x3F; + v[(i-2)/6]>>=6; + + /* Now we map to the proper chars */ + if (rkey[i]>=0 && rkey[i]<12) rkey[i]+=46; + else if (rkey[i]>11 && rkey[i]<38) rkey[i]+=53; + else if (rkey[i]>37 && rkey[i]<64) rkey[i]+=59; + else return NULL; + } + + rkey[13]='\0'; + return rkey; +} diff --git a/libc/misc/ctype.c b/libc/misc/ctype.c new file mode 100644 index 0000000..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/setenv.c b/libc/misc/setenv.c new file mode 100644 index 0000000..10b32d2 --- /dev/null +++ b/libc/misc/setenv.c @@ -0,0 +1,97 @@ +/* Copyright (C) 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +extern char ** environ; + +int +setenv(name, value, replace) +__const char *name; +__const char *value; +int replace; +{ + register char **ep; + register size_t size; + __const size_t namelen = strlen (name); + __const size_t vallen = strlen (value); + int result = 0; + + size = 0; + for (ep = environ; *ep != NULL; ++ep) + if (!memcmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; + + if (*ep == NULL) + { + static char **last_environ = NULL; + char **new_environ = (char **) malloc((size + 2) * sizeof(char *)); + if (new_environ == NULL) + { + result = -1; + goto do_return; + } + (void) memcpy((void*) new_environ, (void*) environ, size * sizeof(char *)); + + new_environ[size] = malloc (namelen + 1 + vallen + 1); + if (new_environ[size] == NULL) + { + free (new_environ); + errno = ENOMEM; + result = -1; + goto do_return; + } + memcpy (new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy (&new_environ[size][namelen + 1], value, vallen + 1); + + new_environ[size + 1] = NULL; + + if (last_environ != NULL) + free ((void*) last_environ); + last_environ = new_environ; + environ = new_environ; + } + else if (replace) + { + size_t len = strlen (*ep); + if (len < namelen + 1 + vallen) + { + char *new = malloc (namelen + 1 + vallen + 1); + if (new == NULL) + { + result = -1; + goto do_return; + } + *ep = new; + } + memcpy (*ep, name, namelen); + (*ep)[namelen] = '='; + memcpy (&(*ep)[namelen + 1], value, vallen + 1); + } + +do_return: + return result; +} + +void +unsetenv(name) +__const char *name; +{ + register char **ep; + register char **dp; + __const size_t namelen = strlen (name); + + for (dp = ep = environ; *ep != NULL; ++ep) + if (memcmp (*ep, name, namelen) || (*ep)[namelen] != '=') + { + *dp = *ep; + ++dp; + } + *dp = NULL; +} diff --git a/libc/misc/strtod.c b/libc/misc/strtod.c new file mode 100644 index 0000000..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..59f38b9 --- /dev/null +++ b/libc/msdos/Makefile @@ -0,0 +1,40 @@ +# 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_segfree.o dos_setvect.o dos_getvect.o \ + dos_isatty.o dos_getmod.o dos_stat.o + +BSRC=i86.c +BOBJ= __seg_regs.o __peek_es.o __poke_es.o __deek_es.o __doke_es.o \ + __strchr_es.o + +ifeq ($(LIB_CPU),i86) +ifeq ($(LIB_OS),DOS) +OBJ=$(AOBJ) $(BOBJ) +else +OBJ=$(BOBJ) +endif +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..44de3e3 --- /dev/null +++ b/libc/msdos/i86.c @@ -0,0 +1,193 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ +/* + * These functions will not normally be useful for Linux-8086. But they + * can be used and may be useful in the kernel. + */ + +#ifdef __AS386_16__ + +#ifdef L___seg_regs +unsigned int +__get_cs() +{ +#asm + mov ax,cs +#endasm +} + +unsigned int +__get_ds() +{ +#asm + mov ax,ds +#endasm +} + +unsigned int +__get_es() +{ +#asm + mov ax,es +#endasm +} + +void +__set_es(seg) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov es,ax +#else + mov bx,sp + mov es,[bx+2] +#endif +#endasm +} +#endif + +#ifdef L___peek_es +int +__peek_es(off) +unsigned int off; +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,ax +#else + mov bx,sp + mov bx,[bx+2] +#endif + seg es + mov al,[bx] + xor ah,ah +#endasm +} +#endif + +#ifdef L___poke_es +int +__poke_es(off, value) +unsigned int off; +int value; +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,sp + mov bx,[bx+2] + xchg ax,bx +#else + mov bx,sp + mov ax,[bx+4] + mov bx,[bx+2] +#endif + seg es + mov [bx],al + xor ah,ah +#endasm +} +#endif + +#ifdef L___deek_es +int +__deek_es(off) +unsigned int off; +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,ax +#else + mov bx,sp + mov bx,[bx+2] +#endif + seg es + mov ax,[bx] +#endasm +} +#endif + +#ifdef L___doke_es +int +__doke_es(off, value) +unsigned int off; +int value; +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov bx,sp + mov bx,[bx+2] + xchg ax,bx +#else + mov bx,sp + mov ax,[bx+4] + mov bx,[bx+2] +#endif + seg es + mov [bx],ax +#endasm +} +#endif + +#ifdef L___strchr_es +char * +__strchr_es(s, c) +char * s; +int c; +{ +#asm + mov bx,sp + push si +#if __FIRST_ARG_IN_AX__ + mov bx,[bx+2] + mov si,ax +#else + mov si,[bx+2] + mov bx,[bx+4] +#endif + xor ax,ax + +#ifdef PARANOID + cld +#endif + push ds + push es + pop ds + +in_loop: + lodsb + cmp al,bl + jz got_it + or al,al + jnz in_loop + pop ds + pop si + ret +got_it: + lea ax,[si-1] + pop ds + pop si + +#endasm +} +#endif + +#ifdef L___strchr_es +char * +__strnget_es(d, s, c) +char *d, *s; +int c; +{ + int ds, es; + char *p = __strchr_es(s, '\0'); + if(p != 0 && p-s < c) + c = p-s+1; + ds = __get_ds(); + es = __get_es(); + + __movedata(es, s, ds, d, c); +} +#endif + +#endif /* __AS386_16__ */ diff --git a/libc/msdos/msdos.c b/libc/msdos/msdos.c new file mode 100644 index 0000000..390e904 --- /dev/null +++ b/libc/msdos/msdos.c @@ -0,0 +1,624 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#if !__FIRST_ARG_IN_AX__ +#ifdef __AS386_16__ +#ifdef __MSDOS__ + +#include <dos.h> +#include <fcntl.h> +#include <errno.h> +int errno; + +#ifdef L_dos_start + +static char * defarg[2] = { "C" }; +static char ** def_environ =defarg+1; +void (*__cleanup)() = 0; + +#asm + .data +export ___envseg +___envseg: + .word 0 + +export ___psp +___psp: + .word 0 + + .text + +export _exit +export __exit +_exit: ! exit(rv) function + mov bx,sp + push [bx+2] ! Copy the `rv` for the exit fuctions. + mov bx,[___cleanup] ! Call exit, normally this is `__do_exit` + test bx,bx + je no_clean ! But it`s default is null + call bx +no_clean: + inc sp + inc sp +__exit: ! _exit(rv) + mov bx,sp + mov ax,[bx+2] + mov ah,#$4c + int #$21 +dos_1_exit: + int #$20 + + .text +export ___cstartup ! Crt0 startup +___cstartup: + mov ax,#$3000 ! Get DOS version + int $21 + cmp al,#2 ! DOS 2+ is Ok + jb dos_1_exit + + mov dx,cs ! Current CS + add dx,#__segoff ! This var generated by the linker + mov ds,dx ! Correct DS + + mov [___psp],es ! PSP segment + seg es + mov ax,[$2c] + mov [___envseg],ax ! Enviroment Segment + + ! Now need to free some RAM + seg es + mov bx,[2] ! Top of Ram + mov ax,ds + add ax,#4096 ! Top of 64k data seg + jc use_tor ! Oops, wrapped + cmp ax,bx + jnc use_tor ! Bigger than tor + mov bx,ax +use_tor: + mov ax,cs ! Work out how big the memseg is needed + sub bx,ax + mov ah,#$4A ! Set it + int $21 + jnc set_stack ! Good. + ! Ooops, problem.. + ! BX is now how big it can be so set that. + ! FIXME should check for BSS v Stack overlap + mov ah,#$4A + int $21 + +set_stack: ! Now set SS to the same as DS + sub bx,#__segoff ! And SP to the top of available memory. + mov cl,#4 + shl bx,cl + sub bx,#2 + mov ss,dx + mov sp,bx + +zap_bss: ! Clear the BSS + mov es,dx ! ES now data seg + mov di,#__edata + mov cx,#__end + sub cx,di + xor ax,ax + cld + rep + stosb + + push [_def_environ] ! Defaults for when nothing is used. + mov ax,#_defarg + push ax + mov ax,#1 + push ax + + mov si,#auto_start ! Pointer to first autostart function +auto_run: + mov bx,[si] + test bx,bx + jz no_entry + call bx ! Call the function +no_entry: + inc si ! SI at next + inc si + jmp auto_run ! And round for the next. + +call_exit: ! Last item called by above. + pop bx ! Be tidy. + push ax ! At the end the last called was main() push it`s + call _exit ! return val and call exit(); +bad_exit: + jmp bad_exit ! Exit returned !! + + loc 2 + .word _main ! Segment 2 is the trailing pointers, main and the + .word call_exit ! routine to call exit. +data_start: + + .text + +#endasm + +__E_nosys() +{ +#asm + .text + +export sys_call5 +export sys_call4 +export sys_call3 +export sys_call2 +export sys_call1 +export sys_call0 +sys_call5: ! Trap the unemulated Linux86 syscalls +sys_call4: +sys_call3: +sys_call2: +sys_call1: +sys_call0: + +#endasm + errno = ENOSYS; + return -1; +} +#endif + +#ifdef L___mkargv + +#ifdef __AS386_16__ +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word ___mkargv ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +__mkargv(__argc, __argv) +int __argc; +char ** __argv; +{ + int length, i, argc=1, s=0; + char *ptr, *p; + __set_es(__psp); /* Pointer to the args */ + length = __peek_es(0x80); /* Length of cmd line */ + if( length > 0 ) + { + ptr = (char*) sbrk(length+1); /* Allocate some space */ + + for(i=0; i<length; i++) /* Copy it in. */ + { + ptr[i] = __peek_es(0x81+i); + if( ptr[i] != ' ' && s == 0 ) { argc++; s=1; } + if( ptr[i] == ' ' && s == 1 ) s=0; + } + ptr[length]=0; + + p= __argv[0]; + __argv = (char**) sbrk((argc+1)*sizeof(char*)); + __argv[0] = p; /* FIXME: The real command can be found */ + __argc=argc; + + argc=1; s=0; + for(i=0; i<length; i++) + { + if( ptr[i] != ' ' && s == 0 ) { __argv[argc++] = ptr+i; s=1; } + if( ptr[i] == ' ' && s == 1 ) { ptr[i] = '\0'; s=0; } + } + __argv[argc] = 0; + } +} +#endif + +#ifdef L_dos__fconv +/* This function converts filenames from unix like to DOS. */ +char * +__fconv(fname) +char * fname; +{ +static char buf1[66], buf2[66], *str = 0; + register char *p, ch; + int dot = 0; + + if( strcmp("/dev/tty", fname) == 0 ) return "CON:"; + + if( str == buf1 ) str = buf2; else str = buf1; + + p = str; + if( strncmp("/mnt/", fname, 5) == 0 ) + { + strcpy(p, "A:"); p+=2; fname+=4; + } + /* + * POSS: + * open("/name/*", ...); looks for an environ var PATH_name=c:\x\y\z + */ + + while((ch = *fname++) && p < str+65) + { + if( ( ch >= 'a' && ch <= 'z' ) + || ( ch >= '0' && ch <= '9' ) + || ch == ':' || ch == '%' || ch == '-' || ch == '$' ) + ; + else if( ch >= 'A' && ch <= 'Z' ) + ch = ch-'A'+'a'; + else if( ch == '.' && dot == 0 ) + dot = 1; + else if( ch == '/' || ch == '\\' ) + { + dot = 0; ch = '\\'; + } + else ch = '_'; + + *p++ = ch; + } + *p++ = '\0'; + return str; +} +#endif + +#ifdef L_dos_read +int +read(fd, ptr, len) +int fd; +char *ptr; +unsigned len; +{ +#asm + mov bx,sp + mov cx,[bx+6] + mov dx,[bx+4] + mov bx,[bx+2] + mov ah,#$3f + int #$21 + jnc readok + mov ax,#-1 +readok: +#endasm +} +#endif + +#ifdef L_dos_write +int +write(fd, ptr, len) +int fd; +char *ptr; +unsigned len; +{ +#asm + mov bx,sp + mov cx,[bx+6] + mov dx,[bx+4] + mov bx,[bx+2] + mov ah,#$40 + int #$21 + jnc writeok + mov ax,#-1 +writeok: +#endasm +} +#endif + +#ifdef L_dos_open +int +open(fname, type, cmode) +char * fname; +int type; +int cmode; +{ + register char * nname = __fconv(fname); + int creat_mode = 0; + int rv; + + if( (cmode & 0222) == 0 ) creat_mode = 1; + + /* BzzzT. Assume these flags both mean the merge of them */ + /* BzzzT. Also ignore O_EXCL */ + if( type & (O_TRUNC|O_CREAT) ) + rv = __dos_creat(nname, creat_mode); + + else + /* Warn, this assumes the standard vals for O_RDWR, O_RDONLY, O_WRONLY */ + rv = __dos_open(nname, type&O_ACCMODE); + if( rv < 0 ) errno=ENOENT; + return rv; +} + +__dos_open(fname, mode) +{ +#asm + mov bx,sp + mov dx,[bx+2] ;ds:dx points to source string + mov al,[bx+4] ;access code + mov ah,#$3d ;ask for a open + int #$21 + jnc openok ;return handle if no error + mov ax,#-1 ;return -1 if error +openok: +#endasm +} + +__dos_creat(fname) +char * fname; +{ +#asm + mov bx,sp + mov dx,[bx+2] ;ds:dx points to source string + xor cx,cx ;normal attributes + mov ah,#$3c ;ask for a create + int #$21 + jnc creok ;return handle if no error + mov ax,#-1 ;return -1 if error +creok: +#endasm +} +#endif + +#ifdef L_dos_close +close(fd) +{ +#asm + mov bx,sp + mov bx,[bx+2] ;file handle + mov ah,#$3e ;ask for a close + int #$21 + mov ax,0 ;return 0 if no error + jnc closeok + mov ax,#-1 ;return -1 if error +closeok: +#endasm +} +#endif + +#ifdef L_dos_unlink +unlink(fname) +char * fname; +{ +#asm + mov bx,sp + push [bx+2] + call ___fconv + inc sp + inc sp + mov dx,ax ;ds:dx points to source string + mov ah,#$41 ;ask for a unlink + int #$21 + mov ax,0 ;assume no errors + jnc unlok + mov ax,#-1 ;return -1 if error +unlok: +#endasm +} +#endif + +#ifdef L_dos_lseek +long +lseek(fd, offset, mode) +int fd, mode; +long offset; +{ +#asm + mov bx,sp + mov al,[bx+8] ;mode of seek (0 to 2) + mov dx,[bx+4] ;cx:dx is long offset + mov cx,[bx+6] + mov bx,[bx+2] ;file handle + mov ah,#$42 + int #$21 ;do the lseek + jnc seekok + mov ax,#-1 ;return -1 if error + mov dx,ax +seekok: +#endasm +} +#endif + +#ifdef L_dos_segalloc +unsigned int +__segalloc(paracount) +unsigned int paracount; +{ +#asm + mov bx,sp + mov bx,[bx+2] + mov ah,#$48 + int $21 + jnc ok + mov ax,#0 +ok: +#endasm +} +#endif + +#ifdef L_dos_segfree +unsigned int +__segfree(segno) +unsigned int segno; +{ +#asm + push es + mov bx,sp + mov es,[bx+4] + mov ah,#$49 + int $21 + jc err + mov ax,#0 +err: + pop es +#endasm +} +#endif + +#ifdef L_dos_setvect +void +__setvect(i,j) +int i; +long j; +{ +#asm + mov bx,sp + mov ax,[bx+2] + mov dx,[bx+4] + mov bx,[bx+6] + push ds + test bx,bx + jnz got_seg + mov bx,cs +got_seg: + mov ds,bx + mov ah,#$25 + int $21 + pop ds +#endasm +} +#endif + +#ifdef L_dos_getvect +long +__getvect(vecno) +int vecno; +{ +#asm + mov bx,sp + mov ax,[bx+2] + mov ah,#$35 + push es + int #$21 + mov dx,es + mov ax,bx + pop es +#endasm +} +#endif + +#ifdef L_dos_getmod +int +__dos_getmod(fname) +{ +#asm +#if __FIRST_ARG_IN_AX__ + mov dx,ax +#else + mov bx,sp + mov dx,[bx+2] +#endif + mov ax,#$4300 + int #$21 + jnc statok + mov cx,#-1 +statok: + mov ax,cx +#endasm +} +#endif + +#ifdef L_dos_stat +int +__dos_stat(fname, dtaptr) +{ +#asm + mov bx,sp +#if __FIRST_ARG_IN_AX__ + mov cx,ax + mov dx,[bx+2] +#else + mov dx,[bx+4] +#endif + mov ah,#$1A ; Set DTA to requested + int #$21 +#if __FIRST_ARG_IN_AX__ + mov ax,cx +#else + mov dx,[bx+2] +#endif + mov ax,#$4300 ; Locate the file + int #$21 + jc nonesuch + mov ax,#$4e00 ; Get all the available information. + int #$21 + jc nonesuch + xor ax,ax + ret +nonesuch: + mov ax,#2 + mov _errno,ax + mov ax,#-1 +#endasm +} +#endif + +#ifdef L_dos_isatty +isatty(fd) +int fd; +{ +#asm + mov bx,sp + mov bx,[bx+2] + mov ah,#$44 + mov al,#0 + int #$21 + xor ax,ax + test dx,#$80 + jz not_tty + inc ax +not_tty: +#endasm +} +#endif + +#endif /* __MSDOS__ */ +#endif /* __AS386_16__ */ +#endif /* !__FIRST_ARG_IN_AX__ */ + +/* +# Name No Args Flag, comment +CHDIR 12 1 +TIME 13 1 * No long return val, arg _must_ exist. +MKNOD 14 3 +CHMOD 15 2 +CHOWN 16 3 +BRK 17 1 * This is only to tell the system +STAT 18 2 +GETPID 20 1 * This gets both pid & ppid +MOUNT 21 3 * Need more args & no ELKS +UMOUNT 22 1 . No ELKS +SETUID 23 1 +GETUID 24 1 * This gets both uid and euid +STIME 25 2 . No ELKS should be 1 LONG arg +PTRACE 26 X + +ALARM 27 2 ? No unused return. +FSTAT 28 2 +PAUSE 29 0 +UTIME 30 2 +STTY 31 2 . ELKS ain't got this and it'll probably change +GTTY 32 2 . ELKS ain't got this and it'll probably change +ACCESS 33 2 +NICE 34 1 +FTIME 35 1 . ELKS ain't got this. +SYNC 36 0 +KILL 37 2 +RENAME 38 2 +MKDIR 39 2 +RMDIR 40 1 +DUP 41 X - Using nasty fcntl function +PIPE 42 1 +TIMES 43 1 +PROF 44 X + +SETGID 46 1 +GETGID 47 1 * This gets both gid and egid +SIGNAL 48 2 + +ACCT 51 X + +PLOCK 53 X + +IOCTL 54 3 +FCNTL 55 3 +EXEC 59 2 ? +UMASK 60 1 +CHROOT 61 1 +SIGACTION 71 X +SIGSUSPEND 72 X +SIGPENDING 73 X +SIGPROCMASK 74 X +SIGRETURN 75 X +REBOOT 76 3 . No ELKS and the magic number will be diff. +*/ + diff --git a/libc/msdos/time.c b/libc/msdos/time.c new file mode 100644 index 0000000..0a66da8 --- /dev/null +++ b/libc/msdos/time.c @@ -0,0 +1,63 @@ + +#include <time.h> + +static int mdays[13] = { 0,31,31+28,31+28+31,31+28+31+30, + 31+28+31+30+31,31+28+31+30+31+30,31+28+31+30+31+30+31, + 31+28+31+30+31+30+31+31,31+28+31+30+31+30+31+31+30, + 31+28+31+30+31+30+31+31+30+31,31+28+31+30+31+30+31+31+30+31+30, + 365 }; + +#define SECSPERHOUR (60*60) +#define SECSPERDAY (SECSPERHOUR*24L) + +/**************************************** + * Return the number of seconds that have elapsed since the start + * of 1970. + * Input: + * timer pointer to where to store result (or NULL) + * Output: + * *timer = result (unless timer == NULL) + * Returns: + * time + */ + +static long get_time(ah) +{ +#asm +#if !__FIST_ARG_IN_AX__ + mov bx,sp + mov ax,[bx+2] +#endif + mov ah,al + int $21 + mov ax,dx + mov dx,cx +#endasm +} + +time_t time(timer) +time_t *timer; +{ + unsigned day,month,year; + long rv; + time_t t; + + rv = get_time(0x2C); + rv >>= 8; t = (rv & 0xFF); + rv >>= 8; t += (rv & 0xFF)*60; + rv >>= 8; t += (rv & 0xFF)*3600; + + rv = get_time(0x2A); + day = (rv & 0xFF); + rv >>= 8; month = (rv & 0xFF) -1; + rv >>= 8; year = (rv & 0xFFFF) - 1970; + + if (month <= 1 || year & 3) /* if before Feb or not a leap year */ + day--; /* don't add day for leap year */ + day += mdays[month]; /* day in year */ + day += (year + 3) >> 2; /* add a day for each leap year */ + t += ((year * 365L) + day) * SECSPERDAY; + if (timer) + *timer = t; + return t; +} diff --git a/libc/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..eb4b844 --- /dev/null +++ b/libc/pwd/Makefile @@ -0,0 +1,44 @@ +# 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-ELKS) +CFLAGS+=$(WALL) +else +CFLAGS=$(CCFLAGS) $(LIBDEFS) -ansi +endif + +PSRC=__getpwent.c pwent.c getpwnam.c getpwuid.c putpwent.c getpw.c fgetpwent.c +ifeq ($(LIB_OS),ELKS) +POBJ=__getpwent.o pwent.o getpwnam.o getpwuid.o putpwent.o getpw.o fgetpwent.o +else +POBJ= +endif + +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; ®dummy = 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 = ®dummy; + 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 == ®dummy) { + 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 != ®dummy) + *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 == ®dummy) { + 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 == ®dummy) + 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 == ®dummy || 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 == ®dummy) + return(NULL); + + offset = NEXT(p); + if (offset == 0) + return(NULL); + + if (OP(p) == BACK) + return(p-offset); + else + return(p+offset); +} + +#ifdef DEBUG + +STATIC char *regprop(); + +/* + - regdump - dump a regexp onto stdout in vaguely comprehensible form + */ +void +regdump(r) +regexp *r; +{ + register char *s; + register char op = EXACTLY; /* Arbitrary non-END op. */ + register char *next; + extern char *strchr(); + + + s = r->program + 1; + while (op != END) { /* While that wasn't END last time... */ + op = OP(s); + printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ + next = regnext(s); + if (next == NULL) /* Next ptr. */ + printf("(0)"); + else + printf("(%d)", (s-r->program)+(next-s)); + s += 3; + if (op == ANYOF || op == ANYBUT || op == EXACTLY) { + /* Literal string, where present. */ + while (*s != '\0') { + putchar(*s); + s++; + } + s++; + } + putchar('\n'); + } + + /* Header fields of interest. */ + if (r->regstart != '\0') + printf("start `%c' ", r->regstart); + if (r->reganch) + printf("anchored "); + if (r->regmust != NULL) + printf("must have \"%s\"", r->regmust); + printf("\n"); +} + +/* + - regprop - printable representation of opcode + */ +static char * +regprop(op) +char *op; +{ + register char *p; + static char buf[50]; + + (void) strcpy(buf, ":"); + + switch (OP(op)) { + case BOL: + p = "BOL"; + break; + case EOL: + p = "EOL"; + break; + case ANY: + p = "ANY"; + break; + case ANYOF: + p = "ANYOF"; + break; + case ANYBUT: + p = "ANYBUT"; + break; + case BRANCH: + p = "BRANCH"; + break; + case EXACTLY: + p = "EXACTLY"; + break; + case NOTHING: + p = "NOTHING"; + break; + case BACK: + p = "BACK"; + break; + case END: + p = "END"; + break; + case OPEN+1: + case OPEN+2: + case OPEN+3: + case OPEN+4: + case OPEN+5: + case OPEN+6: + case OPEN+7: + case OPEN+8: + case OPEN+9: + sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); + p = NULL; + break; + case CLOSE+1: + case CLOSE+2: + case CLOSE+3: + case CLOSE+4: + case CLOSE+5: + case CLOSE+6: + case CLOSE+7: + case CLOSE+8: + case CLOSE+9: + sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); + p = NULL; + break; + case STAR: + p = "STAR"; + break; + case PLUS: + p = "PLUS"; + break; + default: + regerror("corrupted opcode"); + break; + } + if (p != NULL) + (void) strcat(buf, p); + return(buf); +} +#endif + +/* + * The following is provided for those people who do not have strcspn() in + * their C libraries. They should get off their butts and do something + * about it; at least one public-domain implementation of those (highly + * useful) string routines has been published on Usenet. + */ +#ifdef STRCSPN +/* + * strcspn - find length of initial segment of s1 consisting entirely + * of characters not from s2 + */ + +static int +strcspn(s1, s2) +char *s1; +char *s2; +{ + register char *scan1; + register char *scan2; + register int count; + + count = 0; + for (scan1 = s1; *scan1 != '\0'; scan1++) { + for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ + if (*scan1 == *scan2++) + return(count); + count++; + } + return(count); +} +#endif diff --git a/libc/regexp/regexp.h b/libc/regexp/regexp.h new file mode 100644 index 0000000..73d6bf4 --- /dev/null +++ b/libc/regexp/regexp.h @@ -0,0 +1,21 @@ +/* + * Definitions etc. for regexp(3) routines. + * + * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof], + * not the System V one. + */ +#define NSUBEXP 10 +typedef struct regexp { + char *startp[NSUBEXP]; + char *endp[NSUBEXP]; + char regstart; /* Internal use only. */ + char reganch; /* Internal use only. */ + char *regmust; /* Internal use only. */ + int regmlen; /* Internal use only. */ + char program[1]; /* Unwarranted chumminess with compiler. */ +} regexp; + +extern regexp *regcomp(); +extern int regexec(); +extern void regsub(); +extern void regerror(); diff --git a/libc/regexp/regmagic.h b/libc/regexp/regmagic.h new file mode 100644 index 0000000..5acf447 --- /dev/null +++ b/libc/regexp/regmagic.h @@ -0,0 +1,5 @@ +/* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. + */ +#define MAGIC 0234 diff --git a/libc/regexp/regsub.c b/libc/regexp/regsub.c new file mode 100644 index 0000000..5ca5676 --- /dev/null +++ b/libc/regexp/regsub.c @@ -0,0 +1,82 @@ +/* + * regsub + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + */ +#include <stdio.h> +#include <regexp.h> +#include "regmagic.h" + +#ifndef CHARBITS +#define UCHARAT(p) ((int)*(unsigned char *)(p)) +#else +#define UCHARAT(p) ((int)*(p)&CHARBITS) +#endif + +/* + - regsub - perform substitutions after a regexp match + */ +void +regsub(prog, source, dest) +regexp *prog; +char *source; +char *dest; +{ + register char *src; + register char *dst; + register char c; + register int no; + register int len; + extern char *strncpy(); + + if (prog == NULL || source == NULL || dest == NULL) { + regerror("NULL parm to regsub"); + return; + } + if (UCHARAT(prog->program) != MAGIC) { + regerror("damaged regexp fed to regsub"); + return; + } + + src = source; + dst = dest; + while ((c = *src++) != '\0') { + if (c == '&') + no = 0; + else if (c == '\\' && '0' <= *src && *src <= '9') + no = *src++ - '0'; + else + no = -1; + + if (no < 0) { /* Ordinary character. */ + if (c == '\\' && (*src == '\\' || *src == '&')) + c = *src++; + *dst++ = c; + } else if (prog->startp[no] != NULL && prog->endp[no] != NULL) { + len = prog->endp[no] - prog->startp[no]; + (void) strncpy(dst, prog->startp[no], len); + dst += len; + if (len != 0 && *(dst-1) == '\0') { + /* strncpy hit NUL. */ + regerror("damaged match string"); + return; + } + } + } + *dst++ = '\0'; +} diff --git a/libc/regexp/tests b/libc/regexp/tests new file mode 100644 index 0000000..e5bc16d --- /dev/null +++ b/libc/regexp/tests @@ -0,0 +1,127 @@ +abc abc y & abc +abc xbc n - - +abc axc n - - +abc abx n - - +abc xabcy y & abc +abc ababc y & abc +ab*c abc y & abc +ab*bc abc y & abc +ab*bc abbc y & abbc +ab*bc abbbbc y & abbbbc +ab+bc abbc y & abbc +ab+bc abc n - - +ab+bc abq n - - +ab+bc abbbbc y & abbbbc +ab?bc abbc y & abbc +ab?bc abc y & abc +ab?bc abbbbc n - - +ab?c abc y & abc +^abc$ abc y & abc +^abc$ abcc n - - +^abc abcc y & abc +^abc$ aabc n - - +abc$ aabc y & abc +^ abc y & +$ abc y & +a.c abc y & abc +a.c axc y & axc +a.*c axyzc y & axyzc +a.*c axyzd n - - +a[bc]d abc n - - +a[bc]d abd y & abd +a[b-d]e abd n - - +a[b-d]e ace y & ace +a[b-d] aac y & ac +a[-b] a- y & a- +a[b-] a- y & a- +a[b-a] - c - - +a[]b - c - - +a[ - c - - +a] a] y & a] +a[]]b a]b y & a]b +a[^bc]d aed y & aed +a[^bc]d abd n - - +a[^-b]c adc y & adc +a[^-b]c a-c n - - +a[^]b]c a]c n - - +a[^]b]c adc y & adc +ab|cd abc y & ab +ab|cd abcd y & ab +()ef def y &-\1 ef- +()* - c - - +*a - c - - +^* - c - - +$* - c - - +(*)b - c - - +$b b n - - +a\ - c - - +a\(b a(b y &-\1 a(b- +a\(*b ab y & ab +a\(*b a((b y & a((b +a\\b a\b y & a\b +abc) - c - - +(abc - c - - +((a)) abc y &-\1-\2 a-a-a +(a)b(c) abc y &-\1-\2 abc-a-c +a+b+c aabbabc y & abc +a** - c - - +a*? - c - - +(a*)* - c - - +(a*)+ - c - - +(a|)* - c - - +(a*|b)* - c - - +(a+|b)* ab y &-\1 ab-b +(a+|b)+ ab y &-\1 ab-b +(a+|b)? ab y &-\1 a-a +[^ab]* cde y & cde +(^)* - c - - +(ab|)* - c - - +)( - c - - + abc y & +abc n - - +a* y & +([abc])*d abbbcd y &-\1 abbbcd-c +([abc])*bcd abcd y &-\1 abcd-a +a|b|c|d|e e y & e +(a|b|c|d|e)f ef y &-\1 ef-e +((a*|b))* - c - - +abcd*efg abcdefg y & abcdefg +ab* xabyabbbz y & ab +ab* xayabbbz y & a +(ab|cd)e abcde y &-\1 cde-cd +[abhgefdc]ij hij y & hij +^(ab|cd)e abcde n x\1y xy +(abc|)ef abcdef y &-\1 ef- +(a|b)c*d abcd y &-\1 bcd-b +(ab|ab*)bc abc y &-\1 abc-a +a([bc]*)c* abc y &-\1 abc-bc +a([bc]*)(c*d) abcd y &-\1-\2 abcd-bc-d +a([bc]+)(c*d) abcd y &-\1-\2 abcd-bc-d +a([bc]*)(c+d) abcd y &-\1-\2 abcd-b-cd +a[bcd]*dcdcde adcdcde y & adcdcde +a[bcd]+dcdcde adcdcde n - - +(ab|a)b*c abc y &-\1 abc-ab +((a)(b)c)(d) abcd y \1-\2-\3-\4 abc-a-b-d +[a-zA-Z_][a-zA-Z0-9_]* alpha y & alpha +^a(bc+|b[eh])g|.h$ abh y &-\1 bh- +(bc+d$|ef*g.|h?i(j|k)) effgz y &-\1-\2 effgz-effgz- +(bc+d$|ef*g.|h?i(j|k)) ij y &-\1-\2 ij-ij-j +(bc+d$|ef*g.|h?i(j|k)) effg n - - +(bc+d$|ef*g.|h?i(j|k)) bcdd n - - +(bc+d$|ef*g.|h?i(j|k)) reffgz y &-\1-\2 effgz-effgz- +((((((((((a)))))))))) - c - - +(((((((((a))))))))) a y & a +multiple words of text uh-uh n - - +multiple words multiple words, yeah y & multiple words +(.*)c(.*) abcde y &-\1-\2 abcde-ab-de +\((.*), (.*)\) (a, b) y (\2, \1) (b, a) +[k] ab n - - +abcd abcd y &-\&-\\& abcd-&-\abcd +a(bc)d abcd y \1-\\1-\\\1 bc-\1-\bc +[ -~]* abc y & abc +[ -~ -~]* abc y & abc +[ -~ -~ -~]* abc y & abc +[ -~ -~ -~ -~]* abc y & abc +[ -~ -~ -~ -~ -~]* abc y & abc +[ -~ -~ -~ -~ -~ -~]* abc y & abc +[ -~ -~ -~ -~ -~ -~ -~]* abc y & abc diff --git a/libc/regexp/timer.c b/libc/regexp/timer.c new file mode 100644 index 0000000..2d84a12 --- /dev/null +++ b/libc/regexp/timer.c @@ -0,0 +1,182 @@ +/* + * Simple timing program for regcomp(). + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Usage: timer ncomp nexec nsub + * or + * timer ncomp nexec nsub regexp string [ answer [ sub ] ] + * + * The second form is for timing repetitions of a single test case. + * The first form's test data is a compiled-in copy of the "tests" file. + * Ncomp, nexec, nsub are how many times to do each regcomp, regexec, + * and regsub. The way to time an operation individually is to do something + * like "timer 1 50 1". + */ +#include <stdio.h> + +struct try { + char *re, *str, *ans, *src, *dst; +} tests[] = { +#include "timer.t.h" +{ NULL, NULL, NULL, NULL, NULL } +}; + +#include <regexp.h> + +int errreport = 0; /* Report errors via errseen? */ +char *errseen = NULL; /* Error message. */ + +char *progname; + +/* ARGSUSED */ +main(argc, argv) +int argc; +char *argv[]; +{ + int ncomp, nexec, nsub; + struct try one; + char dummy[512]; + + if (argc < 4) { + ncomp = 1; + nexec = 1; + nsub = 1; + } else { + ncomp = atoi(argv[1]); + nexec = atoi(argv[2]); + nsub = atoi(argv[3]); + } + + progname = argv[0]; + if (argc > 5) { + one.re = argv[4]; + one.str = argv[5]; + if (argc > 6) + one.ans = argv[6]; + else + one.ans = "y"; + if (argc > 7) { + one.src = argv[7]; + one.dst = "xxx"; + } else { + one.src = "x"; + one.dst = "x"; + } + errreport = 1; + try(one, ncomp, nexec, nsub); + } else + multiple(ncomp, nexec, nsub); + exit(0); +} + +void +regerror(s) +char *s; +{ + if (errreport) + errseen = s; + else + error(s, ""); +} + +#ifndef ERRAVAIL +error(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "regexp: "); + fprintf(stderr, s1, s2); + fprintf(stderr, "\n"); + exit(1); +} +#endif + +int lineno = 0; + +multiple(ncomp, nexec, nsub) +int ncomp, nexec, nsub; +{ + register int i; + extern char *strchr(); + + errreport = 1; + for (i = 0; tests[i].re != NULL; i++) { + lineno++; + try(tests[i], ncomp, nexec, nsub); + } +} + +try(fields, ncomp, nexec, nsub) +struct try fields; +int ncomp, nexec, nsub; +{ + regexp *r; + char dbuf[BUFSIZ]; + register int i; + + errseen = NULL; + r = regcomp(fields.re); + if (r == NULL) { + if (*fields.ans != 'c') + complain("regcomp failure in `%s'", fields.re); + return; + } + if (*fields.ans == 'c') { + complain("unexpected regcomp success in `%s'", fields.re); + free((char *)r); + return; + } + for (i = ncomp-1; i > 0; i--) { + free((char *)r); + r = regcomp(fields.re); + } + if (!regexec(r, fields.str)) { + if (*fields.ans != 'n') + complain("regexec failure in `%s'", ""); + free((char *)r); + return; + } + if (*fields.ans == 'n') { + complain("unexpected regexec success", ""); + free((char *)r); + return; + } + for (i = nexec-1; i > 0; i--) + (void) regexec(r, fields.str); + errseen = NULL; + for (i = nsub; i > 0; i--) + regsub(r, fields.src, dbuf); + if (errseen != NULL) { + complain("regsub complaint", ""); + free((char *)r); + return; + } + if (strcmp(dbuf, fields.dst) != 0) + complain("regsub result `%s' wrong", dbuf); + free((char *)r); +} + +complain(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "try: %d: ", lineno); + fprintf(stderr, s1, s2); + fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : ""); +} diff --git a/libc/regexp/try.c b/libc/regexp/try.c new file mode 100644 index 0000000..71620c2 --- /dev/null +++ b/libc/regexp/try.c @@ -0,0 +1,238 @@ +/* + * Simple test program for regexp(3) stuff. Knows about debugging hooks. + * + * Copyright (c) 1986 by University of Toronto. + * Written by Henry Spencer. Not derived from licensed software. + * + * Permission is granted to anyone to use this software for any + * purpose on any computer system, and to redistribute it freely, + * subject to the following restrictions: + * + * 1. The author is not responsible for the consequences of use of + * this software, no matter how awful, even if they arise + * from defects in it. + * + * 2. The origin of this software must not be misrepresented, either + * by explicit claim or by omission. + * + * 3. Altered versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * Usage: try re [string [output [-]]] + * The re is compiled and dumped, regexeced against the string, the result + * is applied to output using regsub(). The - triggers a running narrative + * from regexec(). Dumping and narrative don't happen unless DEBUG. + * + * If there are no arguments, stdin is assumed to be a stream of lines with + * five fields: a r.e., a string to match it against, a result code, a + * source string for regsub, and the proper result. Result codes are 'c' + * for compile failure, 'y' for match success, 'n' for match failure. + * Field separator is tab. + */ +#include <stdio.h> +#include <regexp.h> + +#ifdef ERRAVAIL +char *progname; +extern char *mkprogname(); +#endif + +#ifdef DEBUG +extern int regnarrate; +#endif + +char buf[BUFSIZ]; + +int errreport = 0; /* Report errors via errseen? */ +char *errseen = NULL; /* Error message. */ +int status = 0; /* Exit status. */ + +/* ARGSUSED */ +main(argc, argv) +int argc; +char *argv[]; +{ + regexp *r; + int i; + +#ifdef ERRAVAIL + progname = mkprogname(argv[0]); +#endif + + if (argc == 1) { + multiple(); + exit(status); + } + + r = regcomp(argv[1]); + if (r == NULL) + error("regcomp failure", ""); +#ifdef DEBUG + regdump(r); + if (argc > 4) + regnarrate++; +#endif + if (argc > 2) { + i = regexec(r, argv[2]); + printf("%d", i); + for (i = 1; i < NSUBEXP; i++) + if (r->startp[i] != NULL && r->endp[i] != NULL) + printf(" \\%d", i); + printf("\n"); + } + if (argc > 3) { + regsub(r, argv[3], buf); + printf("%s\n", buf); + } + exit(status); +} + +void +regerror(s) +char *s; +{ + if (errreport) + errseen = s; + else + error(s, ""); +} + +#ifndef ERRAVAIL +error(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "regexp: "); + fprintf(stderr, s1, s2); + fprintf(stderr, "\n"); + exit(1); +} +#endif + +int lineno; + +regexp badregexp; /* Implicit init to 0. */ + +multiple() +{ + char rbuf[BUFSIZ]; + char *field[5]; + char *scan; + int i; + regexp *r; + extern char *strchr(); + + errreport = 1; + lineno = 0; + while (fgets(rbuf, sizeof(rbuf), stdin) != NULL) { + rbuf[strlen(rbuf)-1] = '\0'; /* Dispense with \n. */ + lineno++; + scan = rbuf; + for (i = 0; i < 5; i++) { + field[i] = scan; + if (field[i] == NULL) { + complain("bad testfile format", ""); + exit(1); + } + scan = strchr(scan, '\t'); + if (scan != NULL) + *scan++ = '\0'; + } + try(field); + } + + /* And finish up with some internal testing... */ + lineno = 9990; + errseen = NULL; + if (regcomp((char *)NULL) != NULL || errseen == NULL) + complain("regcomp(NULL) doesn't complain", ""); + lineno = 9991; + errseen = NULL; + if (regexec((regexp *)NULL, "foo") || errseen == NULL) + complain("regexec(NULL, ...) doesn't complain", ""); + lineno = 9992; + r = regcomp("foo"); + if (r == NULL) { + complain("regcomp(\"foo\") fails", ""); + return; + } + lineno = 9993; + errseen = NULL; + if (regexec(r, (char *)NULL) || errseen == NULL) + complain("regexec(..., NULL) doesn't complain", ""); + lineno = 9994; + errseen = NULL; + regsub((regexp *)NULL, "foo", rbuf); + if (errseen == NULL) + complain("regsub(NULL, ..., ...) doesn't complain", ""); + lineno = 9995; + errseen = NULL; + regsub(r, (char *)NULL, rbuf); + if (errseen == NULL) + complain("regsub(..., NULL, ...) doesn't complain", ""); + lineno = 9996; + errseen = NULL; + regsub(r, "foo", (char *)NULL); + if (errseen == NULL) + complain("regsub(..., ..., NULL) doesn't complain", ""); + lineno = 9997; + errseen = NULL; + if (regexec(&badregexp, "foo") || errseen == NULL) + complain("regexec(nonsense, ...) doesn't complain", ""); + lineno = 9998; + errseen = NULL; + regsub(&badregexp, "foo", rbuf); + if (errseen == NULL) + complain("regsub(nonsense, ..., ...) doesn't complain", ""); +} + +try(fields) +char **fields; +{ + regexp *r; + char dbuf[BUFSIZ]; + + errseen = NULL; + r = regcomp(fields[0]); + if (r == NULL) { + if (*fields[2] != 'c') + complain("regcomp failure in `%s'", fields[0]); + return; + } + if (*fields[2] == 'c') { + complain("unexpected regcomp success in `%s'", fields[0]); + free((char *)r); + return; + } + if (!regexec(r, fields[1])) { + if (*fields[2] != 'n') + complain("regexec failure in `%s'", ""); + free((char *)r); + return; + } + if (*fields[2] == 'n') { + complain("unexpected regexec success", ""); + free((char *)r); + return; + } + errseen = NULL; + regsub(r, fields[3], dbuf); + if (errseen != NULL) { + complain("regsub complaint", ""); + free((char *)r); + return; + } + if (strcmp(dbuf, fields[4]) != 0) + complain("regsub result `%s' wrong", dbuf); + free((char *)r); +} + +complain(s1, s2) +char *s1; +char *s2; +{ + fprintf(stderr, "try: %d: ", lineno); + fprintf(stderr, s1, s2); + fprintf(stderr, " (%s)\n", (errseen != NULL) ? errseen : ""); + status = 1; +} diff --git a/libc/stdio2/Config b/libc/stdio2/Config new file mode 100644 index 0000000..665045f --- /dev/null +++ b/libc/stdio2/Config @@ -0,0 +1,4 @@ +# + +stdio: Robert's stdio package + diff --git a/libc/stdio2/Makefile b/libc/stdio2/Makefile new file mode 100644 index 0000000..f77df3a --- /dev/null +++ b/libc/stdio2/Makefile @@ -0,0 +1,45 @@ + +TOP=.. +include $(TOP)/Make.defs + +ifneq ($(LIB_CPU),i86) +CFLAGS=$(CCFLAGS) $(LIBDEFS) -DFLOATS +endif + +ASRC=stdio.c +AOBJ=_stdio_init.o fputc.o fgetc.o fflush.o fgets.o gets.o fputs.o \ + puts.o fread.o fwrite.o fopen.o fclose.o fseek.o rewind.o ftell.o \ + setbuffer.o setvbuf.o ungetc.o + +PSRC=printf.c +POBJ=printf.o sprintf.o fprintf.o vprintf.o vsprintf.o vfprintf.o + +SSRC=scanf.c +SOBJ=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o + +OBJ= $(AOBJ) $(POBJ) $(SOBJ) + +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 + +$(OBJ): stdio.h + +$(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..5a5744d --- /dev/null +++ b/libc/stdio2/printf.c @@ -0,0 +1,367 @@ +/* + * 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 + +#ifdef FLOATS +int (*__fp_print)() = 0; +#endif + +static int +prtfld(op, buf, ljustf, sign, pad, width, preci, buffer_mode) +register FILE *op; +register unsigned char *buf; +int ljustf; +register char sign; +char pad; +register int width; +int preci; +int buffer_mode; +/* + * Output the given field in the manner specified by the arguments. Return + * the number of characters output. + */ +{ + register int cnt = 0, len; + register unsigned char ch; + + len = strlen(buf); + + if (*buf == '-') + sign = *buf++; + else if (sign) + len++; + + if ((preci != -1) && (len > preci)) /* limit max data width */ + len = preci; + + if (width < len) /* flexible field width or width overflow */ + width = len; + + /* + * at this point: width = total field width len = actual data width + * (including possible sign character) + */ + cnt = width; + width -= len; + + while (width || len) + { + if (!ljustf && width) /* left padding */ + { + if (len && sign && (pad == '0')) + goto showsign; + ch = pad; + --width; + } + else if (len) + { + if (sign) + { + showsign:ch = sign; /* sign */ + sign = '\0'; + } + else + ch = *buf++; /* main field */ + --len; + } + else + { + ch = pad; /* right padding */ + --width; + } + putc(ch, op); + if( ch == '\n' && buffer_mode == _IOLBF ) fflush(op); + } + + return (cnt); +} + +int +vfprintf(op, fmt, ap) +FILE *op; +register __const char *fmt; +register va_list ap; +{ + register int i, cnt = 0, ljustf, lval; + int preci, dpoint, width; + char pad, sign, radix, hash; + register char *ptmp; + char tmp[64], *ltostr(), *ultostr(); + int buffer_mode; + + /* This speeds things up a bit for unbuffered */ + buffer_mode = (op->mode&__MODE_BUF); + op->mode &= (~__MODE_BUF); + + while (*fmt) + { + if (*fmt == '%') + { + if( buffer_mode == _IONBF ) fflush(op); + ljustf = 0; /* left justify flag */ + sign = '\0'; /* sign char & status */ + pad = ' '; /* justification padding char */ + width = -1; /* min field width */ + dpoint = 0; /* found decimal point */ + preci = -1; /* max data width */ + radix = 10; /* number base */ + ptmp = tmp; /* pointer to area to print */ + hash = 0; + lval = (sizeof(int)==sizeof(long)); /* long value flaged */ + fmtnxt: + i = 0; + for(;;) + { + ++fmt; + if(*fmt < '0' || *fmt > '9' ) break; + i = (i * 10) + (*fmt - '0'); + if (dpoint) + preci = i; + else if (!i && (pad == ' ')) + { + pad = '0'; + goto fmtnxt; + } + else + width = i; + } + + switch (*fmt) + { + case '\0': /* early EOS */ + --fmt; + goto charout; + + case '-': /* left justification */ + ljustf = 1; + goto fmtnxt; + + case ' ': + case '+': /* leading sign flag */ + sign = *fmt; + goto fmtnxt; + + case '*': /* parameter width value */ + i = va_arg(ap, int); + if (dpoint) + preci = i; + else + width = i; + goto fmtnxt; + + case '.': /* secondary width field */ + dpoint = 1; + goto fmtnxt; + + case 'l': /* long data */ + lval = 1; + goto fmtnxt; + + case 'h': /* short data */ + lval = 0; + goto fmtnxt; + + case 'd': /* Signed decimal */ + case 'i': + ptmp = ltostr((long) ((lval) + ? va_arg(ap, long) + : va_arg(ap, short)), + 10); + goto printit; + + case 'b': /* Unsigned binary */ + radix = 2; + goto usproc; + + case 'o': /* Unsigned octal */ + radix = 8; + goto usproc; + + case 'p': /* Pointer */ + lval = (sizeof(char*) == sizeof(long)); + pad = '0'; + width = 6; + preci = 8; + /* fall thru */ + + case 'x': /* Unsigned hexadecimal */ + case 'X': + radix = 16; + /* fall thru */ + + case 'u': /* Unsigned decimal */ + usproc: + ptmp = ultostr((unsigned long) ((lval) + ? va_arg(ap, unsigned long) + : va_arg(ap, unsigned short)), + radix); + if( hash && radix == 8 ) { width = strlen(ptmp)+1; pad='0'; } + goto printit; + + case '#': + hash=1; + goto fmtnxt; + + case 'c': /* Character */ + ptmp[0] = va_arg(ap, int); + ptmp[1] = '\0'; + goto nopad; + + case 's': /* String */ + ptmp = va_arg(ap, char*); + nopad: + sign = '\0'; + pad = ' '; + printit: + cnt += prtfld(op, ptmp, ljustf, + sign, pad, width, preci, buffer_mode); + break; + +#if FLOATS + case 'e': /* float */ + case 'f': + case 'g': + case 'E': + case 'G': + if ( __fp_print ) + { + (*__fp_print)(&va_arg(ap, double), *fmt, preci, ptmp); + preci = -1; + goto printit; + } + /* FALLTHROUGH if no floating printf available */ +#endif + + default: /* unknown character */ + goto charout; + } + } + else + { + charout: + putc(*fmt, op); /* normal char out */ + ++cnt; + if( *fmt == '\n' && buffer_mode == _IOLBF ) fflush(op); + } + ++fmt; + } + op->mode |= buffer_mode; + if( buffer_mode == _IONBF ) fflush(op); + if( buffer_mode == _IOLBF ) op->bufwrite = op->bufstart; + return (cnt); +} +#endif diff --git a/libc/stdio2/scanf.c b/libc/stdio2/scanf.c new file mode 100644 index 0000000..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..bab246b --- /dev/null +++ b/libc/stdio2/stdio.c @@ -0,0 +1,814 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +/* This is an implementation of the C standard IO package. + */ + +#include <stdio.h> + +#include <fcntl.h> +#include <sys/types.h> +#include <malloc.h> +#include <errno.h> + +extern FILE *__IO_list; /* For fflush at exit */ + +#ifdef __AS386_16__ +#define Inline_init +#endif + +#ifdef __AS386_32__ +#define Inline_init +#endif + +#ifndef Inline_init +#define Inline_init __io_init_vars() +#endif + +#ifdef L__stdio_init + +#define buferr (stderr->unbuf) /* Stderr is unbuffered */ + +FILE *__IO_list = 0; /* For fflush at exit */ + +static char bufin[BUFSIZ]; +static char bufout[BUFSIZ]; +#ifndef buferr +static char buferr[BUFSIZ]; +#endif + +FILE stdin[1] = +{ + {bufin, bufin, bufin, bufin, bufin + sizeof(bufin), + 0, _IOFBF | __MODE_READ | __MODE_IOTRAN} +}; + +FILE stdout[1] = +{ + {bufout, bufout, bufout, bufout, bufout + sizeof(bufout), + 1, _IOFBF | __MODE_WRITE | __MODE_IOTRAN} +}; + +FILE stderr[1] = +{ + {buferr, buferr, buferr, buferr, buferr + sizeof(buferr), + 2, _IONBF | __MODE_WRITE | __MODE_IOTRAN} +}; + +/* Call the stdio initiliser; it's main job it to call atexit */ + +#ifdef __AS386_16__ +#define STATIC static + +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .word ___io_init_vars ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +#ifdef __AS386_32__ +#define STATIC static + +#asm + loc 1 ! Make sure the pointer is in the correct segment +auto_func: ! Label for bcc -M to work. + .long ___io_init_vars ! Pointer to the autorun function + .text ! So the function after is also in the correct seg. +#endasm +#endif + +#ifndef STATIC +#define STATIC +#endif + +STATIC int +__stdio_close_all() +{ + FILE *fp; + fflush(stdout); + fflush(stderr); + for (fp = __IO_list; fp; fp = fp->next) + { + fflush(fp); + close(fp->fd); + /* Note we're not de-allocating the memory */ + /* There doesn't seem to be much point :-) */ + fp->fd = -1; + } +} + +STATIC void +__io_init_vars() +{ +#ifndef __AS386_16__ +#ifndef __AS386_32__ + static int first_time = 1; + if( !first_time ) return ; first_time = 1; +#endif +#endif + if (isatty(1)) + stdout->mode |= _IOLBF; + atexit(__stdio_close_all); +} +#endif + +#ifdef L_fputc +int +fputc(ch, fp) +int ch; +FILE *fp; +{ + register int v; + Inline_init; + + v = fp->mode; + /* If last op was a read ... */ + if ((v & __MODE_READING) && fflush(fp)) + return EOF; + + /* Can't write or there's been an EOF or error then return EOF */ + if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) + return EOF; + + /* In MSDOS translation mode */ +#if __MODE_IOTRAN + if (ch == '\n' && (v & __MODE_IOTRAN) && fputc('\r', fp) == EOF) + return EOF; +#endif + + /* Buffer is full */ + if (fp->bufpos >= fp->bufend && fflush(fp)) + return EOF; + + /* Right! Do it! */ + *(fp->bufpos++) = ch; + fp->mode |= __MODE_WRITING; + + /* Unbuffered or Line buffered and end of line */ + if (((ch == '\n' && (v & _IOLBF)) || (v & _IONBF)) + && fflush(fp)) + return EOF; + + /* Can the macro handle this by itself ? */ + if (v & (__MODE_IOTRAN | _IOLBF | _IONBF)) + fp->bufwrite = fp->bufstart; /* Nope */ + else + fp->bufwrite = fp->bufend; /* Yup */ + + /* Correct return val */ + return (unsigned char) ch; +} +#endif + +#ifdef L_fgetc +int +fgetc(fp) +FILE *fp; +{ + int ch; + + if (fp->mode & __MODE_WRITING) + fflush(fp); + + try_again: + /* Can't read or there's been an EOF or error then return EOF */ + if ((fp->mode & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) + return EOF; + + /* Nothing in the buffer - fill it up */ + if (fp->bufpos >= fp->bufread) + { + fp->bufpos = fp->bufread = fp->bufstart; + ch = fread(fp->bufpos, 1, fp->bufend - fp->bufstart, fp); + if (ch == 0) + return EOF; + fp->bufread += ch; + fp->mode |= __MODE_READING; + fp->mode &= ~__MODE_UNGOT; + } + ch = *(fp->bufpos++); + +#if __MODE_IOTRAN + /* In MSDOS translation mode; WARN: Doesn't work with UNIX macro */ + if (ch == '\r' && (fp->mode & __MODE_IOTRAN)) + goto try_again; +#endif + + return ch; +} +#endif + +#ifdef L_fflush +int +fflush(fp) +FILE *fp; +{ + int len, cc; + if (fp == NULL) /* On NULL flush the lot. */ + { + if (fflush(stdin)) + return EOF; + if (fflush(stdout)) + return EOF; + if (fflush(stderr)) + return EOF; + + for (fp = __IO_list; fp; fp = fp->next) + if (fflush(fp)) + return EOF; + + return 0; + } + + /* If there's output data pending */ + if (fp->mode & __MODE_WRITING) + { + len = fp->bufpos - fp->bufstart; + + if (len) + { + /* + * The loop is so we don't get upset by signals + */ + do + { + cc = write(fp->fd, fp->bufstart, len); + } + while (cc == -1 && errno == EINTR); + /* + * I think the following test is _too_ stringent, but it's not + * serious If it is found to be a problem then if cc>0 we can do + * a memcpy to put the buffer in a state for a retry. Or even do + * the retry ourselves. + */ + if (cc != len) + { + fp->mode |= __MODE_ERR; + return EOF; + } + } + } + /* If there's data in the buffer sychronise the file positions */ + else if (fp->mode & __MODE_READING) + { + /* Humm, I think this means sync the file like fpurge() ... */ + /* Anyway the user isn't supposed to call this function when reading */ + + len = fp->bufread - fp->bufpos; /* Bytes buffered but unread */ + /* If it's a file, make it good */ + if (len > 0 && lseek(fp->fd, -len, 1) < 0) + { + /* Hummm - Not certain here, I don't think this is reported */ + /* + * fp->mode |= __MODE_ERR; return EOF; + */ + } + } + + /* All done, no problem */ + fp->mode &= (~(__MODE_READING|__MODE_WRITING|__MODE_EOF|__MODE_UNGOT)); + fp->bufread = fp->bufwrite = fp->bufpos = fp->bufstart; + return 0; +} +#endif + +#ifdef L_fgets +/* Nothing special here ... */ +char * +fgets(s, count, f) +char *s; +size_t count; +FILE *f; +{ + char *ret; + register size_t i; + register int ch; + + ret = s; + for (i = count; i > 0; i--) + { + ch = getc(f); + if (ch == EOF) + { + if (s == ret) + return 0; + break; + } + *s++ = (char) ch; + if (ch == '\n') + break; + } + *s = 0; + + if (ferror(f)) + return 0; + return ret; +} +#endif + +#ifdef L_gets +char * +gets(str) /* BAD function; DON'T use it! */ +char *str; +{ + /* Auwlright it will work but of course _your_ program will crash */ + /* if it's given a too long line */ + register char *p = str; + register int c; + + while (((c = getc(stdin)) != EOF) && (c != '\n')) + *p++ = c; + *p = '\0'; + return (((c == EOF) && (p == str)) ? NULL : str); /* NULL == EOF */ +} +#endif + +#ifdef L_fputs +int +fputs(str, fp) +char *str; +FILE *fp; +{ + register int n = 0; + while (*str) + { + if (putc(*str++, fp) == EOF) + return (EOF); + ++n; + } + return (n); +} +#endif + +#ifdef L_puts +int +puts(str) +char *str; +{ + register int n; + + if (((n = fputs(str, stdout)) == EOF) + || (putc('\n', stdout) == EOF)) + return (EOF); + return (++n); +} +#endif + +#ifdef L_fread +/* + * fread will often be used to read in large chunks of data calling read() + * directly can be a big win in this case. Beware also fgetc calls this + * function to fill the buffer. + * + * This ignores __MODE__IOTRAN; probably exactly what you want. (It _is_ what + * fgetc wants) + */ +int +fread(buf, size, nelm, fp) +char *buf; +int size; +int nelm; +FILE *fp; +{ + int len, v; + unsigned bytes, got = 0; + Inline_init; + + v = fp->mode; + + /* Want to do this to bring the file pointer up to date */ + if (v & __MODE_WRITING) + fflush(fp); + + /* Can't read or there's been an EOF or error then return zero */ + if ((v & (__MODE_READ | __MODE_EOF | __MODE_ERR)) != __MODE_READ) + return 0; + + /* This could be long, doesn't seem much point tho */ + bytes = size * nelm; + + len = fp->bufread - fp->bufpos; + if (len >= bytes) /* Enough buffered */ + { + memcpy(buf, fp->bufpos, (unsigned) bytes); + fp->bufpos += bytes; + return bytes; + } + else if (len > 0) /* Some buffered */ + { + memcpy(buf, fp->bufpos, len); + got = len; + } + + /* Need more; do it with a direct read */ + len = read(fp->fd, buf + got, (unsigned) (bytes - got)); + + /* Possibly for now _or_ later */ + if (len < 0) + { + fp->mode |= __MODE_ERR; + len = 0; + } + else if (len == 0) + fp->mode |= __MODE_EOF; + + return (got + len) / size; +} +#endif + +#ifdef L_fwrite +/* + * Like fread, fwrite will often be used to write out large chunks of + * data; calling write() directly can be a big win in this case. + * + * But first we check to see if there's space in the buffer. + * + * Again this ignores __MODE__IOTRAN. + */ +int +fwrite(buf, size, nelm, fp) +char *buf; +int size; +int nelm; +FILE *fp; +{ + register int v; + int len; + unsigned bytes, put; + + v = fp->mode; + /* If last op was a read ... */ + if ((v & __MODE_READING) && fflush(fp)) + return 0; + + /* Can't write or there's been an EOF or error then return 0 */ + if ((v & (__MODE_WRITE | __MODE_EOF | __MODE_ERR)) != __MODE_WRITE) + return 0; + + /* This could be long, doesn't seem much point tho */ + bytes = size * nelm; + + len = fp->bufend - fp->bufpos; + + /* Flush the buffer if not enough room */ + if (bytes > len) + if (fflush(fp)) + return 0; + + len = fp->bufend - fp->bufpos; + if (bytes <= len) /* It'll fit in the buffer ? */ + { + fp->mode |= __MODE_WRITING; + memcpy(fp->bufpos, buf, bytes); + fp->bufpos += bytes; + + /* If we're not fully buffered */ + if (v & (_IOLBF | _IONBF)) + fflush(fp); + + return nelm; + } + else + /* Too big for the buffer */ + { + put = write(fp->fd, buf, bytes); + if (put < 0) + { + fp->mode |= __MODE_ERR; + put = 0; + } + } + + return put / size; +} +#endif + +#ifdef L_rewind +void +rewind(fp) +FILE * fp; +{ + fseek(fp, (long)0, 0); + clearerr(fp); +} +#endif + +#ifdef L_fseek +int +fseek(fp, offset, ref) +FILE *fp; +long offset; +int ref; +{ + /* Use fflush to sync the pointers */ + +#if 0 + /* if __MODE_READING and no ungetc ever done can just move pointer */ + /* This needs testing! */ + + if ( (fp->mode &(__MODE_READING | __MODE_UNGOT)) == __MODE_READING && + ( ref == SEEK_SET || ref == SEEK_CUR ) + { + long fpos = lseek(fp->fd, 0L, SEEK_CUR); + if( fpos == -1 ) return EOF; + + if( ref == SEEK_CUR ) + { + ref = SEEK_SET; + offset = fpos + offset + fp->bufpos - fp->bufread; + } + if( ref == SEEK_SET ) + { + if ( offset < fpos && offset >= fpos + fp->bufstart - fp->bufread ) + { + fp->bufpos = offset - fpos + fp->bufread; + return 0; + } + } + } +#endif + + if (fflush(fp) == EOF) + return EOF; + if (lseek(fp->fd, offset, ref) < 0) + return EOF; + return 0; +} +#endif + +#ifdef L_ftell +long ftell(fp) +FILE * fp; +{ + long rv; + if (fflush(fp) == EOF) + return EOF; + return lseek(fp->fd, 0L, SEEK_CUR); +} +#endif + +#ifdef L_fopen +/* + * This Fopen is all three of fopen, fdopen and freopen. The macros in + * stdio.h show the other names. + */ +FILE * +__fopen(fname, fd, fp, mode) +char *fname; +int fd; +FILE *fp; +char *mode; +{ + int open_mode = 0; +#if __MODE_IOTRAN + int do_iosense = 1; +#endif + int fopen_mode = 0; + FILE *nfp = 0; + + /* If we've got an fp close the old one (freopen) */ + if (fp) + { + /* Careful, don't de-allocate it */ + fopen_mode |= (fp->mode & (__MODE_BUF | __MODE_FREEFIL | __MODE_FREEBUF)); + fp->mode &= ~(__MODE_FREEFIL | __MODE_FREEBUF); + fclose(fp); + } + + /* decode the new open mode */ + while (*mode) + switch (*mode++) + { + case 'r': + fopen_mode |= __MODE_READ; + break; + case 'w': + fopen_mode |= __MODE_WRITE; + open_mode = (O_CREAT | O_TRUNC); + break; + case 'a': + fopen_mode |= __MODE_WRITE; + open_mode = (O_CREAT | O_APPEND); + break; + case '+': + fopen_mode |= __MODE_RDWR; + break; +#if __MODE_IOTRAN + case 'b': /* Binary */ + fopen_mode &= ~__MODE_IOTRAN; + do_iosense=0; + break; + case 't': /* Text */ + fopen_mode |= __MODE_IOTRAN; + do_iosense=0; + break; +#endif + } + + /* Add in the read/write options to mode for open() */ + switch (fopen_mode & (__MODE_READ | __MODE_WRITE)) + { + case 0: + return 0; + case __MODE_READ: + open_mode |= O_RDONLY; + break; + case __MODE_WRITE: + open_mode |= O_WRONLY; + break; + default: + open_mode |= O_RDWR; + break; + } + + /* Allocate the (FILE) before we do anything irreversable */ + if (fp == 0) + { + nfp = malloc(sizeof(FILE)); + if (nfp == 0) + return 0; + } + + /* Open the file itself */ + if (fname) + fd = open(fname, open_mode, 0666); + if (fd < 0) /* Grrrr */ + { + if (nfp) + free(nfp); + return 0; + } + + /* If this isn't freopen create a (FILE) and buffer for it */ + if (fp == 0) + { + fp = nfp; + fp->next = __IO_list; + __IO_list = fp; + + fp->mode = __MODE_FREEFIL; + if( isatty(fd) ) + { + fp->mode |= _IOLBF; +#if __MODE_IOTRAN + if( do_iosense ) fopen_mode |= __MODE_IOTRAN; +#endif + } + else + fp->mode |= _IOFBF; + fp->bufstart = malloc(BUFSIZ); + if (fp->bufstart == 0) /* Oops, no mem */ + { /* Humm, full buffering with a two(!) byte + * buffer. */ + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + } + else + { + fp->bufend = fp->bufstart + BUFSIZ; + fp->mode |= __MODE_FREEBUF; + } + } + + /* Ok, file's ready clear the buffer and save important bits */ + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; + fp->mode |= fopen_mode; + fp->fd = fd; + + return fp; +} +#endif + +#ifdef L_fclose +int +fclose(fp) +FILE *fp; +{ + int rv = 0; + + if (fp == 0) + { + errno = EINVAL; + return EOF; + } + if (fflush(fp)) + return EOF; + + if (close(fp->fd)) + rv = EOF; + fp->fd = -1; + + if (fp->mode & __MODE_FREEBUF) + { + free(fp->bufstart); + fp->mode &= ~__MODE_FREEBUF; + fp->bufstart = fp->bufend = 0; + } + + if (fp->mode & __MODE_FREEFIL) + { + FILE *prev = 0, *ptr; + fp->mode = 0; + + for (ptr = __IO_list; ptr && ptr != fp; ptr = ptr->next) + ; + if (ptr == fp) + { + if (prev == 0) + __IO_list = fp->next; + else + prev->next = fp->next; + } + free(fp); + } + else + fp->mode = 0; + + return rv; +} +#endif + +#ifdef L_setbuffer +void +setbuffer(fp, buf, size) +FILE * fp; +char * buf; +int size; +{ + fflush(fp); + if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart); + fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); + + if( buf == 0 ) + { + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + fp->mode |= _IONBF; + } + else + { + fp->bufstart = buf; + fp->bufend = buf+size; + fp->mode |= _IOFBF; + } + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; +} +#endif + +#ifdef L_setvbuf +int setvbuf(fp, buf, mode, size) +FILE * fp; +char * buf; +int mode; +size_t size; +{ + fflush(fp); + if( fp->mode & __MODE_FREEBUF ) free(fp->bufstart); + fp->mode &= ~(__MODE_FREEBUF|__MODE_BUF); + fp->bufstart = fp->unbuf; + fp->bufend = fp->unbuf + sizeof(fp->unbuf); + fp->mode |= _IONBF; + + if( mode == _IOFBF || mode == _IOLBF ) + { + if( size <= 0 ) size = BUFSIZ; + if( buf == 0 ) buf = malloc(size); + if( buf == 0 ) return EOF; + + fp->bufstart = buf; + fp->bufend = buf+size; + fp->mode |= mode; + } + fp->bufpos = fp->bufread = fp->bufwrite = fp->bufstart; +} +#endif + +#ifdef L_ungetc +int +ungetc(c, fp) +int c; +FILE *fp; +{ + if (fp->mode & __MODE_WRITING) + fflush(fp); + + /* Can't read or there's been an error then return EOF */ + if ((fp->mode & (__MODE_READ | __MODE_ERR)) != __MODE_READ) + return EOF; + + /* Can't do fast fseeks */ + fp->mode |= __MODE_UNGOT; + + if( fp->bufpos > fp->bufstart ) + return *--fp->bufpos = (unsigned char) c; + else if( fp->bufread == fp->bufstart ) + return *fp->bufread++ = (unsigned char) c; + else + return EOF; +} +#endif + diff --git a/libc/stdio2/stdio.h b/libc/stdio2/stdio.h new file mode 100644 index 0000000..98ca38a --- /dev/null +++ b/libc/stdio2/stdio.h @@ -0,0 +1,129 @@ + +#ifndef __STDIO_H +#define __STDIO_H + +#include <features.h> +#include <sys/types.h> + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#define _IOFBF 0x00 /* full buffering */ +#define _IOLBF 0x01 /* line buffering */ +#define _IONBF 0x02 /* no buffering */ +#define __MODE_BUF 0x03 /* Modal buffering dependent on isatty */ + +#define __MODE_FREEBUF 0x04 /* Buffer allocated with malloc, can free */ +#define __MODE_FREEFIL 0x08 /* FILE allocated with malloc, can free */ + +#define __MODE_READ 0x10 /* Opened in read only */ +#define __MODE_WRITE 0x20 /* Opened in write only */ +#define __MODE_RDWR 0x30 /* Opened in read/write */ + +#define __MODE_READING 0x40 /* Buffer has pending read data */ +#define __MODE_WRITING 0x80 /* Buffer has pending write data */ + +#define __MODE_EOF 0x100 /* EOF status */ +#define __MODE_ERR 0x200 /* Error status */ +#define __MODE_UNGOT 0x400 /* Buffer has been polluted by ungetc */ + +#ifdef __MSDOS__ +#define __MODE_IOTRAN 0x1000 /* MSDOS nl <-> cr,nl translation */ +#else +#define __MODE_IOTRAN 0 +#endif + +/* when you add or change fields here, be sure to change the initialization + * in stdio_init and fopen */ +struct __stdio_file { + unsigned char *bufpos; /* the next byte to write to or read from */ + unsigned char *bufread; /* the end of data returned by last read() */ + unsigned char *bufwrite; /* highest address writable by macro */ + unsigned char *bufstart; /* the start of the buffer */ + unsigned char *bufend; /* the end of the buffer; ie the byte after the last + malloc()ed byte */ + + int fd; /* the file descriptor associated with the stream */ + int mode; + + char unbuf[8]; /* The buffer for 'unbuffered' streams */ + + struct __stdio_file * next; +}; + +#define EOF (-1) +#ifndef NULL +#define NULL (0) +#endif + +typedef struct __stdio_file FILE; + +#ifdef __AS386_16__ +#define BUFSIZ (256) +#else +#define BUFSIZ (2048) +#endif + +extern FILE stdin[1]; +extern FILE stdout[1]; +extern FILE stderr[1]; + +#ifdef __MSDOS__ +#define putc(c, fp) fputc(c, fp) +#define getc(fp) fgetc(fp) +#else +#define putc(c, stream) \ + (((stream)->bufpos >= (stream)->bufwrite) ? fputc((c), (stream)) \ + : (unsigned char) (*(stream)->bufpos++ = (c)) ) + +#define getc(stream) \ + (((stream)->bufpos >= (stream)->bufread) ? fgetc(stream): \ + (*(stream)->bufpos++)) +#endif + +#define putchar(c) putc((c), stdout) +#define getchar() getc(stdin) + +#define ferror(fp) (((fp)->mode&__MODE_ERR) != 0) +#define feof(fp) (((fp)->mode&__MODE_EOF) != 0) +#define clearerr(fp) ((fp)->mode &= ~(__MODE_EOF|__MODE_ERR),0) +#define fileno(fp) ((fp)->fd) + +/* declare functions; not like it makes much difference without ANSI */ +/* RDB: The return values _are_ important, especially if we ever use + 8086 'large' model + */ + +/* These two call malloc */ +#define setlinebuf(__fp) setvbuf((__fp), (char*)0, _IOLBF, 0) +extern int setvbuf __P((FILE*, char*, int, size_t)); + +/* These don't */ +#define setbuf(__fp, __buf) setbuffer((__fp), (__buf), BUFSIZ) +extern void setbuffer __P((FILE*, char*, int)); + +extern int fgetc __P((FILE*)); +extern int fputc __P((int, FILE*)); + +extern int fclose __P((FILE*)); +extern int fflush __P((FILE*)); +extern char *fgets __P((char*, size_t, FILE*)); +extern FILE *__fopen __P((char*, int, FILE*, char*)); + +#define fopen(__file, __mode) __fopen((__file), -1, (FILE*)0, (__mode)) +#define freopen(__file, __mode, __fp) __fopen((__file), -1, (__fp), (__mode)) +#define fdopen(__file, __mode) __fopen((char*)0, (__file), (FILE*)0, (__mode)) + +extern int fputs __P((char*, FILE*)); +extern int puts __P((char*)); + +extern int printf __P ((__const char*, ...)); +extern int fprintf __P ((FILE*, __const char*, ...)); +extern int sprintf __P ((char*, __const char*, ...)); + +#define stdio_pending(fp) ((fp)->bufread>(fp)->bufpos) + +#endif /* __STDIO_H */ diff --git a/libc/string/Config b/libc/string/Config new file mode 100644 index 0000000..b712dcf --- /dev/null +++ b/libc/string/Config @@ -0,0 +1 @@ +string: String and memory manipulation diff --git a/libc/string/Makefile b/libc/string/Makefile new file mode 100644 index 0000000..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..3e6d2e4 --- /dev/null +++ b/libc/string/string.c @@ -0,0 +1,669 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <string.h> +#include <malloc.h> + +#ifdef __AS386_16__ +#if __FIRST_ARG_IN_AX__ +#define BCC_AX_ASM /* BCC Assembler that can cope with arg in AX */ +#else +#define BCC_AX_ASM +#define BCC_ASM /* Use 16 bit BCC assembler */ +#endif + +#define PARANOID /* Include extra code for cld and ES register */ +#endif + +/* This is a basic string package; it includes the most used functions + + strlen strcat strcpy strcmp strncat strncpy strncmp strchr strrchr strdup + memcpy memccpy memchr memset memcmp memmove + + These functions are in seperate files. + strpbrk.o strsep.o strstr.o strtok.o strcspn.o + strspn.o strcasecmp.o strncasecmp.o + */ + +/********************** Function strlen ************************************/ + +#ifdef L_strlen +size_t strlen(str) +const char * str; +{ +#ifdef BCC_AX_ASM +#asm +#if !__FIRST_ARG_IN_AX__ + mov bx,sp +#endif + push di + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif ! This is almost the same as memchr, but it can + ! stay as a special. + +#if __FIRST_ARG_IN_AX__ + mov di,ax +#else + mov di,[bx+2] +#endif + mov cx,#-1 + xor ax,ax + repne + scasb + not cx + dec cx + mov ax,cx + +#ifdef PARANOID + pop es +#endif + pop di +#endasm +#else + register char * p =(char *) str; + while(*p) p++; + return p-str; +#endif /* ifdef BCC_AX_ASM */ +} +#endif + +/********************** Function strcat ************************************/ + +#ifdef L_strcat +char * strcat(d, s) +char *d; +const char * s; +{ + (void) strcpy(d+strlen(d), s); + return d; +} +#endif + +/********************** Function strcpy ************************************/ + +#ifdef L_strcpy +char * strcpy(d, s) +char *d; +const char * s; +{ + /* This is probably the quickest on an 8086 but a CPU with a cache will + * prefer to do this in one pass */ + return memcpy(d, s, strlen(s)+1); +} +#endif + +/********************** Function strcmp ************************************/ + +#ifdef L_strcmp +int strcmp(d, s) +const char *d; +const char * s; +{ + /* There are a number of ways to do this and it really does depend on the + types of strings given as to which is better, nevertheless the Glib + method is quite reasonable so we'll take that */ + +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push di + push si + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov di,ax ; dest + mov si,[bx+2] ; source +#else + mov di,[bx+2] ; dest + mov si,[bx+4] ; source +#endif +sc_1: + lodsb + scasb + jne sc_2 ; If bytes are diff skip out. + testb al,al + jne sc_1 ; If this byte in str1 is nul the strings are equal + xor ax,ax ; so return zero + jmp sc_3 +sc_2: + sbb ax,ax ; Collect correct val (-1,1). + orb al,#1 +sc_3: + +#ifdef PARANOID + pop es +#endif + pop si + pop di +#endasm +#else /* ifdef BCC_AX_ASM */ + register char *s1=(char *)d, *s2=(char *)s, c1,c2; + while((c1= *s1++) == (c2= *s2++) && c1 ); + return c1 - c2; +#endif /* ifdef BCC_AX_ASM */ +} +#endif + +/********************** Function strncat ************************************/ + +#ifdef L_strncat +char * strncat(d, s, l) +char *d, *s; +size_t l; +{ + register char *s1=d+strlen(d), *s2; + + s2 = memchr(s, l, 0); + if( s2 ) + memcpy(s1, s, s2-s+1); + else + { + memcpy(s1, s, l); + s1[l] = '\0'; + } + return d; +} +#endif + +/********************** Function strncpy ************************************/ + +#ifdef L_strncpy +char * strncpy(d, s, l) /* FIXME need the fast version of this */ +char *d, *s; +size_t l; +{ + register char *s1=d, *s2=s; + while(l > 0) + { + l--; + if( (*s1++ = *s2++) == '\0') + break; + } + + /* This _is_ correct strncpy is supposed to zap */ + for(; l>0; l--) *s1++ = '\0'; + return d; +} +#endif + +/********************** Function strncmp ************************************/ + +#ifdef L_strncmp +int strncmp(d, s, l) +const char *d, *s; +size_t l; +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push si + push di + +#ifdef PARANOID + push es + push ds ! Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov si,ax + mov di,[bx+2] + mov cx,[bx+4] +#else + mov si,[bx+2] ! Fetch + mov di,[bx+4] + mov cx,[bx+6] +#endif + + inc cx +lp1: + dec cx + je lp2 + lodsb + scasb + jne lp3 + testb al,al + jne lp1 +lp2: + xor ax,ax + jmp lp4 +lp3: + sbb ax,ax + or al,#1 +lp4: + +#ifdef PARANOID + pop es +#endif + pop di + pop si +#endasm +#else + register char c1=0, c2=0; + while(l-- >0) + if( (c1= *d++) != (c2= *s++) || c1 == '\0' ) + break; + return c1-c2; +#endif +} +#endif + +/********************** Function strchr ************************************/ + +#ifdef L_strchr +char * +strchr(s, c) +char * s; +int c; +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push si +#if __FIRST_ARG_IN_AX__ + mov bx,[bx+2] + mov si,ax +#else + mov si,[bx+2] + mov bx,[bx+4] +#endif + xor ax,ax + +#ifdef PARANOID + cld +#endif + +in_loop: + lodsb + cmp al,bl + jz got_it + or al,al + jnz in_loop + pop si + ret +got_it: + lea ax,[si-1] + pop si + +#endasm +#else /* ifdef BCC_AX_ASM */ + register char ch; + for(;;) + { + if( (ch= *s) == c ) return s; + if( ch == 0 ) return 0; + s++; + } +#endif /* ifdef BCC_AX_ASM */ +} +#endif + +/********************** Function strrchr ************************************/ + +#ifdef L_strrchr +char * strrchr(s, c) +char * s; +int c; +{ + register char * prev = 0; + register char * p = s; + /* For null it's just like strlen */ + if( c == '\0' ) return p+strlen(p); + + /* everything else just step along the string. */ + while( (p=strchr(p, c)) != 0 ) + { + prev = p; p++; + } + return prev; +} +#endif + +/********************** Function strdup ************************************/ + +#ifdef L_strdup +char * strdup(s) +char * s; +{ + register size_t len; + register char * p; + + len = strlen(s)+1; + p = (char *) malloc(len); + if(p) memcpy(p, s, len); /* Faster than strcpy */ + return p; +} +#endif + +/********************** Function memcpy ************************************/ + +#ifdef L_memcpy +void * +memcpy(d, s, l) +void *d; +const void *s; +size_t l; +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push di + push si + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov di,ax ; dest + mov si,[bx+2] ; source + mov cx,[bx+4] ; count +#else + mov di,[bx+2] ; dest + mov si,[bx+4] ; source + mov cx,[bx+6] ; count + + mov ax,di +#endif + ; If di is odd mov 1 byte before doing word move + ; this will speed slightly but + ; NB 8086 has no problem with mis-aligned access. + + shr cx,#1 ; Do this faster by doing a mov word + rep + movsw + adc cx,cx ; Retrieve the leftover 1 bit from cflag. + rep + movsb + +#ifdef PARANOID + pop es +#endif + pop si + pop di +#endasm +#else /* ifdef BCC_AX_ASM */ + register char *s1=d, *s2=(char *)s; + for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++); + return d; +#endif /* ifdef BCC_AX_ASM */ +} +#endif + +/********************** Function memccpy ************************************/ + +#ifdef L_memccpy +void * memccpy(d, s, c, l) /* Do we need a fast one ? */ +void *s, *d; +int c; +size_t l; +{ + register char *s1=d, *s2=s; + while(l-- > 0) + if((*s1++ = *s2++) == c ) + return s1; + return 0; +} +#endif + +/********************** Function memchr ************************************/ + +#ifdef L_memchr +void * memchr(str, c, l) +const void * str; +int c; +size_t l; +{ +#ifdef BCC_ASM +#asm + mov bx,sp + push di + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + + mov di,[bx+2] + mov ax,[bx+4] + mov cx,[bx+6] + test cx,cx + je is_z ! Zero length, do not find. + + repne ! Scan + scasb + jne is_z ! Not found, ret zero + dec di ! Adjust ptr + mov ax,di ! return + jmp xit +is_z: + xor ax,ax +xit: + +#ifdef PARANOID + pop es +#endif + pop di +#endasm +#else /* ifdef BCC_ASM */ + register char *p=(char *)str; + while(l-- > 0) + { + if(*p == c) return p; + p++; + } + return 0; +#endif /* ifdef BCC_ASM */ +} +#endif + +/********************** Function memset ************************************/ + +#ifdef L_memset +void * memset(str, c, l) +void * str; +int c; +size_t l; +{ +#ifdef BCC_AX_ASM +#asm + mov bx,sp + push di + +#ifdef PARANOID + push es + push ds ; Im not sure if this is needed, so just in case. + pop es + cld +#endif + +#if __FIRST_ARG_IN_AX__ + mov di,ax ; Fetch + mov ax,[bx+2] + mov cx,[bx+4] +#else + mov di,[bx+2] ; Fetch + mov ax,[bx+4] + mov cx,[bx+6] +#endif + +; How much difference does this alignment make ? +; I don`t think it`s significant cause most will already be aligned. + +; test cx,cx ; Zero size - skip +; je xit +; +; test di,#1 ; Line it up +; je s_1 +; stosb +; dec cx +;s_1: + + mov ah,al ; Replicate byte + shr cx,#1 ; Do this faster by doing a sto word + rep ; Bzzzzz ... + stosw + adc cx,cx ; Retrieve the leftover 1 bit from cflag. + + rep ; ... z + stosb + +xit: + mov ax,[bx+2] +#ifdef PARANOID + pop es +#endif + pop di +#endasm +#else /* ifdef BCC_AX_ASM */ + register char *s1=str; + while(l-->0) *s1++ = c; + return str; +#endif /* ifdef BCC_AX_ASM */ +} +#endif + +/********************** Function memcmp ************************************/ + +#ifdef L_memcmp +int memcmp(s, d, l) +const void *s, *d; +size_t l; +{ +#ifdef BCC_ASM +#asm + mov bx,sp + push di + push si + +#ifdef PARANOID + push es + push ds ! Im not sure if this is needed, so just in case. + pop es + cld +#endif + + mov si,[bx+2] ! Fetch + mov di,[bx+4] + mov cx,[bx+6] + xor ax,ax + + rep ! Bzzzzz + cmpsb + je xit ! All the same! + sbb ax,ax + sbb ax,#-1 ! choose +/-1 +xit: +#ifdef PARANOID + pop es +#endif + pop si + pop di +#endasm +#else /* ifdef BCC_ASM */ + register const char *s1=d, *s2=s; + register char c1=0, c2=0; + while(l-- > 0) + if( (c1= *s1++) != (c2= *s2++) ) + break; + return c1-c2; +#endif /* ifdef BCC_ASM */ +} +#endif + +/********************** Function memmove ************************************/ + +#ifdef L_memmove +void * +memmove(d, s, l) +void *d, *s; +size_t l; +{ + register char *s1=d, *s2=s; + /* This bit of sneakyness c/o Glibc, it assumes the test is unsigned */ + if( s1-s2 >= l ) return memcpy(d,s,l); + + /* This reverse copy only used if we absolutly have to */ + s1+=l; s2+=l; + while(l-- >0) + *(--s1) = *(--s2); + return d; +} +#endif + +/********************** Function movedata ***********************************/ + +#ifdef L_movedata + +/* NB There isn't any C version of this function ... */ + +#ifdef BCC_AX_ASM +void +__movedata(srcseg, srcoff, destseg, destoff, len) +unsigned int srcseg, srcoff, destseg, destoff, len; +{ +#asm + push bp + mov bp,sp + push si + push di + push ds +#ifdef PARANOID + push es + cld +#endif + + ! sei ! Are we _really_ paranoid ? + +#if !__FIRST_ARG_IN_AX__ + mov ds,[bp+4] ! Careful, [bp+xx] is SS based. + mov si,[bp+6] + mov es,[bp+8] + mov di,[bp+10] + mov cx,[bp+12] +#else + mov ds,ax + mov si,[bp+4] + mov es,[bp+6] + mov di,[bp+8] + mov cx,[bp+10] +#endif + rep + movsb + + ! cli ! Are we _really_ paranoid ? + +#ifdef PARANOID + pop es +#endif + pop ds + pop di + pop si + pop bp +#endasm +} +#endif + +#endif + +/********************** THE END ********************************************/ + diff --git a/libc/string/string.h b/libc/string/string.h new file mode 100644 index 0000000..2233bf9 --- /dev/null +++ b/libc/string/string.h @@ -0,0 +1,53 @@ + +#ifndef __STRING_H +#define __STRING_H +#include <features.h> +#include <sys/types.h> +#include <stddef.h> + +/* Basic string functions */ +extern size_t strlen __P ((__const char* __str)); + +extern char * strcat __P ((char*, __const char*)); +extern char * strcpy __P ((char*, __const char*)); +extern int strcmp __P ((__const char*, __const char*)); + +extern char * strncat __P ((char*, char*, size_t)); +extern char * strncpy __P ((char*, char*, size_t)); +extern int strncmp __P ((__const char*, __const char*, size_t)); + +extern char * strchr __P ((char*, int)); +extern char * strrchr __P ((char*, int)); +extern char * strdup __P ((char*)); + +/* Basic mem functions */ +extern void * memcpy __P ((void*, __const void*, size_t)); +extern void * memccpy __P ((void*, void*, int, size_t)); +extern void * memchr __P ((__const void*, __const int, size_t)); +extern void * memset __P ((void*, int, size_t)); +extern int memcmp __P ((__const void*, __const void*, size_t)); + +extern void * memmove __P ((void*, void*, size_t)); + +/* Minimal (very!) locale support */ +#define strcoll strcmp +#define strxfrm strncpy + +/* BSDisms */ +#define index strchr +#define rindex strrchr + +/* Other common BSD functions */ +extern int strcasecmp __P ((char*, char*)); +extern int strncasecmp __P ((char*, char*, size_t)); +char *strpbrk __P ((char *, char *)); +char *strsep __P ((char **, char *)); +char *strstr __P ((char *, char *)); +char *strtok __P ((char *, char *)); +size_t strcspn __P ((char *, char *)); +size_t strspn __P ((char *, char *)); + +/* Linux silly hour */ +char *strfry __P ((char *)); + +#endif diff --git a/libc/string/strncasecmp.c b/libc/string/strncasecmp.c new file mode 100644 index 0000000..561f72a --- /dev/null +++ b/libc/string/strncasecmp.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <string.h> +#include <ctype.h> + +int +strncasecmp(s, d, l) +char *s; +char *d; +size_t l; +{ + while(l>0) + { + if( *s != *d ) + { + if( tolower(*s) != tolower(*d) ) + return *s - *d; + } + else + if( *s == '\0' ) return 0; + s++; d++; l--; + } + return 0; +} + diff --git a/libc/string/strpbrk.c b/libc/string/strpbrk.c new file mode 100644 index 0000000..3fc27ec --- /dev/null +++ b/libc/string/strpbrk.c @@ -0,0 +1,21 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <string.h> + +/* This uses strchr, strchr should be in assembler */ + +char *strpbrk(str, set) +register char *str; +char *set; +{ + while (*str != '\0') + if (strchr(set, *str) == 0) + ++str; + else + return (char *) str; + + return 0; +} diff --git a/libc/string/strsep.c b/libc/string/strsep.c new file mode 100644 index 0000000..21aa1bb --- /dev/null +++ b/libc/string/strsep.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <string.h> + +char * +strsep(pp, delim) +char **pp; +char *delim; +{ + char *p, *q; + + if (!(p = *pp)) + return 0; + if (q = strpbrk (p, delim)) + { + *pp = q + 1; + *q = '\0'; + } + else + *pp = 0; + return p; +} diff --git a/libc/string/strspn.c b/libc/string/strspn.c new file mode 100644 index 0000000..2094caa --- /dev/null +++ b/libc/string/strspn.c @@ -0,0 +1,44 @@ +/* Copyright (C) 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <string.h> + +/* Return the length of the maximum initial segment + of S which contains only characters in ACCEPT. */ +size_t +strspn(s, accept) +char *s; +char *accept; +{ + register char *p; + register char *a; + register size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + else + ++count; + } + + return count; +} diff --git a/libc/string/strstr.c b/libc/string/strstr.c new file mode 100644 index 0000000..aafcaf9 --- /dev/null +++ b/libc/string/strstr.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <string.h> + +#if 1 +/* We've now got a nice fast strchr and memcmp use them */ + +char * +strstr(s1, s2) +char *s1; char *s2; +{ + register int l = strlen(s2); + register char * p = s1; + + if( l==0 ) return p; + + while (p = strchr(p, *s2)) + { + if( memcmp(p, s2, l) == 0 ) + return p; + p++; + } + return (char *) 0; +} + +#else +/* This is a nice simple self contained strstr, + now go and work out why the GNU one is faster :-) */ + +char *strstr(str1, str2) +char *str1, *str2; +{ + register char *Sptr, *Tptr; + int len = strlen(str1) -strlen(str2) + 1; + + if (*str2) + for (; len > 0; len--, str1++){ + if (*str1 != *str2) + continue; + + for (Sptr = str1, Tptr = str2; *Tptr != '\0'; Sptr++, Tptr++) + if (*Sptr != *Tptr) + break; + + if (*Tptr == '\0') + return (char*) str1; + } + + return (char*)0; +} +#endif diff --git a/libc/string/strtok.c b/libc/string/strtok.c new file mode 100644 index 0000000..27d8f25 --- /dev/null +++ b/libc/string/strtok.c @@ -0,0 +1,71 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <string.h> + + +static char *olds = 0; + +/* Parse S into tokens separated by characters in DELIM. + If S is NULL, the last string strtok() was called with is + used. For example: + char s[] = "-abc=-def"; + x = strtok(s, "-"); // x = "abc" + x = strtok(NULL, "=-"); // x = "def" + x = strtok(NULL, "="); // x = NULL + // s = "abc\0-def\0" +*/ +char * +strtok(s, delim) +register char *s; +register char *delim; +{ + char *token; + + if (s == 0) + { + if (olds == 0) + { + return 0; + } + else + s = olds; + } + + /* Scan leading delimiters. */ + s += strspn(s, delim); + if (*s == '\0') + { + olds = 0; + return 0; + } + + /* Find the end of the token. */ + token = s; + s = strpbrk(token, delim); + if (s == 0) + /* This token finishes the string. */ + olds = 0; + else + { + /* Terminate the token and make OLDS point past it. */ + *s = '\0'; + olds = s + 1; + } + return token; +} diff --git a/libc/syscall/Config b/libc/syscall/Config new file mode 100644 index 0000000..472e74b --- /dev/null +++ b/libc/syscall/Config @@ -0,0 +1 @@ +syscall: Linux-8086 system call routines diff --git a/libc/syscall/Makefile b/libc/syscall/Makefile new file mode 100644 index 0000000..06728da --- /dev/null +++ b/libc/syscall/Makefile @@ -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. + +TOP=.. +include $(TOP)/Make.defs + +LSRC=syslibc.c +LOBJ=time.o abort.o wait.o waitpid.o killpg.o setpgrp.o sleep.o \ + usleep.o + +LSRC3=syslib3.c +LOBJ3=__cstart3.o + +LSRC0=syslib0.c +LOBJ0=__cstartup.o lseek.o getpid.o getppid.o getuid.o geteuid.o getgid.o \ + getegid.o dup2.o dup.o getpgrp.o times.o + +ESRC=execve.c +E2OBJ=execl.o execv.o execle.o +EOBJ=execve.o $(E2OBJ) + +DSRC=dirent.c +DOBJ=opendir.o closedir.o readdir.o + +ifeq ($(LIB_CPU)-$(LIB_OS),i86-ELKS) +SYSCALLS=sh mksyscall +OBJ=$(LOBJ0) $(LOBJ) $(DOBJ) $(EOBJ) signal.o setjmp.o +DEP=mksyscall syscall.dat +endif + +ifeq ($(LIB_CPU)-$(LIB_OS),i386-ELKS) +SYSCALLS=sh mksys386 +OBJ=setjmp.o $(LOBJ3) $(LOBJ) $(E2OBJ) $(DOBJ) +DEP=mksys386 sys386.dat +endif + +ifeq ($(SYSCALLS),) +SYSCALLS=true +OBJ=setjmp.o +DEP= +endif + +all: $(DEP) $(OBJ) + $(SYSCALLS) + +libc.a: $(DEP) $(OBJ) + $(SYSCALLS) libc.a + ar r ../$(LIBC) $(OBJ) + @touch libc.a + +clean: + rm -f *.o libc.a syscall.c syscall.mak call_tab.v defn_tab.v + +$(LOBJ): $(LSRC) + $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC) + +$(DOBJ): $(DSRC) + $(CC) $(CFLAGS) -c -DL_$* -o $@ $(DSRC) + +$(EOBJ): $(ESRC) + $(CC) $(CFLAGS) -c -DL_$* -o $@ $(ESRC) + +$(LOBJ0): $(LSRC0) + $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC0) + +$(LOBJ3): $(LSRC3) + $(CC) $(CFLAGS) -c -DL_$* -o $@ $(LSRC3) 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..8f7574c --- /dev/null +++ b/libc/syscall/dirent.c @@ -0,0 +1,106 @@ + +#include <errno.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <dirent.h> +#include <malloc.h> + +#ifdef L_opendir +DIR * +opendir(dname) +const char *dname; +{ + struct stat st; + int fd; + DIR *p; + + if (stat(dname, &st) < 0) + return 0; + + if (!S_ISDIR(st.st_mode)) + { + errno = ENOTDIR; + return 0; + } + if ((fd = open(dname, O_RDONLY)) < 0) + return 0; + + p = malloc(sizeof(DIR)); + if (p == 0) + { + close(fd); + return 0; + } + + p->dd_buf = malloc(sizeof(struct dirent)); + if (p->dd_buf == 0) + { + free(p); + close(fd); + return 0; + } + p->dd_fd = fd; + p->dd_loc = p->dd_size = 0; + + return p; +} +#endif + +#ifdef L_closedir +int +closedir(dirp) +DIR *dirp; +{ + int fd; + fd = dirp->dd_fd; + free(dirp->dd_buf); + free(dirp); + return close(fd); +} +#endif + +#ifdef __AS386_16__ +#ifdef L_readdir +/* + * This currently assumes we see a v. simple diectory structure, it's + * probably faked! + */ +struct dirent * +readdir(dirp) +DIR *dirp; +{ + int cc; + cc = read(dirp->dd_fd, dirp->dd_buf, sizeof(struct dirent)); + + if (cc <= 0) + return 0; + if (cc != sizeof(struct dirent)) + { + errno = EBADF; + return 0; + } + return dirp->dd_buf; +} +#endif +#else + +/* This is for 386 linux */ + +#ifdef L_readdir +struct dirent * +readdir(dirp) +DIR *dirp; +{ + int cc; + + cc = __readdir(dirp->dd_fd, dirp->dd_buf, 1); + if (cc <= 0) + return 0; + if (cc>1) dirp->dd_buf->d_name[cc] = 0; + + return dirp->dd_buf; +} +#endif + +#endif diff --git a/libc/syscall/execve.c b/libc/syscall/execve.c new file mode 100644 index 0000000..33643ca --- /dev/null +++ b/libc/syscall/execve.c @@ -0,0 +1,208 @@ + +#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 + +#ifdef L_execvve +int +execvve(fname, interp, argv, envp) +char * fname; +char ** interp; +char ** argv; +char ** envp; +{ + char **p; + int argv_len=0, argv_count=0; + int envp_len=0, envp_count=0; + int stack_bytes; + unsigned short * pip; + char * pcp, * stk_ptr, *baseoff; + int rv; + + /* How much space for argv */ + for(p=interp; p && *p && argv_len >= 0; p++) + { + argv_count++; argv_len += strlen(*p)+1; + } + for(p=argv; p && *p && argv_len >= 0; p++) + { + argv_count++; argv_len += strlen(*p)+1; + } + + /* How much space for envp */ + for(p=envp; p && *p && envp_len >= 0; p++) + { + envp_count++; envp_len += strlen(*p)+1; + } + + /* tot it all up */ + stack_bytes = 2 /* argc */ + + argv_count * 2 + 2 /* argv */ + + argv_len + + envp_count * 2 + 2 /* envp */ + + envp_len; + + /* Allocate it */ + if( argv_len < 0 || envp_len < 0 || stack_bytes <= 0 + || (int)(stk_ptr = (char*)sbrk(stack_bytes)) == -1) + { + errno = ENOMEM; + return -1; + } + +/* Sanity check + printf("Argv = (%d,%d), Envp=(%d,%d), stack=%d\n", + argv_count, argv_len, envp_count, envp_len, stack_bytes); +*/ + + /* Now copy in the strings */ + pip=(unsigned short *) stk_ptr; + pcp=stk_ptr+2*(1+argv_count+1+envp_count+1); + + /* baseoff = stk_ptr + stack_bytes; */ + baseoff = stk_ptr; + *pip++ = argv_count; + for(p=interp; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + for(p=argv; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + *pip++ = 0; + + for(p=envp; p && *p; p++) + { + int l; + *pip++ = pcp-baseoff; + l = strlen(*p)+1; + memcpy(pcp, *p, l); + pcp += l; + } + *pip++ = 0; + + rv = __exec(fname, stk_ptr, stack_bytes); + /* FIXME: This will probably have to interpret '#!' style exe's */ + sbrk(-stack_bytes); + return rv; +} +#endif 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/mksys386 b/libc/syscall/mksys386 new file mode 100644 index 0000000..be7b2d5 --- /dev/null +++ b/libc/syscall/mksys386 @@ -0,0 +1,154 @@ +# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> +# This file is part of the Linux-8086 C library and is distributed +# under the GNU Library General Public License. +# +# This script generates the 'simple' system calls for the 386 +# +# Each call is put into it's own object file, if the semantics of the +# call are not correct UNIX then the 4th field in the dat file has a +# marker and the function is generated with a __ prefix. +# +# +# Different levels of squeeze +# 0 = each is complete +# 1 = Short codes calling common function + +rm -f syscall.c syscall.mak call_tab.v defn_tab.v + +tr '[A-Z]' '[a-z]' < sys386.dat | \ +awk 'BEGIN{ + print "# Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>" > "syscall.mak"; + print "# This file is part of the Linux-8086 C library and is distributed" > "syscall.mak"; + print "# under the GNU Library General Public License." > "syscall.mak"; + print "# " > "syscall.mak"; + print "# This file is automatically generated\n" > "syscall.mak" + + print "/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>"; + print " * This file is part of the Linux-8086 C library and is distributed"; + print " * under the GNU Library General Public License."; + print " * "; + print " * This file is automatically generated */\n" + obj="OBJ="; + + print "/* Standard start */\n\n" + printf("#ifndef __MSDOS__\n"); + printf("#ifdef __AS386_32__\n"); + printf("#asm\n"); + printf(" .text\n"); + printf(" .align 4\n"); + printf("#endasm\n\n"); + + COMPACT=0; +} +/^[ ]*#/ { next; } +/^[ ]*$/ { next; } +{ + if( $2 > max_call ) max_call = $2; + + if( $3 == "x" || $3 == "" ) next; + else if( $4 == "-" ) next; + else if( $4 == "*" ) funcname="__" $1; + else funcname=$1; + + shortname=substr(funcname,1,12); + + if( length(obj) > 60 ) + { + printf("%s\t\\\n", obj) > "syscall.mak"; + obj=" "; + } + obj=obj shortname ".o "; + + printf "/* CALL %s */\n\n", $0; + + printf("#ifdef L_%s\n", shortname); + printf("#asm\n"); + printf("export _%s\n", funcname); + printf("_%s:\n", funcname); + + # Inline assembler max to 5 args (20 bytes) + if( $3 != 4 && $3 != 5 && ( COMPACT || $3 > 5 )) + { + if( $3 == 0 ) + { + printf(" mov eax,#%d\n", $2); + } + else + { + printf("#if __FIRST_ARG_IN_AX__\n"); + printf(" mov edx,#%d\n", $2); + printf("#else\n"); + printf(" mov eax,#%d\n", $2); + printf("#endif\n"); + } + printf(" br sys_call%d\n", $3); + } + else + { + if( $3 >= 1 ) printf("#if __FIRST_ARG_IN_AX__\n"); + if( $3 >= 5 ) printf(" push edi\n"); + if( $3 >= 4 ) printf(" push esi\n"); + if( $3 >= 5 ) printf(" mov edi,[esp+16]\n"); + if( $3 >= 4 ) printf(" mov esi,[esp+12]\n"); + if( $3 >= 3 ) printf(" mov edx,[esp+8]\n"); + if( $3 >= 2 ) printf(" mov ecx,[esp+4]\n"); + if( $3 >= 1 ) printf(" mov ebx,eax\n"); + if( $3 >= 1 ) printf("#else\n"); + if( $3 >= 5 ) printf(" push edi\n"); + if( $3 >= 4 ) printf(" push esi\n"); + if( $3 >= 5 ) printf(" mov edi,[esp+20]\n"); + if( $3 >= 4 ) printf(" mov esi,[esp+16]\n"); + if( $3 >= 3 ) printf(" mov edx,[esp+12]\n"); + if( $3 >= 2 ) printf(" mov ecx,[esp+8]\n"); + if( $3 >= 1 ) printf(" mov ebx,[esp+4]\n"); + if( $3 >= 1 ) printf("#endif\n"); + printf(" mov eax,#%d\n", $2); + printf(" int $80\n"); + + if( $3 >= 4 ) printf(" pop esi\n"); + if( $3 >= 5 ) printf(" pop edi\n"); + + printf(" test eax,eax\n"); + printf(" jl syscall_err\n"); + printf(" ret\n"); + printf("syscall_err:\n"); + printf(" neg eax\n"); + printf(" mov [_errno],eax\n"); + printf(" mov eax,#-1\n"); + printf(" ret\n"); + } + printf("#endasm\n"); + printf("#endif\n\n"); +} +END{ + + printf("#endif /* __AS386_32__ */\n\n"); + printf("#endif /* __MSDOS__ */\n\n"); + printf("%s\n", obj) > "syscall.mak"; + printf "\n" > "syscall.mak"; + +}' > syscall.c + +cat >> syscall.mak <<\! + +TOP=.. +include $(TOP)/Make.defs + +all: $(OBJ) + +libc.a: $(OBJ) + ar r ../$(LIBC) $(OBJ) + @touch libc.a + +$(OBJ): sys386.dat mksys386 + $(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/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..dad3389 --- /dev/null +++ b/libc/syscall/signal.c @@ -0,0 +1,99 @@ + +#ifndef __MSDOS__ +#ifdef __AS386_16__ + +#include <errno.h> +#include <signal.h> + +typedef __sighandler_t Sig; + +extern int __signal __P((int, __sighandler_t)); +static Sig system_signal(); + +Sig __sigtable[_NSIG-1]; + +/* + * Signal handler. + * + */ + +/* + * KERNEL INTERFACE: + * It is assumed the kernel will never give us a signal we haven't + * _explicitly_ asked for! + * + * The Kernel need only save space for _one_ function pointer + * (to system_signal) and must deal with SIG_DFL and SIG_IGN + * in kernel space. + * + * When a signal is required the kernel must set all the registers as if + * returning from a interrupt normally then push the number of the signal + * to be generated, push the current pc value, then set the pc to the + * address of the 'system_signal' function. + */ + +Sig +signal(number, pointer) +int number; +Sig pointer; +{ + Sig old_sig; + int rv; + if( number < 1 || number >= _NSIG ) { errno=EINVAL; return SIG_ERR; } + + if( pointer == SIG_DFL || pointer == SIG_IGN ) + rv = __signal(number, pointer); + else + rv = __signal(number, (__sighandler_t) system_signal); + + if( rv < 0 ) return SIG_ERR; + + old_sig = __sigtable[number-1]; + __sigtable[number-1] = pointer; + + switch(rv) + { + case 0: return SIG_DFL; + case 1: return SIG_IGN; + return old_sig; + } +} + +#asm + .text +_system_signal: ! When this is called by the kernel the stack contains + pushf ! in order: + push ax ! + push bx ! The signal number, (NOS) + push cx ! The program counter, (TOS) + push dx ! + push si ! It does NOT contain the CS register or the flags. + push di ! This means it cannot be unraveled by an iret. + push bp + push es ! Note also only ES segment register is saved. + mov bx,sp ! Unlike minix the rv from a system call is in AX. + mov bx,[bx+20] +#if __FIRST_ARG_IN_AX__ + mov ax,bx +#else + push bx ! NB this is _unchecked_, do we want to ? +#endif + add bx,bx + mov bx,[bx+___sigtable-2] ! Offset by 2 cause no entry for signal 0 + call bx ! Do we want to check BX for 0 or 1 ? + inc sp + inc sp + pop es + pop bp + pop di + pop si + pop dx + pop cx + pop bx + pop ax + popf + ret #2 ! Get rid of the signum too. +#endasm + +#endif /* __AS386_16__ */ +#endif /* __MSDOS__ */ diff --git a/libc/syscall/sys386.dat b/libc/syscall/sys386.dat new file mode 100644 index 0000000..da9ad6c --- /dev/null +++ b/libc/syscall/sys386.dat @@ -0,0 +1,155 @@ + +# +# Name No Args Flag, comment +# +# . = Ok, with comment +# * = Needs libc code (Prefix __) +# - = Obsolete/not required +# +# Name N C +setup 0 X +exit 1 1 * +fork 2 0 +vfork 2 0 . Fake alias of fork +read 3 3 +write 4 3 +open 5 3 +close 6 1 +waitpid 7 3 +creat 8 2 +link 9 2 +unlink 10 1 +execve 11 3 +chdir 12 1 +time 13 1 +dv32_mknod 14 3 * Has correct args for 32bit dev_t +chmod 15 2 +chown 16 3 +break 17 X - This is done in a special function +oldstat 18 X - +lseek 19 3 +getpid 20 0 +mount 21 5 +umount 22 1 +setuid 23 1 +getuid 24 0 +stime 25 1 +ptrace 26 4 +alarm 27 1 +oldfstat 28 X - +pause 29 0 +utime 30 2 +stty 31 X - +gtty 32 X - +access 33 2 +nice 34 1 +ftime 35 1 +sync 36 0 +kill 37 2 +rename 38 2 +mkdir 39 2 +rmdir 40 1 +dup 41 1 +pipe 42 1 +times 43 1 +prof 44 X - +brk 45 1 - need to save brk_addr & -ve is valid return. +setgid 46 1 +getgid 47 0 +signal 48 2 +geteuid 49 0 +getegid 50 0 +acct 51 1 +phys 52 X - +lock 53 X - +ioctl 54 3 +fcntl 55 3 +mpx 56 X - +setpgid 57 2 +ulimit 58 2 +oldolduname 59 X - +umask 60 1 +chroot 61 1 +dv32_ustat 62 2 * Has correct args for 32bit dev_t +dup2 63 2 +getppid 64 0 +getpgrp 65 0 +setsid 66 0 +sigaction 67 3 +siggetmask 68 0 +sigsetmask 69 1 +setreuid 70 2 +setregid 71 2 +sigsuspend 72 1 +sigpending 73 1 +sethostname 74 2 +setrlimit 75 2 +getrlimit 76 2 +getrusage 77 2 +gettimeofday 78 2 +settimeofday 79 2 +getgroups 80 2 +setgroups 81 2 +select 82 1 * select's arg is &arg1 +symlink 83 2 +oldlstat 84 X - +readlink 85 3 +uselib 86 1 +swapon 87 2 +reboot 88 3 +readdir 89 3 * Takes the fd not a ddptr +mmap 90 1 * Is a pointer to a buffer with the 6 args. +munmap 91 2 +truncate 92 2 +ftruncate 93 2 +fchmod 94 2 +fchown 95 2 +getpriority 96 2 +setpriority 97 3 +profil 98 X - glibc has userspace +statfs 99 2 +fstatfs 100 2 +ioperm 101 3 +socketcall 102 2 * This is a lib internal for socket stuff +klog 103 X +setitimer 104 3 +getitimer 105 2 +dv32_stat 106 2 * Has correct args for 32 bit dev_t +dv32_lstat 107 2 * Has correct args for 32 bit dev_t +dv32_fstat 108 2 * Has correct args for 32 bit dev_t +olduname 109 X - +iopl 110 1 +vhangup 111 0 +idle 112 0 - System internal +vm86 113 1 +wait4 114 4 +swapoff 115 1 +sysinfo 116 1 +ipc 117 5 * SYSV ipc entry point +fsync 118 1 +sigreturn 119 1 * Signal internal +clone 120 2 +setdomainname 121 2 +uname 122 1 +modify_ldt 123 X +adjtimex 124 1 +mprotect 125 3 +sigprocmask 126 3 +create_module 127 X - Module handling, NO WAY! +init_module 128 X +delete_module 129 X +get_kernel_syms 130 X +quotactl 131 X +getpgid 132 1 +fchdir 133 1 +bdflush 134 2 +sysfs 135 3 +personality 136 1 * Linux specific. +afs_syscall 137 X +setfsuid 138 1 +setfsgid 139 1 +_llseek 140 X +getdents 141 3 * New style readdir ? +_newselect 142 X +flock 143 2 +syscall_flock 143 X diff --git a/libc/syscall/syscall.dat b/libc/syscall/syscall.dat new file mode 100644 index 0000000..de5ed9b --- /dev/null +++ b/libc/syscall/syscall.dat @@ -0,0 +1,142 @@ +# +# Name No Args Flag, comment +# +# . = Ok, with comment +# * = Needs libc code (Prefix __) +# - = Obsolete/not required +# +# WARNING! +# This file is used to generate includes for ELKSemu too. +# This file is continually changing, when you upgrade you _MUST_ ensure +# that ELKSemu is of a matching build! +# +# Calls that use one fd +READ 3 3 +WRITE 4 3 +CLOSE 6 1 +LSEEK 19 3 * NB 2nd arg is an IO ptr to long not a long. +FSTAT 28 2 +IOCTL 54 3 . Make this and fcntl the same ? +FCNTL 55 3 +FTRUNCATE 93 3 +FCHMOD 94 2 +FCHOWN 95 3 +FSYNC 118 1 +FCHDIR 133 1 +LLSEEK 140 3 * 2nd arg is ptr to two longs +READV 145 3 +WRITEV 146 3 +FLOCK 143 2 - Use fcntl +DUP 41 1 - Using nasty fcntl function + +# +SETUP 0 X +EXIT 1 1 * C exit does stdio, _exit in crt0 +FORK 2 0 +OPEN 5 3 +WAIT4 7 4 +VFORK 8 0 . Needed for 8086 +GETINFO 49 1 - Possible? Gets pid,ppid,uid,euid etc +LINK 9 2 +UNLINK 10 1 +EXEC 11 3 * Minix style exec +CHDIR 12 1 +GETTIMEOFDAY 13 2 . time() exists only in libc +MKNOD 14 3 +CHMOD 15 2 +CHOWN 16 3 +BRK 17 1 * This is only to tell the system +STAT 18 2 +GETPID 20 1 * This gets both pid & ppid +MOUNT 21 5 +UMOUNT 22 1 +SETUID 23 1 +GETUID 24 1 * This gets both uid and euid +SETTIMEOFDAY 25 2 . STIME should _NOT_ exist even as a libc. +STIME 25 2 - This must NOT exist - even as a libc. +PTRACE 26 4 +ALARM 27 2 +PAUSE 29 0 +UTIME 30 2 +ACCESS 33 2 +NICE 34 1 . +FTIME 35 1 - Use gettimeofday +SYNC 36 0 +KILL 37 2 +RENAME 38 2 +MKDIR 39 2 +RMDIR 40 1 +PIPE 42 1 +TIMES 43 2 * 2nd arg is pointer for long ret val. +SETGID 46 1 +GETGID 47 1 * This gets both gid and egid +SIGNAL 48 2 * Have put the despatch table in user space. +ACCT 51 1 - +SETPGID 57 2 +ULIMIT 58 2 +UMASK 60 1 +CHROOT 61 1 +USTAT 62 2 +GETPGRP 65 0 - use getpgid(0) +SETSID 66 0 +SIGACTION 67 X +SGETMASK 68 X +SSETMASK 69 X +SETREUID 70 2 +SETREGID 71 2 +SIGSUSPEND 72 X +SIGPENDING 73 X +SETHOSTNAME 74 2 +SETRLIMIT 75 2 +GETRLIMIT 76 2 +GETRUSAGE 77 2 +GETGROUPS 80 2 +SETGROUPS 81 2 +SYMLINK 83 2 +LSTAT 84 2 +READLINK 85 3 +SWAPON 87 X +REBOOT 88 3 . The magic number is 0xfee1,0xdead,... +MUNMAP 91 X +TRUNCATE 92 3 +GETPRIORITY 96 2 +SETPRIORITY 97 3 +PROFIL 98 X +STATFS 99 2 +FSTATFS 100 2 +SOCKETCALL 102 X +SYSLOG 103 X +SETITIMER 104 3 +GETITIMER 105 2 +UNAME 109 1 +VHANGUP 111 0 +SWAPOFF 115 X +SYSINFO 116 X - Use /proc +IPC 117 5 * This is for all SYSV IPC +SIGRETURN 119 X +SETDOMAINNAME 121 X +ADJTIMEX 124 X +MPROTECT 125 X +SIGPROCMASK 126 X +QUOTACTL 131 X +GETPGID 132 1 +SYSFS 135 X +PERSONALITY 136 X +SETFSUID 138 1 +SETFSGID 139 1 +GETDENTS 141 X +SELECT 142 5 * +MSYNC 144 X +GETSID 147 X +FDATASYNC 148 X +SYSCTL 149 X +MUNLOCK 151 X +MUNLOCKALL 153 X +SCHED_SETPARAM 154 X +SCHED_GETPARAM 155 X +SCHED_SETSCHEDULER 156 X +SCHED_GETSCHEDULER 157 X +SCHED_YIELD 158 X +SCHED_GET_PRIORITY_MAX 159 X +SCHED_GET_PRIORITY_MIN 160 X +SCHED_RR_GET_INTERVAL 161 X diff --git a/libc/syscall/syslib0.c b/libc/syscall/syslib0.c new file mode 100644 index 0000000..98f59e6 --- /dev/null +++ b/libc/syscall/syslib0.c @@ -0,0 +1,264 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <sys/types.h> +#include <errno.h> +#include <time.h> +#include <sys/times.h> + +/* MSDOS has it's own versions */ +#ifndef __MSDOS__ +#ifdef __AS386_16__ + +/********************** Function __cstartup *******************************/ + +#ifdef L___cstartup + +void (*__cleanup)() = 0; +char ** environ; + +#asm + loc 2 +call_main: + .word _main ! Segment 2 is the trailing pointers, main and the + .word call_exit ! routine to call exit. +#if __FIRST_ARG_IN_AX__ + .data +saved_arg1: + .word 0 +#endif +#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 + +export ___mkargv +___mkargv: ! BCC tells the linker to init argc,argv with this. + + push ax ! Push Envp + mov [_environ],ax ! And save + push bx ! Push argv +#if __FIRST_ARG_IN_AX__ + mov [saved_arg1],cx +#else + push cx ! Push argc +#endif + + mov 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 + mov bx,[si] + test bx,bx + jz no_entry + call bx ! Call the function +no_entry: +#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 lseek ************************************/ + +#ifdef L_lseek +off_t lseek(fd, posn, where) +int fd; +off_t posn; +int where; +{ + if( __lseek(fd, &posn, where) < 0 ) return -1; + else return posn; +} +#endif + +/********************** Function getpid ************************************/ + +#ifdef L_getpid +int getpid() +{ + int ppid; + return __getpid(&ppid); +} +#endif + +/********************** Function getppid ************************************/ + +#ifdef L_getppid +int getppid() +{ + int ppid; + __getpid(&ppid); + return ppid; +} +#endif + +/********************** Function getuid ************************************/ + +#ifdef L_getuid +int getuid() +{ + int euid; + return __getuid(&euid); +} +#endif + +/********************** Function geteuid ************************************/ + +#ifdef L_geteuid +int geteuid() +{ + int euid; + __getuid(&euid); + return euid; +} +#endif + +/********************** Function getgid ************************************/ + +#ifdef L_getgid +int getgid() +{ + int egid; + return __getgid(&egid); +} +#endif + +/********************** Function getegid ************************************/ + +#ifdef L_getegid +int getegid() +{ + int egid; + __getgid(&egid); + return egid; +} +#endif + +/********************** Function dup2 ************************************/ + +#ifdef L_dup2 + +#include <fcntl.h> + +int dup2(ifd, ofd) +int ifd; +{ + return fcntl(ifd, F_DUPFD, ofd); +} +#endif + +/********************** Function dup ************************************/ + +#ifdef L_dup +#include <sys/param.h> +#include <fcntl.h> +#include <errno.h> + +/* This is horribly complicated, there _must_ be a better way! */ + +int +dup(fd) +int fd; +{ + int nfd; + extern int errno; + int oerr = errno; + + errno = 0; + for(nfd=0; nfd<NR_OPEN; nfd++) + { + if( fcntl(nfd, F_GETFD) < 0 ) + break; + } + if( nfd == NR_OPEN ) { errno = EMFILE ; return -1; } + errno = oerr; + if( fcntl(fd, F_DUPFD, nfd) < 0 ) + { + if( errno == EINVAL ) errno = EMFILE; + return -1; + } + return nfd; +} +#endif + +/********************** Function getpgrp ************************************/ + +#ifdef L_getpgrp +int +getpgrp() +{ + return getpgid(0); +} +#endif + +/********************** Function times ************************************/ + +#ifdef L_times +clock_t times(buf) +struct tms* buf; +{ + long rv; + __times(buf, &rv); + return rv; +} +#endif + +/********************** THE END ********************************************/ + +#endif /* __AS386_16__ */ +#endif /* __MSDOS__ */ diff --git a/libc/syscall/syslib3.c b/libc/syscall/syslib3.c new file mode 100644 index 0000000..c4df1fc --- /dev/null +++ b/libc/syscall/syslib3.c @@ -0,0 +1,109 @@ +/* Copyright (C) 1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <sys/types.h> +#include <errno.h> +#include <time.h> +#include <sys/times.h> + +/* MSDOS has it's own versions */ +#ifndef __MSDOS__ +#ifdef __AS386_32__ + +/********************** Function __cstartup *******************************/ + +#ifdef L___cstart3 + +void (*__cleanup)() = 0; +char ** environ; + +#asm + loc 2 +call_main: + .long _main ! Segment 2 is the trailing pointers, main and the + .long call_exit ! routine to call exit. +#if __FIRST_ARG_IN_AX__ + .data +saved_arg1: + .long 0 +#endif +#if __CALLER_SAVES__ + .data +loopy_safe: + .long 0 +#endif + .text + +export ___mkargv +___mkargv: ! BCC Tells linker to init argv ... none needed. + +export ___cstartup +___cstartup: ! Crt0 startup (Linux style) + mov eax,[esp] + test eax,eax + jz call_exit ! If argc == 0 this is being called by ldd, exit. + mov eax,[esp+8] + mov [_environ],eax +#if __FIRST_ARG_IN_AX__ + pop [saved_arg1] ! Argc will go into eax +#endif + + mov esi,#auto_start ! Pointer to first autostart function +auto_run: +#if __FIRST_ARG_IN_AX__ + mov eax,[saved_arg1] +#endif +#if __CALLER_SAVES__ + mov [loopy_safe],esi +#endif + mov ebx,[esi] + test ebx,ebx + jz no_func + call ebx ! Call the function +no_func: +#if __CALLER_SAVES__ + mov esi,[loopy_safe] +#endif + add esi,#4 ! SI at next + jmp auto_run ! And round for the next. + +call_exit: ! Last item called by above. + pop ebx ! Be tidy. +#if !__FIRST_ARG_IN_AX__ + push eax ! At the end the last called was main() push it`s +#endif + call _exit ! return val and call exit(); +bad_exit: + jmp bad_exit ! Exit returned !! + +export _exit +export __exit +_exit: ! exit(rv) function +#if __FIRST_ARG_IN_AX__ + mov [saved_arg1],eax +#else + push [esp+4] ! Copy the `rv` for the exit fuctions. +#endif + mov ebx,[___cleanup] ! Call exit, normally this is `__do_exit` + test ebx,ebx + je no_clean ! But it`s default is null + call ebx +no_clean: +#if __FIRST_ARG_IN_AX__ + mov eax,[saved_arg1] +#else + add esp,#4 +#endif +__exit: ! _exit(rv) + br ___exit ! This is just an alias for __exit(); + +#endasm +#endif + +/********************** Function ? ************************************/ + +/*---*/ +#endif +#endif diff --git a/libc/syscall/syslibc.c b/libc/syscall/syslibc.c new file mode 100644 index 0000000..68f5a0b --- /dev/null +++ b/libc/syscall/syslibc.c @@ -0,0 +1,155 @@ +/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk> + * This file is part of the Linux-8086 C library and is distributed + * under the GNU Library General Public License. + */ + +#include <sys/types.h> +#include <errno.h> +#include <time.h> + +/* MSDOS has it's own versions */ +#ifndef __MSDOS__ + +/********************** Function time ************************************/ + +#ifdef L_time +time_t time(where) +time_t *where; +{ + struct timeval rv; + if( gettimeofday(&rv, (void*)0) < 0 ) return -1; + if(where) *where = rv.tv_sec; + return rv.tv_sec; +} +#endif + +/********************** Function abort ************************************/ + +#ifdef L_abort +#include <signal.h> + +int abort() +{ + signal(SIGABRT, SIG_DFL); + kill(SIGABRT, getpid()); /* Correct one */ + pause(); /* System may just schedule */ + signal(SIGKILL, SIG_DFL); + kill(SIGKILL, getpid()); /* Can't trap this! */ + __exit(255); /* WHAT!! */ +} +#endif + +/********************** Function wait ************************************/ + +#ifdef L_wait +int +wait(status) +int * status; +{ + return wait4(-1, status, 0, (void*)0); +} +#endif + +/********************** Function waitpid ************************************/ + +#ifdef L_waitpid +int +waitpid(pid, status, opts) +int pid; +int * status; +int opts; +{ + return wait4(pid, status, opts, (void*)0); +} +#endif + +/********************** Function killpg ************************************/ + +#ifdef L_killpg +int +killpg(pid, sig) +int pid; +int sig; +{ + if(pid == 0) + pid = getpgrp(); + if(pid > 1) + return kill(-pid, sig); + errno = EINVAL; + return -1; +} +#endif + +/********************** Function setpgrp ************************************/ + +#ifdef L_setpgrp +int +setpgrp() +{ + return setpgid(0,0); +} +#endif + +/********************** Function sleep ************************************/ + +#ifdef L_sleep +#include <signal.h> + +/* This uses SIGALRM, it does keep the previous alarm call but will lose + * any alarms that go off during the sleep + */ + +static void alrm() { } + +unsigned int sleep(seconds) +unsigned int seconds; +{ + void (*last_alarm)(); + unsigned int prev_sec; + + prev_sec = alarm(0); + if( prev_sec <= seconds ) prev_sec = 1; else prev_sec -= seconds; + + last_alarm = signal(SIGALRM, alrm); + alarm(seconds); + pause(); + seconds = alarm(prev_sec); + signal(SIGALRM, last_alarm); + return seconds; +} +#if 0 + /* Is this a better way ? If we have select of course :-) */ +#include <sys/time.h> +unsigned int +sleep(seconds) +unsigned int seconds; +{ + struct timeval timeout; + time_t start = time((void*)0); + timeout.tv_sec = seconds; + timeout.tv_usec = 0; + select(1, NULL, NULL, NULL, &timeout); + return seconds - (time((void*)0) - start); +} +#endif + +#endif + +/********************** Function usleep ************************************/ + +#ifdef L_usleep +#include <sys/time.h> +void +usleep(useconds) +unsigned long useconds; +{ + struct timeval timeout; + timeout.tv_sec = useconds%1000000L; + timeout.tv_usec = useconds/1000000L; + select(1, NULL, NULL, NULL, &timeout); +} +#endif + +/********************** THE END ********************************************/ + +#endif /* __MSDOS__ */ diff --git a/libc/termios/Config b/libc/termios/Config new file mode 100644 index 0000000..f0c9bde --- /dev/null +++ b/libc/termios/Config @@ -0,0 +1 @@ +termios: Termios functions diff --git a/libc/termios/Makefile b/libc/termios/Makefile new file mode 100644 index 0000000..7903bc2 --- /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 cfmakeraw.o + +ifeq ($(LIB_OS),ELKS) +OBJ=$(TOBJ) ttyname.o +else +OBJ= +endif + +all: $(OBJ) + +libc.a: $(OBJ) + ar r ../$(LIBC) $(OBJ) + @touch libc.a + +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..a617e86 --- /dev/null +++ b/libc/termios/termios.c @@ -0,0 +1,220 @@ +/* Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk> This + * file is part of the Linux-8086 C library and is distributed under the + * GNU Library General Public License. + */ + +/* Note: This is based loosely on the Glib termios routines. */ + +#ifndef __MSDOS__ + +#include <errno.h> +#include <stddef.h> +#include <sys/ioctl.h> +#include <termios.h> + +#ifdef L_isatty +isatty(fd) +int fd; +{ + struct termios term; + int rv, err = errno; + rv= (ioctl(fd, TCGETS, &term)==0); + if( rv==0 && errno == ENOSYS ) + rv = (fd<3); + errno = err; + return rv; +} +#endif + +#ifdef L_tcgetattr +int +tcgetattr(fd, term) +int fd; +struct termios *term; +{ + return ioctl(fd, TCGETS, term); +} +#endif + +#ifdef L_tcsetattr +int +tcsetattr(fildes, optional_actions, termios_p) +int fildes; +int optional_actions; +struct termios *termios_p; +{ + switch (optional_actions) + { + case TCSANOW: + return ioctl(fildes, TCSETS, termios_p); + case TCSADRAIN: + return ioctl(fildes, TCSETSW, termios_p); + case TCSAFLUSH: + return ioctl(fildes, TCSETSF, termios_p); + default: + errno = EINVAL; + return -1; + } +} +#endif + +#ifdef L_tcdrain +/* Wait for pending output to be written on FD. */ +int +tcdrain(fd) +int fd; +{ + /* With an argument of 1, TCSBRK just waits for output to drain. */ + return ioctl(fd, TCSBRK, 1); +} +#endif + +#ifdef L_tcflow +int +tcflow(fd, action) +int fd; +int action; +{ + return ioctl(fd, TCXONC, action); +} +#endif + +#ifdef L_tcflush +/* Flush pending data on FD. */ +int +tcflush(fd, queue_selector) +int fd; +int queue_selector; +{ + return ioctl(fd, TCFLSH, queue_selector); +} +#endif + +#ifdef L_tcsendbreak +/* Send zero bits on FD. */ +int +tcsendbreak(fd, duration) +int fd; +int duration; +{ + /* + * The break lasts 0.25 to 0.5 seconds if DURATION is zero, and an + * implementation-defined period if DURATION is nonzero. We define a + * positive DURATION to be number of milliseconds to break. + */ + if (duration <= 0) + return ioctl(fd, TCSBRK, 0); + + /* + * ioctl can't send a break of any other duration for us. This could be + * changed to use trickery (e.g. lower speed and send a '\0') to send + * the break, but for now just return an error. + */ + errno = EINVAL; + return -1; +} +#endif + +#ifdef L_tcsetpgrp +/* Set the foreground process group ID of FD set PGRP_ID. */ +int +tcsetpgrp(fd, pgrp_id) +int fd; +pid_t pgrp_id; +{ + return ioctl(fd, TIOCSPGRP, &pgrp_id); +} +#endif + +#ifdef L_tcgetpgrp +/* Return the foreground process group ID of FD. */ +pid_t +tcgetpgrp(fd) +int fd; +{ + int pgrp; + if (ioctl(fd, TIOCGPGRP, &pgrp) < 0) + return (pid_t) - 1; + return (pid_t) pgrp; +} +#endif + +#ifdef L_cfgetospeed +speed_t cfgetospeed(tp) +struct termios *tp; +{ + return (tp->c_cflag & CBAUD); +} +#endif + +#ifdef L_cfgetispeed +speed_t cfgetispeed(tp) +struct termios *tp; +{ + return (tp->c_cflag & CBAUD); +} +#endif + +#ifdef L_cfsetospeed +int cfsetospeed(tp, speed) +struct termios *tp; speed_t speed; +{ +#ifdef CBAUDEX + if ((speed & ~CBAUD) || + ((speed & CBAUDEX) && (speed < B57600 || speed > B115200))) + return 0; +#else + if (speed & ~CBAUD) + return 0; +#endif + tp->c_cflag &= ~CBAUD; + tp->c_cflag |= speed; + + return 0; +} +#endif + +#ifdef L_cfsetispeed +int cfsetispeed(tp, speed) +struct termios *tp; speed_t speed; +{ + return cfsetospeed(tp, speed); +} +#endif + +/* From linux libc-4.6.27 again */ +#ifdef L_cfmakeraw +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library.*/ + +void +cfmakeraw(t) +struct termios *t; +{ +/* I changed it to the current form according to the suggestions + * from Bruce Evans. Thanks Bruce. Please report the problems to + * H.J. Lu (hlu@eecs.wsu.edu). + */ + +/* + * I took out the bits commented out by #if 1...#else - RHP + */ + + /* VMIN = 0 means non-blocking for Linux */ + t->c_cc[VMIN] = 1; t->c_cc[VTIME] = 1; + /* clear some bits with &= ~(bits), set others with |= */ + t->c_cflag &= ~(CSIZE|PARENB|CSTOPB); + t->c_cflag |= (CS8|HUPCL|CREAD); + t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|INPCK|ISTRIP); + t->c_iflag &= ~(INLCR|IGNCR|ICRNL|IXON|IXOFF); + t->c_iflag |= (BRKINT|IGNPAR); + t->c_oflag &= ~(OPOST|OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL); + t->c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); + t->c_oflag |= (ONLCR|NL0|CR0|TAB3|BS0|VT0|FF0); + t->c_lflag &= ~(ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK|ECHONL); + t->c_lflag &= ~(NOFLSH|XCASE); + t->c_lflag &= ~(ECHOPRT|ECHOCTL|ECHOKE); +} +#endif + +#endif diff --git a/libc/termios/ttyname.c b/libc/termios/ttyname.c new file mode 100644 index 0000000..d777ab3 --- /dev/null +++ b/libc/termios/ttyname.c @@ -0,0 +1,45 @@ + +#include <errno.h> +#include <sys/stat.h> +#include <dirent.h> + +char * +ttyname(fd) +int fd; +{ + static char dev[] = "/dev"; + struct stat st, dst; + DIR *fp; + struct dirent *d; + static char name[MAXNAMLEN]; + int noerr = errno; + + if (fstat(fd, &st) < 0) + return 0; + if (!isatty(fd)) + { + errno = ENOTTY; + return 0; + } + + fp = opendir(dev); + if (fp == 0) + return 0; + strcpy(name, dev); + strcat(name, "/"); + + while ((d = readdir(fp)) != 0) + { + strcpy(name + sizeof(dev), d->d_name); + if (stat(name, &dst) == 0 + && st.st_dev == dst.st_dev && st.st_ino == dst.st_ino) + { + closedir(fp); + errno = noerr; + return name; + } + } + closedir(fp); + errno = noerr; + return 0; +} diff --git a/libc/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..4d308c7 --- /dev/null +++ b/libc/tests/README @@ -0,0 +1,22 @@ +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. + +BTW: i386 OMAGIC files can be converted to deformed ELFs with this: + $ ld -N -Ttext 0 --defsym _start=0 sync -o sync1 -s + +-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..c904969 --- /dev/null +++ b/libc/tests/env.c @@ -0,0 +1,81 @@ + +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 + .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..1bdc737 --- /dev/null +++ b/libc/tests/ft.c @@ -0,0 +1,1209 @@ +/* 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 S_IFSOCK +#include <sys/socket.h> +#endif +#ifndef S_IFLNK +#define lstat stat +#endif + +/* Ansi prototypes */ +#ifdef __STTDC__ +#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 warning PR((int enumber, char * estr, char * eobj)); +int error PR((int enumber, char * estr, char * eobj)); + +#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, "vifRrpsda" }, + { "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; + case 'a': flg_recurse++; flg_preserve++; flg_noderef++; + 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, "", dname); + + dfd = opendir(dname); + } + if( dfd == 0 ) return error(errno, "", 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(EINVAL, "", "No code."); exit(1); + + case CMD_LN+OK_DIR+OK_NO_SOURCE: + case CMD_LN: rv = cmd_ln(fname); break; + + case CMD_INSTALL: error(EINVAL, "", ""); 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 +warning(enumber, estr, eobj) +int enumber; char * estr; char * eobj; +{ + if(flg_verbose) + return error(enumber, estr, eobj); + return 0; +} + +int +error(enumber, estr, eobj) +int enumber; char * estr; char * eobj; +{ + fprintf(stderr, "%s%s: ", prog_name[0]=='-'?"ft":"", prog_name); + fprintf(stderr, "%s%s: %s\n", estr, eobj, strerror(enumber)); + return -1; +} diff --git a/libc/tests/grab.c b/libc/tests/grab.c new file mode 100644 index 0000000..b65fa28 --- /dev/null +++ b/libc/tests/grab.c @@ -0,0 +1,81 @@ + +#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; + unsigned 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>3; ) + { + 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); + exit(0); +} 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 100644 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/time/Config b/libc/time/Config new file mode 100644 index 0000000..053ab81 --- /dev/null +++ b/libc/time/Config @@ -0,0 +1 @@ +time: Unix time manipulation functions. diff --git a/libc/time/Makefile b/libc/time/Makefile new file mode 100644 index 0000000..d04e5f4 --- /dev/null +++ b/libc/time/Makefile @@ -0,0 +1,17 @@ +# 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 + +OBJ=localtime.o gmtime.o asctime.o ctime.o asc_conv.o tm_conv.o + +all: $(OBJ) + +libc.a: $(OBJ) + ar r ../$(LIBC) $(OBJ) + @touch libc.a + +clean: + rm -f *.o libc.a diff --git a/libc/time/README b/libc/time/README new file mode 100644 index 0000000..da4f4e6 --- /dev/null +++ b/libc/time/README @@ -0,0 +1,8 @@ +Copyright (C) 1996 Robert de Bath <robert@mayday.compulink.co.uk> +This file is part of the Linux-8086 C library and is distributed +under the GNU Library General Public License. + +There are two ways of converting the time_t to a struct tm, I'm not +quite sure which is better. + +-Robert diff --git a/libc/time/asc_conv.c b/libc/time/asc_conv.c new file mode 100644 index 0000000..78cbcdd --- /dev/null +++ b/libc/time/asc_conv.c @@ -0,0 +1,49 @@ + +#include <time.h> +#include <string.h> +/* + * Internal ascii conversion routine, avoid use of printf, it's a bit big! + */ + + +static void +hit(buf, val) +char * buf; +int val; +{ + *buf = '0' + val%10; +} + +void +__asctime(buffer, ptm) +register char * buffer; +struct tm * ptm; +{ +static char days[] = "SunMonTueWedThuFriSat"; +static char mons[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + int year; + + /* 012345678901234567890123456 */ + strcpy(buffer, "Err Err .. ..:..:.. ....\n"); + if( (ptm->tm_wday >= 0) && (ptm->tm_wday <= 6) ) + memcpy(buffer, days+3*(ptm->tm_wday), 3); + + if( (ptm->tm_mon >= 0) && (ptm->tm_mon <= 11) ) + memcpy(buffer+4, mons+3*(ptm->tm_mon), 3); + + + hit(buffer+ 8, ptm->tm_mday/10); + hit(buffer+ 9, ptm->tm_mday ); + hit(buffer+11, ptm->tm_hour/10); + hit(buffer+12, ptm->tm_hour ); + hit(buffer+14, ptm->tm_min/10); + hit(buffer+15, ptm->tm_min ); + hit(buffer+17, ptm->tm_sec/10); + hit(buffer+18, ptm->tm_sec ); + + year = ptm->tm_year + 1900; + hit(buffer+20, year/1000); + hit(buffer+21, year/100); + hit(buffer+22, year/10); + hit(buffer+23, year); +} diff --git a/libc/time/asctime.c b/libc/time/asctime.c new file mode 100644 index 0000000..ea13bf8 --- /dev/null +++ b/libc/time/asctime.c @@ -0,0 +1,15 @@ + +#include <time.h> + +extern void __asctime(); + +char * +asctime(timeptr) +__const struct tm * timeptr; +{ +static char timebuf[26]; + + if( timeptr == 0 ) return 0; + __asctime(timebuf, timeptr); + return timebuf; +} diff --git a/libc/time/ctime.c b/libc/time/ctime.c new file mode 100644 index 0000000..2f42cd3 --- /dev/null +++ b/libc/time/ctime.c @@ -0,0 +1,26 @@ + +#include <time.h> + +extern void __tm_conv(); +extern void __asctime(); + +char * +ctime(timep) +__const time_t * timep; +{ + static char cbuf[26]; + struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + __asctime(cbuf, &tmb); + + return cbuf; +} diff --git a/libc/time/gmtime.c b/libc/time/gmtime.c new file mode 100644 index 0000000..aa0a246 --- /dev/null +++ b/libc/time/gmtime.c @@ -0,0 +1,15 @@ + +#include <time.h> + +extern void __tm_conv(); + +struct tm * +gmtime(timep) +__const time_t * timep; +{ + static struct tm tmb; + + __tm_conv(&tmb, timep, 0L); + + return &tmb; +} diff --git a/libc/time/localtime.c b/libc/time/localtime.c new file mode 100644 index 0000000..9d9b46d --- /dev/null +++ b/libc/time/localtime.c @@ -0,0 +1,22 @@ + +#include <time.h> + +extern void __tm_conv(); + +struct tm * +localtime(timep) +__const time_t * timep; +{ + static struct tm tmb; + struct timezone tz; + time_t offt; + + gettimeofday((void*)0, &tz); + + offt = -tz.tz_minuteswest*60L; + + /* tmb.tm_isdst = ? */ + __tm_conv(&tmb, timep, offt); + + return &tmb; +} diff --git a/libc/time/tm_conv.c b/libc/time/tm_conv.c new file mode 100644 index 0000000..ffd524c --- /dev/null +++ b/libc/time/tm_conv.c @@ -0,0 +1,138 @@ + +#if 0 +#include <time.h> + +/* This is a translation from ALGOL in Collected Algorithms of CACM. */ +/* Copied from Algorithm 199, Author: Robert G. Tantzen */ + +void +__tm_conv(tmbuf, timep, offset) +struct tm *tmbuf; +time_t *timep; +time_t offset; +{ +static int moffset[] = + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + long s; + long j, d, m, y; + + offset += *timep; + + tmbuf->tm_isdst = 0; /* Someone else can set this */ + + j = offset / 86400L + 719469; + s = offset % 86400L; + + if( s < 0 ) { s += 86400L; j--; } + + tmbuf->tm_sec = s % 60; + tmbuf->tm_min = (s / 60) % 60; + tmbuf->tm_hour = s / 3600; + + tmbuf->tm_wday = (j+2) % 7; + + /* + * Julian date converter. Takes a julian date (the number of days since + * some distant epoch or other), and fills tmbuf. + */ + + y = (4L * j - 1L) / 146097L; + j = 4L * j - 1L - 146097L * y; + d = j / 4L; + j = (4L * d + 3L) / 1461L; + d = 4L * d + 3L - 1461L * j; + d = (d + 4L) / 4L; + m = (5L * d - 3L) / 153L; + d = 5L * d - 3 - 153L * m; + d = (d + 5L) / 5L; + y = 100L * y + j; + if (m < 10) + m += 2; + else + { + m -= 10; + ++y; + } + + tmbuf->tm_year = y - 1900; + tmbuf->tm_mon = m; + tmbuf->tm_mday = d; + + tmbuf->tm_yday = d + moffset[m]; + if (m > 1 && ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))) + tmbuf->tm_yday++; +} + +#else + +/* This is adapted from glibc */ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc */ + +#define SECS_PER_HOUR 3600L +#define SECS_PER_DAY 86400L + +#include <time.h> + +static const unsigned short int __mon_lengths[2][12] = + { + /* Normal years. */ + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + /* Leap years. */ + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + +void +__tm_conv(tmbuf, t, offset) +struct tm *tmbuf; +time_t *t; +time_t offset; +{ + long days, rem; + register int y; + register unsigned short int *ip; + + days = *t / SECS_PER_DAY; + rem = *t % SECS_PER_DAY; + rem += offset; + while (rem < 0) + { + rem += SECS_PER_DAY; + --days; + } + while (rem >= SECS_PER_DAY) + { + rem -= SECS_PER_DAY; + ++days; + } + tmbuf->tm_hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tmbuf->tm_min = rem / 60; + tmbuf->tm_sec = rem % 60; + /* January 1, 1970 was a Thursday. */ + tmbuf->tm_wday = (4 + days) % 7; + if (tmbuf->tm_wday < 0) + tmbuf->tm_wday += 7; + y = 1970; + while (days >= (rem = __isleap(y) ? 366 : 365)) + { + ++y; + days -= rem; + } + while (days < 0) + { + --y; + days += __isleap(y) ? 366 : 365; + } + tmbuf->tm_year = y - 1900; + tmbuf->tm_yday = days; + ip = __mon_lengths[__isleap(y)]; + for (y = 0; days >= ip[y]; ++y) + days -= ip[y]; + tmbuf->tm_mon = y; + tmbuf->tm_mday = days + 1; + tmbuf->tm_isdst = -1; +} + +#endif diff --git a/libc/utmp/Makefile b/libc/utmp/Makefile new file mode 100644 index 0000000..2c88bd2 --- /dev/null +++ b/libc/utmp/Makefile @@ -0,0 +1,26 @@ +# 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 ($(LIB_OS),ELKS) +OBJ=utent.o +endif + +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); +} + + |